Completed
Push — master ( 00e474...9d3fbd )
by Michael
04:26
created

Nusoap_xmlschema::serializeSchema()   F

Complexity

Conditions 44
Paths 3696

Size

Total Lines 115
Code Lines 69

Duplication

Lines 11
Ratio 9.57 %

Importance

Changes 0
Metric Value
cc 44
eloc 69
nc 3696
nop 0
dl 11
loc 115
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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="' . $this->soap_defencoding . '"?>' . '<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"' . $ns_string . ">\n" . '<SOAP-ENV:Body>' . '<SOAP-ENV:Fault>'
1178
                      . $this->serialize_val($this->faultcode, 'faultcode') . $this->serialize_val($this->faultactor, 'faultactor') . $this->serialize_val($this->faultstring, 'faultstring') . $this->serialize_val($this->faultdetail, 'detail')
1179
                      . '</SOAP-ENV:Fault>' . '</SOAP-ENV:Body>' . '</SOAP-ENV:Envelope>';
1180
1181
        return $return_msg;
1182
    }
1183
}
1184
1185
/**
1186
 * Backward compatibility
1187
 */
1188
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...
1189
{
1190
}
1191
1192
?><?php
1193
1194
/**
1195
 * parses an XML Schema, allows access to it's data, other utility methods.
1196
 * imperfect, no validation... yet, but quite functional.
1197
 *
1198
 * @author   Dietrich Ayala <[email protected]>
1199
 * @author   Scott Nichol <[email protected]>
1200
 * @access   public
1201
 */
1202
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...
1203
{
1204
    // files
1205
    public $schema = '';
1206
    public $xml    = '';
1207
    // namespaces
1208
    public $enclosingNamespaces;
1209
    // schema info
1210
    public $schemaInfo            = array();
1211
    public $schemaTargetNamespace = '';
1212
    // types, elements, attributes defined by the schema
1213
    public $attributes         = array();
1214
    public $complexTypes       = array();
1215
    public $complexTypeStack   = array();
1216
    public $currentComplexType = null;
1217
    public $elements           = array();
1218
    public $elementStack       = array();
1219
    public $currentElement     = null;
1220
    public $simpleTypes        = array();
1221
    public $simpleTypeStack    = array();
1222
    public $currentSimpleType  = null;
1223
    // imports
1224
    public $imports = array();
1225
    // parser vars
1226
    public $parser;
1227
    public $position         = 0;
1228
    public $depth            = 0;
1229
    public $depth_array      = array();
1230
    public $message          = array();
1231
    public $defaultNamespace = array();
1232
1233
    /**
1234
     * constructor
1235
     *
1236
     * @param string       $schema     schema document URI
1237
     * @param string       $xml        xml document URI
1238
     * @param array|string $namespaces namespaces defined in enclosing XML
1239
     * @access   public
1240
     * @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...
1241
     */
1242
    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...
1243
    {
1244
        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...
1245
        $this->debug('nusoap_xmlschema class instantiated, inside constructor');
1246
        // files
1247
        $this->schema = $schema;
1248
        $this->xml    = $xml;
1249
1250
        // namespaces
1251
        $this->enclosingNamespaces = $namespaces;
1252
        $this->namespaces          = array_merge($this->namespaces, $namespaces);
1253
1254
        // parse schema file
1255
        if ($schema != '') {
1256
            $this->debug('initial schema file: ' . $schema);
1257
            $this->parseFile($schema, 'schema');
1258
        }
1259
1260
        // parse xml file
1261
        if ($xml != '') {
1262
            $this->debug('initial xml file: ' . $xml);
1263
            $this->parseFile($xml, 'xml');
1264
        }
1265
    }
1266
1267
    /**
1268
     * parse an XML file
1269
     *
1270
     * @param  string $xml  path/URL to XML file
1271
     * @param  string $type (schema | xml)
1272
     * @return boolean
1273
     * @access public
1274
     */
1275
    public function parseFile($xml, $type)
1276
    {
1277
        // parse xml file
1278
        if ($xml != '') {
1279
            $xmlStr = @implode('', @file($xml));
1280
            if ($xmlStr == '') {
1281
                $msg = 'Error reading XML from ' . $xml;
1282
                $this->setError($msg);
1283
                $this->debug($msg);
1284
1285
                return false;
1286
            } else {
1287
                $this->debug("parsing $xml");
1288
                $this->parseString($xmlStr, $type);
1289
                $this->debug("done parsing $xml");
1290
1291
                return true;
1292
            }
1293
        }
1294
1295
        return false;
1296
    }
1297
1298
    /**
1299
     * parse an XML string
1300
     *
1301
     * @param string $xml  path or URL
1302
     * @param string $type (schema|xml)
1303
     * @access   private
1304
     */
1305
    public function parseString($xml, $type)
1306
    {
1307
        // parse xml string
1308
        if ($xml != '') {
1309
1310
            // Create an XML parser.
1311
            $this->parser = xml_parser_create();
1312
            // Set the options for parsing the XML data.
1313
            xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
1314
1315
            // Set the object for the parser.
1316
            xml_set_object($this->parser, $this);
1317
1318
            // Set the element handlers for the parser.
1319
            if ($type === 'schema') {
1320
                xml_set_element_handler($this->parser, 'schemaStartElement', 'schemaEndElement');
1321
                xml_set_character_data_handler($this->parser, 'schemaCharacterData');
1322
            } elseif ($type === 'xml') {
1323
                xml_set_element_handler($this->parser, 'xmlStartElement', 'xmlEndElement');
1324
                xml_set_character_data_handler($this->parser, 'xmlCharacterData');
1325
            }
1326
1327
            // Parse the XML file.
1328 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...
1329
                // Display an error message.
1330
                $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)));
1331
                $this->debug($errstr);
1332
                $this->debug("XML payload:\n" . $xml);
1333
                $this->setError($errstr);
1334
            }
1335
1336
            xml_parser_free($this->parser);
1337
        } else {
1338
            $this->debug('no xml passed to parseString()!!');
1339
            $this->setError('no xml passed to parseString()!!');
1340
        }
1341
    }
1342
1343
    /**
1344
     * gets a type name for an unnamed type
1345
     *
1346
     * @param   string  Element name
1347
     * @return string A type name for an unnamed type
1348
     * @access  private
1349
     */
1350
    public function CreateTypeName($ename)
1351
    {
1352
        $scope = '';
1353
        for ($i = 0, $iMax = count($this->complexTypeStack); $i < $iMax; ++$i) {
1354
            $scope .= $this->complexTypeStack[$i] . '_';
1355
        }
1356
1357
        return $scope . $ename . '_ContainedType';
1358
    }
1359
1360
    /**
1361
     * start-element handler
1362
     *
1363
     * @param string $parser XML parser object
1364
     * @param string $name   element name
1365
     * @param string $attrs  associative array of attributes
1366
     * @access   private
1367
     */
1368
    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...
1369
    {
1370
1371
        // position in the total number of elements, starting from 0
1372
        $pos   = $this->position++;
1373
        $depth = $this->depth++;
1374
        // set self as current value for this depth
1375
        $this->depth_array[$depth] = $pos;
1376
        $this->message[$pos]       = array('cdata' => '');
1377
        if ($depth > 0) {
1378
            $this->defaultNamespace[$pos] = $this->defaultNamespace[$this->depth_array[$depth - 1]];
1379
        } else {
1380
            $this->defaultNamespace[$pos] = false;
1381
        }
1382
1383
        // get element prefix
1384
        if ($prefix = $this->getPrefix($name)) {
1385
            // get unqualified name
1386
            $name = $this->getLocalPart($name);
1387
        } else {
1388
            $prefix = '';
1389
        }
1390
1391
        // loop thru attributes, expanding, and registering namespace declarations
1392
        if (count($attrs) > 0) {
1393
            foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
1394
                // if ns declarations, add to class level array of valid namespaces
1395
                if (preg_match('/^xmlns/', $k)) {
1396
                    //$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...
1397
                    //$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...
1398
                    if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
1399
                        //$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...
1400
                        $this->namespaces[$ns_prefix] = $v;
1401
                    } else {
1402
                        $this->defaultNamespace[$pos] = $v;
1403
                        if (!$this->getPrefixFromNamespace($v)) {
1404
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
1405
                        }
1406
                    }
1407 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...
1408
                        || $v === 'http://www.w3.org/2000/10/XMLSchema'
1409
                    ) {
1410
                        $this->XMLSchemaVersion  = $v;
1411
                        $this->namespaces['xsi'] = $v . '-instance';
1412
                    }
1413
                }
1414
            }
1415
            foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
1416
                // expand each attribute
1417
                $k          = strpos($k, ':') ? $this->expandQname($k) : $k;
1418
                $v          = strpos($v, ':') ? $this->expandQname($v) : $v;
1419
                $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...
1420
            }
1421
            $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...
1422
        } else {
1423
            $attrs = array();
1424
        }
1425
        // find status, register data
1426
        switch ($name) {
1427
            case 'all':            // (optional) compositor content for a complexType
1428
            case 'choice':
1429
            case 'group':
1430
            case 'sequence':
1431
                //$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...
1432
                $this->complexTypes[$this->currentComplexType]['compositor'] = $name;
1433
                //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...
1434
                //  $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...
1435
                //}
1436
                break;
1437
            case 'attribute':    // complexType attribute
1438
                //$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...
1439
                $this->xdebug('parsing attribute:');
1440
                $this->appendDebug($this->varDump($attrs));
1441
                if (!isset($attrs['form'])) {
1442
                    // TODO: handle globals
1443
                    $attrs['form'] = $this->schemaInfo['attributeFormDefault'];
1444
                }
1445
                if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1446
                    $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1447 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...
1448
                        // no namespace in arrayType attribute value...
1449
                        if ($this->defaultNamespace[$pos]) {
1450
                            // ...so use the default
1451
                            $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'] = $this->defaultNamespace[$pos] . ':' . $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1452
                        }
1453
                    }
1454
                }
1455
                if (isset($attrs['name'])) {
1456
                    $this->attributes[$attrs['name']] = $attrs;
1457
                    $aname                            = $attrs['name'];
1458
                } elseif (isset($attrs['ref'])
1459
                          && $attrs['ref'] === 'http://schemas.xmlsoap.org/soap/encoding/:arrayType'
1460
                ) {
1461
                    if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1462
                        $aname = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1463
                    } else {
1464
                        $aname = '';
1465
                    }
1466
                } elseif (isset($attrs['ref'])) {
1467
                    $aname                           = $attrs['ref'];
1468
                    $this->attributes[$attrs['ref']] = $attrs;
1469
                }
1470
1471
                if ($this->currentComplexType) {    // This should *always* be
1472
                    $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...
1473
                }
1474
                // arrayType attribute
1475
                if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])
1476
                    || $this->getLocalPart($aname) === 'arrayType'
1477
                ) {
1478
                    $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1479
                    $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...
1480
                    if (isset($attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'])) {
1481
                        $v = $attrs['http://schemas.xmlsoap.org/wsdl/:arrayType'];
1482
                    } else {
1483
                        $v = '';
1484
                    }
1485
                    if (strpos($v, '[,]')) {
1486
                        $this->complexTypes[$this->currentComplexType]['multidimensional'] = true;
1487
                    }
1488
                    $v = substr($v, 0, strpos($v, '[')); // clip the []
1489
                    if (!strpos($v, ':') && isset($this->typemap[$this->XMLSchemaVersion][$v])) {
1490
                        $v = $this->XMLSchemaVersion . ':' . $v;
1491
                    }
1492
                    $this->complexTypes[$this->currentComplexType]['arrayType'] = $v;
1493
                }
1494
                break;
1495
            case 'complexContent':    // (optional) content for a complexType
1496
                $this->xdebug("do nothing for element $name");
1497
                break;
1498
            case 'complexType':
1499
                array_push($this->complexTypeStack, $this->currentComplexType);
1500
                if (isset($attrs['name'])) {
1501
                    // TODO: what is the scope of named complexTypes that appear
1502
                    //       nested within other c complexTypes?
1503
                    $this->xdebug('processing named complexType ' . $attrs['name']);
1504
                    //$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...
1505
                    $this->currentComplexType                                   = $attrs['name'];
1506
                    $this->complexTypes[$this->currentComplexType]              = $attrs;
1507
                    $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1508
                    // This is for constructs like
1509
                    //           <complexType name="ListOfString" base="soap:Array">
1510
                    //                <sequence>
1511
                    //                    <element name="string" type="xsd:string"
1512
                    //                        minOccurs="0" maxOccurs="unbounded" />
1513
                    //                </sequence>
1514
                    //            </complexType>
1515 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...
1516
                        $this->xdebug('complexType is unusual array');
1517
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1518
                    } else {
1519
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1520
                    }
1521
                } else {
1522
                    $name = $this->CreateTypeName($this->currentElement);
1523
                    $this->xdebug('processing unnamed complexType for element ' . $this->currentElement . ' named ' . $name);
1524
                    $this->currentComplexType = $name;
1525
                    //$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...
1526
                    $this->complexTypes[$this->currentComplexType]              = $attrs;
1527
                    $this->complexTypes[$this->currentComplexType]['typeClass'] = 'complexType';
1528
                    // This is for constructs like
1529
                    //           <complexType name="ListOfString" base="soap:Array">
1530
                    //                <sequence>
1531
                    //                    <element name="string" type="xsd:string"
1532
                    //                        minOccurs="0" maxOccurs="unbounded" />
1533
                    //                </sequence>
1534
                    //            </complexType>
1535 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...
1536
                        $this->xdebug('complexType is unusual array');
1537
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1538
                    } else {
1539
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'struct';
1540
                    }
1541
                }
1542
                $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'false';
1543
                break;
1544
            case 'element':
1545
                array_push($this->elementStack, $this->currentElement);
1546
                if (!isset($attrs['form'])) {
1547
                    if ($this->currentComplexType) {
1548
                        $attrs['form'] = $this->schemaInfo['elementFormDefault'];
1549
                    } else {
1550
                        // global
1551
                        $attrs['form'] = 'qualified';
1552
                    }
1553
                }
1554
                if (isset($attrs['type'])) {
1555
                    $this->xdebug('processing typed element ' . $attrs['name'] . ' of type ' . $attrs['type']);
1556
                    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...
1557 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...
1558
                            $attrs['type'] = $this->defaultNamespace[$pos] . ':' . $attrs['type'];
1559
                            $this->xdebug('used default namespace to make type ' . $attrs['type']);
1560
                        }
1561
                    }
1562
                    // This is for constructs like
1563
                    //           <complexType name="ListOfString" base="soap:Array">
1564
                    //                <sequence>
1565
                    //                    <element name="string" type="xsd:string"
1566
                    //                        minOccurs="0" maxOccurs="unbounded" />
1567
                    //                </sequence>
1568
                    //            </complexType>
1569 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...
1570
                        && $this->complexTypes[$this->currentComplexType]['phpType'] === 'array'
1571
                    ) {
1572
                        $this->xdebug('arrayType for unusual array is ' . $attrs['type']);
1573
                        $this->complexTypes[$this->currentComplexType]['arrayType'] = $attrs['type'];
1574
                    }
1575
                    $this->currentElement = $attrs['name'];
1576
                    $ename                = $attrs['name'];
1577
                } elseif (isset($attrs['ref'])) {
1578
                    $this->xdebug('processing element as ref to ' . $attrs['ref']);
1579
                    $this->currentElement = 'ref to ' . $attrs['ref'];
1580
                    $ename                = $this->getLocalPart($attrs['ref']);
1581
                } else {
1582
                    $type = $this->CreateTypeName($this->currentComplexType . '_' . $attrs['name']);
1583
                    $this->xdebug('processing untyped element ' . $attrs['name'] . ' type ' . $type);
1584
                    $this->currentElement = $attrs['name'];
1585
                    $attrs['type']        = $this->schemaTargetNamespace . ':' . $type;
1586
                    $ename                = $attrs['name'];
1587
                }
1588
                if (isset($ename) && $this->currentComplexType) {
1589
                    $this->xdebug("add element $ename to complexType $this->currentComplexType");
1590
                    $this->complexTypes[$this->currentComplexType]['elements'][$ename] = $attrs;
1591
                } elseif (!isset($attrs['ref'])) {
1592
                    $this->xdebug("add element $ename to elements array");
1593
                    $this->elements[$attrs['name']]              = $attrs;
1594
                    $this->elements[$attrs['name']]['typeClass'] = 'element';
1595
                }
1596
                break;
1597
            case 'enumeration':    //   restriction value list member
1598
                $this->xdebug('enumeration ' . $attrs['value']);
1599
                if ($this->currentSimpleType) {
1600
                    $this->simpleTypes[$this->currentSimpleType]['enumeration'][] = $attrs['value'];
1601
                } elseif ($this->currentComplexType) {
1602
                    $this->complexTypes[$this->currentComplexType]['enumeration'][] = $attrs['value'];
1603
                }
1604
                break;
1605
            case 'extension':    // simpleContent or complexContent type extension
1606
                $this->xdebug('extension ' . $attrs['base']);
1607
                if ($this->currentComplexType) {
1608
                    $ns = $this->getPrefix($attrs['base']);
1609
                    if ($ns == '') {
1610
                        $this->complexTypes[$this->currentComplexType]['extensionBase'] = $this->schemaTargetNamespace . ':' . $attrs['base'];
1611
                    } else {
1612
                        $this->complexTypes[$this->currentComplexType]['extensionBase'] = $attrs['base'];
1613
                    }
1614
                } else {
1615
                    $this->xdebug('no current complexType to set extensionBase');
1616
                }
1617
                break;
1618
            case 'import':
1619
                if (isset($attrs['schemaLocation'])) {
1620
                    $this->xdebug('import namespace ' . $attrs['namespace'] . ' from ' . $attrs['schemaLocation']);
1621
                    $this->imports[$attrs['namespace']][] = array(
1622
                        'location' => $attrs['schemaLocation'],
1623
                        'loaded'   => false
1624
                    );
1625
                } else {
1626
                    $this->xdebug('import namespace ' . $attrs['namespace']);
1627
                    $this->imports[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
1628 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...
1629
                        $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
1630
                    }
1631
                }
1632
                break;
1633
            case 'include':
1634
                if (isset($attrs['schemaLocation'])) {
1635
                    $this->xdebug('include into namespace ' . $this->schemaTargetNamespace . ' from ' . $attrs['schemaLocation']);
1636
                    $this->imports[$this->schemaTargetNamespace][] = array(
1637
                        'location' => $attrs['schemaLocation'],
1638
                        'loaded'   => false
1639
                    );
1640
                } else {
1641
                    $this->xdebug('ignoring invalid XML Schema construct: include without schemaLocation attribute');
1642
                }
1643
                break;
1644
            case 'list':    // simpleType value list
1645
                $this->xdebug("do nothing for element $name");
1646
                break;
1647
            case 'restriction':    // simpleType, simpleContent or complexContent value restriction
1648
                $this->xdebug('restriction ' . $attrs['base']);
1649
                if ($this->currentSimpleType) {
1650
                    $this->simpleTypes[$this->currentSimpleType]['type'] = $attrs['base'];
1651 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...
1652
                    $this->complexTypes[$this->currentComplexType]['restrictionBase'] = $attrs['base'];
1653
                    if (strstr($attrs['base'], ':') === ':Array') {
1654
                        $this->complexTypes[$this->currentComplexType]['phpType'] = 'array';
1655
                    }
1656
                }
1657
                break;
1658
            case 'schema':
1659
                $this->schemaInfo                  = $attrs;
1660
                $this->schemaInfo['schemaVersion'] = $this->getNamespaceFromPrefix($prefix);
1661
                if (isset($attrs['targetNamespace'])) {
1662
                    $this->schemaTargetNamespace = $attrs['targetNamespace'];
1663
                }
1664
                if (!isset($attrs['elementFormDefault'])) {
1665
                    $this->schemaInfo['elementFormDefault'] = 'unqualified';
1666
                }
1667
                if (!isset($attrs['attributeFormDefault'])) {
1668
                    $this->schemaInfo['attributeFormDefault'] = 'unqualified';
1669
                }
1670
                break;
1671
            case 'simpleContent':    // (optional) content for a complexType
1672
                if ($this->currentComplexType) {    // This should *always* be
1673
                    $this->complexTypes[$this->currentComplexType]['simpleContent'] = 'true';
1674
                } else {
1675
                    $this->xdebug("do nothing for element $name because there is no current complexType");
1676
                }
1677
                break;
1678
            case 'simpleType':
1679
                array_push($this->simpleTypeStack, $this->currentSimpleType);
1680
                if (isset($attrs['name'])) {
1681
                    $this->xdebug('processing simpleType for name ' . $attrs['name']);
1682
                    $this->currentSimpleType                        = $attrs['name'];
1683
                    $this->simpleTypes[$attrs['name']]              = $attrs;
1684
                    $this->simpleTypes[$attrs['name']]['typeClass'] = 'simpleType';
1685
                    $this->simpleTypes[$attrs['name']]['phpType']   = 'scalar';
1686
                } else {
1687
                    $name = $this->CreateTypeName($this->currentComplexType . '_' . $this->currentElement);
1688
                    $this->xdebug('processing unnamed simpleType for element ' . $this->currentElement . ' named ' . $name);
1689
                    $this->currentSimpleType = $name;
1690
                    //$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...
1691
                    $this->simpleTypes[$this->currentSimpleType]            = $attrs;
1692
                    $this->simpleTypes[$this->currentSimpleType]['phpType'] = 'scalar';
1693
                }
1694
                break;
1695
            case 'union':    // simpleType type list
1696
                $this->xdebug("do nothing for element $name");
1697
                break;
1698
            default:
1699
                $this->xdebug("do not have any logic to process element $name");
1700
        }
1701
    }
1702
1703
    /**
1704
     * end-element handler
1705
     *
1706
     * @param string $parser XML parser object
1707
     * @param string $name   element name
1708
     * @access   private
1709
     */
1710
    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...
1711
    {
1712
        // bring depth down a notch
1713
        $this->depth--;
1714
        // position of current element is equal to the last value left in depth_array for my depth
1715
        if (isset($this->depth_array[$this->depth])) {
1716
            $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...
1717
        }
1718
        // get element prefix
1719
        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...
1720
            // get unqualified name
1721
            $name = $this->getLocalPart($name);
1722
        } else {
1723
            $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...
1724
        }
1725
        // move on...
1726
        if ($name === 'complexType') {
1727
            $this->xdebug('done processing complexType ' . ($this->currentComplexType ?: '(unknown)'));
1728
            $this->xdebug($this->varDump($this->complexTypes[$this->currentComplexType]));
1729
            $this->currentComplexType = array_pop($this->complexTypeStack);
1730
            //$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...
1731
        }
1732
        if ($name === 'element') {
1733
            $this->xdebug('done processing element ' . ($this->currentElement ?: '(unknown)'));
1734
            $this->currentElement = array_pop($this->elementStack);
1735
        }
1736
        if ($name === 'simpleType') {
1737
            $this->xdebug('done processing simpleType ' . ($this->currentSimpleType ?: '(unknown)'));
1738
            $this->xdebug($this->varDump($this->simpleTypes[$this->currentSimpleType]));
1739
            $this->currentSimpleType = array_pop($this->simpleTypeStack);
1740
        }
1741
    }
1742
1743
    /**
1744
     * element content handler
1745
     *
1746
     * @param string $parser XML parser object
1747
     * @param string $data   element content
1748
     * @access   private
1749
     */
1750
    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...
1751
    {
1752
        $pos = $this->depth_array[$this->depth - 1];
1753
        $this->message[$pos]['cdata'] .= $data;
1754
    }
1755
1756
    /**
1757
     * serialize the schema
1758
     *
1759
     * @access   public
1760
     */
1761
    public function serializeSchema()
1762
    {
1763
        $schemaPrefix = $this->getPrefixFromNamespace($this->XMLSchemaVersion);
1764
        $xml          = '';
1765
        // imports
1766 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...
1767
            foreach ($this->imports as $ns => $list) {
1768
                foreach ($list as $ii) {
1769
                    if ($ii['location'] != '') {
1770
                        $xml .= " <$schemaPrefix:import location=\"" . $ii['location'] . '" namespace="' . $ns . "\" />\n";
1771
                    } else {
1772
                        $xml .= " <$schemaPrefix:import namespace=\"" . $ns . "\" />\n";
1773
                    }
1774
                }
1775
            }
1776
        }
1777
        // complex types
1778
        foreach ($this->complexTypes as $typeName => $attrs) {
1779
            $contentStr = '';
1780
            // serialize child elements
1781
            if (isset($attrs['elements']) && (count($attrs['elements']) > 0)) {
1782
                foreach ($attrs['elements'] as $element => $eParts) {
1783
                    if (isset($eParts['ref'])) {
1784
                        $contentStr .= "   <$schemaPrefix:element ref=\"$element\"/>\n";
1785
                    } else {
1786
                        $contentStr .= "   <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQname($eParts['type']) . "\"";
1787
                        foreach ($eParts as $aName => $aValue) {
1788
                            // handle, e.g., abstract, default, form, minOccurs, maxOccurs, nillable
1789
                            if ($aName !== 'name' && $aName !== 'type') {
1790
                                $contentStr .= " $aName=\"$aValue\"";
1791
                            }
1792
                        }
1793
                        $contentStr .= "/>\n";
1794
                    }
1795
                }
1796
                // compositor wraps elements
1797
                if (isset($attrs['compositor']) && ($attrs['compositor'] != '')) {
1798
                    $contentStr = "  <$schemaPrefix:$attrs[compositor]>\n" . $contentStr . "  </$schemaPrefix:$attrs[compositor]>\n";
1799
                }
1800
            }
1801
            // attributes
1802
            if (isset($attrs['attrs']) && (count($attrs['attrs']) >= 1)) {
1803
                foreach ($attrs['attrs'] as $attr => $aParts) {
1804
                    $contentStr .= "    <$schemaPrefix:attribute";
1805
                    foreach ($aParts as $a => $v) {
1806
                        if ($a === 'ref' || $a === 'type') {
1807
                            $contentStr .= " $a=\"" . $this->contractQname($v) . '"';
1808
                        } elseif ($a === 'http://schemas.xmlsoap.org/wsdl/:arrayType') {
1809
                            $this->usedNamespaces['wsdl'] = $this->namespaces['wsdl'];
1810
                            $contentStr .= ' wsdl:arrayType="' . $this->contractQname($v) . '"';
1811
                        } else {
1812
                            $contentStr .= " $a=\"$v\"";
1813
                        }
1814
                    }
1815
                    $contentStr .= "/>\n";
1816
                }
1817
            }
1818
            // if restriction
1819
            if (isset($attrs['restrictionBase']) && $attrs['restrictionBase'] != '') {
1820
                $contentStr = "   <$schemaPrefix:restriction base=\"" . $this->contractQname($attrs['restrictionBase']) . "\">\n" . $contentStr . "   </$schemaPrefix:restriction>\n";
1821
                // complex or simple content
1822
                if ((isset($attrs['elements']) && count($attrs['elements']) > 0)
1823
                    || (isset($attrs['attrs'])
1824
                        && count($attrs['attrs']) > 0)
1825
                ) {
1826
                    $contentStr = "  <$schemaPrefix:complexContent>\n" . $contentStr . "  </$schemaPrefix:complexContent>\n";
1827
                }
1828
            }
1829
            // finalize complex type
1830
            if ($contentStr != '') {
1831
                $contentStr = " <$schemaPrefix:complexType name=\"$typeName\">\n" . $contentStr . " </$schemaPrefix:complexType>\n";
1832
            } else {
1833
                $contentStr = " <$schemaPrefix:complexType name=\"$typeName\"/>\n";
1834
            }
1835
            $xml .= $contentStr;
1836
        }
1837
        // simple types
1838
        if (isset($this->simpleTypes) && count($this->simpleTypes) > 0) {
1839
            foreach ($this->simpleTypes as $typeName => $eParts) {
1840
                $xml .= " <$schemaPrefix:simpleType name=\"$typeName\">\n  <$schemaPrefix:restriction base=\"" . $this->contractQname($eParts['type']) . "\">\n";
1841
                if (isset($eParts['enumeration'])) {
1842
                    foreach ($eParts['enumeration'] as $e) {
1843
                        $xml .= "  <$schemaPrefix:enumeration value=\"$e\"/>\n";
1844
                    }
1845
                }
1846
                $xml .= "  </$schemaPrefix:restriction>\n </$schemaPrefix:simpleType>";
1847
            }
1848
        }
1849
        // elements
1850
        if (isset($this->elements) && count($this->elements) > 0) {
1851
            foreach ($this->elements as $element => $eParts) {
1852
                $xml .= " <$schemaPrefix:element name=\"$element\" type=\"" . $this->contractQname($eParts['type']) . "\"/>\n";
1853
            }
1854
        }
1855
        // attributes
1856
        if (isset($this->attributes) && count($this->attributes) > 0) {
1857
            foreach ($this->attributes as $attr => $aParts) {
1858
                $xml .= " <$schemaPrefix:attribute name=\"$attr\" type=\"" . $this->contractQname($aParts['type']) . "\"\n/>";
1859
            }
1860
        }
1861
        // finish 'er up
1862
        $attr = '';
1863
        foreach ($this->schemaInfo as $k => $v) {
1864
            if ($k === 'elementFormDefault' || $k === 'attributeFormDefault') {
1865
                $attr .= " $k=\"$v\"";
1866
            }
1867
        }
1868
        $el = "<$schemaPrefix:schema$attr targetNamespace=\"$this->schemaTargetNamespace\"\n";
1869
        foreach (array_diff($this->usedNamespaces, $this->enclosingNamespaces) as $nsp => $ns) {
1870
            $el .= " xmlns:$nsp=\"$ns\"";
1871
        }
1872
        $xml = $el . ">\n" . $xml . "</$schemaPrefix:schema>\n";
1873
1874
        return $xml;
1875
    }
1876
1877
    /**
1878
     * adds debug data to the clas level debug string
1879
     *
1880
     * @param string $string debug data
1881
     * @access   private
1882
     */
1883
    public function xdebug($string)
1884
    {
1885
        $this->debug('<' . $this->schemaTargetNamespace . '> ' . $string);
1886
    }
1887
1888
    /**
1889
     * get the PHP type of a user defined type in the schema
1890
     * PHP type is kind of a misnomer since it actually returns 'struct' for assoc. arrays
1891
     * returns false if no type exists, or not w/ the given namespace
1892
     * else returns a string that is either a native php type, or 'struct'
1893
     *
1894
     * @param  string $type name of defined type
1895
     * @param  string $ns   namespace of type
1896
     * @return mixed
1897
     * @access public
1898
     * @deprecated
1899
     */
1900
    public function getPHPType($type, $ns)
1901
    {
1902
        if (isset($this->typemap[$ns][$type])) {
1903
            //print "found type '$type' and ns $ns in typemap<br>";
1904
            return $this->typemap[$ns][$type];
1905
        } elseif (isset($this->complexTypes[$type])) {
1906
            //print "getting type '$type' and ns $ns from complexTypes array<br>";
1907
            return $this->complexTypes[$type]['phpType'];
1908
        }
1909
1910
        return false;
1911
    }
1912
1913
    /**
1914
     * returns an associative array of information about a given type
1915
     * returns false if no type exists by the given name
1916
     *
1917
     *   For a complexType typeDef = array(
1918
     *   'restrictionBase' => '',
1919
     *   'phpType' => '',
1920
     *   'compositor' => '(sequence|all)',
1921
     *   'elements' => array(), // refs to elements array
1922
     *   'attrs' => array() // refs to attributes array
1923
     *   ... and so on (see addComplexType)
1924
     *   )
1925
     *
1926
     *   For simpleType or element, the array has different keys.
1927
     *
1928
     * @param  string $type
1929
     * @return mixed
1930
     * @access public
1931
     * @see    addComplexType
1932
     * @see    addSimpleType
1933
     * @see    addElement
1934
     */
1935
    public function getTypeDef($type)
1936
    {
1937
        //$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...
1938
        if (substr($type, -1) === '^') {
1939
            $is_element = 1;
1940
            $type       = substr($type, 0, -1);
1941
        } else {
1942
            $is_element = 0;
1943
        }
1944
1945
        if ((!$is_element) && isset($this->complexTypes[$type])) {
1946
            $this->xdebug("in getTypeDef, found complexType $type");
1947
1948
            return $this->complexTypes[$type];
1949
        } elseif ((!$is_element) && isset($this->simpleTypes[$type])) {
1950
            $this->xdebug("in getTypeDef, found simpleType $type");
1951
            if (!isset($this->simpleTypes[$type]['phpType'])) {
1952
                // get info for type to tack onto the simple type
1953
                // TODO: can this ever really apply (i.e. what is a simpleType really?)
1954
                $uqType = substr($this->simpleTypes[$type]['type'], strrpos($this->simpleTypes[$type]['type'], ':') + 1);
1955
                $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...
1956
                $etype  = $this->getTypeDef($uqType);
1957
                if ($etype) {
1958
                    $this->xdebug("in getTypeDef, found type for simpleType $type:");
1959
                    $this->xdebug($this->varDump($etype));
1960
                    if (isset($etype['phpType'])) {
1961
                        $this->simpleTypes[$type]['phpType'] = $etype['phpType'];
1962
                    }
1963
                    if (isset($etype['elements'])) {
1964
                        $this->simpleTypes[$type]['elements'] = $etype['elements'];
1965
                    }
1966
                }
1967
            }
1968
1969
            return $this->simpleTypes[$type];
1970
        } elseif (isset($this->elements[$type])) {
1971
            $this->xdebug("in getTypeDef, found element $type");
1972
            if (!isset($this->elements[$type]['phpType'])) {
1973
                // get info for type to tack onto the element
1974
                $uqType = substr($this->elements[$type]['type'], strrpos($this->elements[$type]['type'], ':') + 1);
1975
                $ns     = substr($this->elements[$type]['type'], 0, strrpos($this->elements[$type]['type'], ':'));
1976
                $etype  = $this->getTypeDef($uqType);
1977
                if ($etype) {
1978
                    $this->xdebug("in getTypeDef, found type for element $type:");
1979
                    $this->xdebug($this->varDump($etype));
1980
                    if (isset($etype['phpType'])) {
1981
                        $this->elements[$type]['phpType'] = $etype['phpType'];
1982
                    }
1983
                    if (isset($etype['elements'])) {
1984
                        $this->elements[$type]['elements'] = $etype['elements'];
1985
                    }
1986
                    if (isset($etype['extensionBase'])) {
1987
                        $this->elements[$type]['extensionBase'] = $etype['extensionBase'];
1988
                    }
1989
                } elseif ($ns === 'http://www.w3.org/2001/XMLSchema') {
1990
                    $this->xdebug("in getTypeDef, element $type is an XSD type");
1991
                    $this->elements[$type]['phpType'] = 'scalar';
1992
                }
1993
            }
1994
1995
            return $this->elements[$type];
1996
        } elseif (isset($this->attributes[$type])) {
1997
            $this->xdebug("in getTypeDef, found attribute $type");
1998
1999
            return $this->attributes[$type];
2000
        } elseif (preg_match('/_ContainedType$/', $type)) {
2001
            $this->xdebug("in getTypeDef, have an untyped element $type");
2002
            $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...
2003
            $typeDef['phpType']   = 'scalar';
2004
            $typeDef['type']      = 'http://www.w3.org/2001/XMLSchema:string';
2005
2006
            return $typeDef;
2007
        }
2008
        $this->xdebug("in getTypeDef, did not find $type");
2009
2010
        return false;
2011
    }
2012
2013
    /**
2014
     * returns a sample serialization of a given type, or false if no type by the given name
2015
     *
2016
     * @param  string $type name of type
2017
     * @return mixed
2018
     * @access public
2019
     * @deprecated
2020
     */
2021
    public function serializeTypeDef($type)
2022
    {
2023
        //print "in sTD() for type $type<br>";
2024
        if ($typeDef = $this->getTypeDef($type)) {
2025
            $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...
2026
            if (is_array($typeDef['attrs'])) {
2027
                foreach ($typeDef['attrs'] as $attName => $data) {
2028
                    $str .= " $attName=\"{type = " . $data['type'] . "}\"";
2029
                }
2030
            }
2031
            $str .= " xmlns=\"" . $this->schema['targetNamespace'] . "\"";
2032
            if (count($typeDef['elements']) > 0) {
2033
                $str .= '>';
2034
                foreach ($typeDef['elements'] as $element => $eData) {
2035
                    $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...
2036
                }
2037
                $str .= "</$type>";
2038
            } elseif ($typeDef['typeClass'] === 'element') {
2039
                $str .= "></$type>";
2040
            } else {
2041
                $str .= '/>';
2042
            }
2043
2044
            return $str;
2045
        }
2046
2047
        return false;
2048
    }
2049
2050
    /**
2051
     * returns HTML form elements that allow a user
2052
     * to enter values for creating an instance of the given type.
2053
     *
2054
     * @param  string $name name for type instance
2055
     * @param  string $type name of type
2056
     * @return string
2057
     * @access public
2058
     * @deprecated
2059
     */
2060
    public function typeToForm($name, $type)
2061
    {
2062
        // get typedef
2063
        if ($typeDef = $this->getTypeDef($type)) {
2064
            // if struct
2065
            if ($typeDef['phpType'] === 'struct') {
2066
                $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...
2067
                foreach ($typeDef['elements'] as $child => $childDef) {
2068
                    $buffer .= "
2069
                    <tr><td align='right'>$childDef[name] (type: " . $this->getLocalPart($childDef['type']) . "):</td>
2070
                    <td><input type='text' name='parameters[" . $name . "][$childDef[name]]'></td></tr>";
2071
                }
2072
                $buffer .= '</table>';
2073
                // if array
2074
            } elseif ($typeDef['phpType'] === 'array') {
2075
                $buffer .= '<table>';
2076
                for ($i = 0; $i < 3; ++$i) {
2077
                    $buffer .= "
2078
                    <tr><td align='right'>array item (type: $typeDef[arrayType]):</td>
2079
                    <td><input type='text' name='parameters[" . $name . "][]'></td></tr>";
2080
                }
2081
                $buffer .= '</table>';
2082
                // if scalar
2083
            } else {
2084
                $buffer .= "<input type='text' name='parameters[$name]'>";
2085
            }
2086
        } else {
2087
            $buffer .= "<input type='text' name='parameters[$name]'>";
2088
        }
2089
2090
        return $buffer;
2091
    }
2092
2093
    /**
2094
     * adds a complex type to the schema
2095
     *
2096
     * example: array
2097
     *
2098
     * addType(
2099
     *   'ArrayOfstring',
2100
     *   'complexType',
2101
     *   'array',
2102
     *   '',
2103
     *   'SOAP-ENC:Array',
2104
     *   array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'string[]'),
2105
     *   'xsd:string'
2106
     * );
2107
     *
2108
     * example: PHP associative array ( SOAP Struct )
2109
     *
2110
     * addType(
2111
     *   'SOAPStruct',
2112
     *   'complexType',
2113
     *   'struct',
2114
     *   'all',
2115
     *   array('myVar'=> array('name'=>'myVar','type'=>'string')
2116
     * );
2117
     *
2118
     * @param                  $name
2119
     * @param string           $typeClass
2120
     * @param string           $phpType
2121
     * @param string           $compositor
2122
     * @param namespace|string $restrictionBase
2123
     * @param array            $elements
2124
     * @param array            $attrs
2125
     * @param string           $arrayType
2126
     * @internal param $name
2127
     * @internal param $typeClass (complexType|simpleType|attribute)
2128
     * @internal param $phpType : currently supported are array and struct (php assoc array)
2129
     * @internal param $compositor (all|sequence|choice)
2130
     * @internal param namespace $restrictionBase :name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2131
     * @internal param $elements = array ( name = array(name=>'',type=>'') )
2132
     * @internal param $attrs = array(
2133
     *       array(
2134
     *       'ref' => "http://schemas.xmlsoap.org/soap/encoding/:arrayType",
2135
     *       "http://schemas.xmlsoap.org/wsdl/:arrayType" => "string[]"
2136
     *       )
2137
     *       )
2138
     * @internal param $arrayType : namespace:name (http://www.w3.org/2001/XMLSchema:string)
2139
     * @access   public
2140
     * @see      getTypeDef
2141
     */
2142
    public function addComplexType(
2143
        $name,
2144
        $typeClass = 'complexType',
2145
        $phpType = 'array',
2146
        $compositor = '',
2147
        $restrictionBase = '',
2148
        $elements = array(),
2149
        $attrs = array(),
2150
        $arrayType = ''
2151
    ) {
2152
        $this->complexTypes[$name] = array(
2153
            'name'            => $name,
2154
            'typeClass'       => $typeClass,
2155
            'phpType'         => $phpType,
2156
            'compositor'      => $compositor,
2157
            'restrictionBase' => $restrictionBase,
2158
            'elements'        => $elements,
2159
            'attrs'           => $attrs,
2160
            'arrayType'       => $arrayType
2161
        );
2162
2163
        $this->xdebug("addComplexType $name:");
2164
        $this->appendDebug($this->varDump($this->complexTypes[$name]));
2165
    }
2166
2167
    /**
2168
     * adds a simple type to the schema
2169
     *
2170
     * @param string $name
2171
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
2172
     * @param string $typeClass       (should always be simpleType)
2173
     * @param string $phpType         (should always be scalar)
2174
     * @param array  $enumeration     array of values
2175
     * @access public
2176
     * @see    nusoap_xmlschema
2177
     * @see    getTypeDef
2178
     */
2179
    public function addSimpleType(
2180
        $name,
2181
        $restrictionBase = '',
2182
        $typeClass = 'simpleType',
2183
        $phpType = 'scalar',
2184
        $enumeration = array()
2185
    ) {
2186
        $this->simpleTypes[$name] = array(
2187
            'name'        => $name,
2188
            'typeClass'   => $typeClass,
2189
            'phpType'     => $phpType,
2190
            'type'        => $restrictionBase,
2191
            'enumeration' => $enumeration
2192
        );
2193
2194
        $this->xdebug("addSimpleType $name:");
2195
        $this->appendDebug($this->varDump($this->simpleTypes[$name]));
2196
    }
2197
2198
    /**
2199
     * adds an element to the schema
2200
     *
2201
     * @param array $attrs attributes that must include name and type
2202
     * @see    nusoap_xmlschema
2203
     * @access public
2204
     */
2205
    public function addElement($attrs)
2206
    {
2207
        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...
2208
            $attrs['type'] = $this->schemaTargetNamespace . ':' . $attrs['type'];
2209
        }
2210
        $this->elements[$attrs['name']]              = $attrs;
2211
        $this->elements[$attrs['name']]['typeClass'] = 'element';
2212
2213
        $this->xdebug('addElement ' . $attrs['name']);
2214
        $this->appendDebug($this->varDump($this->elements[$attrs['name']]));
2215
    }
2216
}
2217
2218
/**
2219
 * Backward compatibility
2220
 */
2221
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...
2222
{
2223
}
2224
2225
?><?php
2226
2227
/**
2228
 * For creating serializable abstractions of native PHP types.  This class
2229
 * allows element name/namespace, XSD type, and XML attributes to be
2230
 * associated with a value.  This is extremely useful when WSDL is not
2231
 * used, but is also useful when WSDL is used with polymorphic types, including
2232
 * xsd:anyType and user-defined types.
2233
 *
2234
 * @author   Dietrich Ayala <[email protected]>
2235
 * @access   public
2236
 */
2237
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...
2238
{
2239
    /**
2240
     * The XML element name
2241
     *
2242
     * @var string
2243
     * @access private
2244
     */
2245
    public $name;
2246
    /**
2247
     * The XML type name (string or false)
2248
     *
2249
     * @var mixed
2250
     * @access private
2251
     */
2252
    public $type;
2253
    /**
2254
     * The PHP value
2255
     *
2256
     * @var mixed
2257
     * @access private
2258
     */
2259
    public $value;
2260
    /**
2261
     * The XML element namespace (string or false)
2262
     *
2263
     * @var mixed
2264
     * @access private
2265
     */
2266
    public $element_ns;
2267
    /**
2268
     * The XML type namespace (string or false)
2269
     *
2270
     * @var mixed
2271
     * @access private
2272
     */
2273
    public $type_ns;
2274
    /**
2275
     * The XML element attributes (array or false)
2276
     *
2277
     * @var mixed
2278
     * @access private
2279
     */
2280
    public $attributes;
2281
2282
    /**
2283
     * constructor
2284
     *
2285
     * @param string $name       optional name
2286
     * @param mixed  $type       optional type name
2287
     * @param mixed  $value      optional value
2288
     * @param mixed  $element_ns optional namespace of value
2289
     * @param mixed  $type_ns    optional namespace of type
2290
     * @param mixed  $attributes associative array of attributes to add to element serialization
2291
     * @access   public
2292
     * @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...
2293
     */
2294
    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...
2295
        $name = 'soapval',
2296
        $type = false,
2297
        $value = -1,
2298
        $element_ns = false,
2299
        $type_ns = false,
2300
        $attributes = false
2301
    ) {
2302
        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...
2303
        $this->name       = $name;
2304
        $this->type       = $type;
2305
        $this->value      = $value;
2306
        $this->element_ns = $element_ns;
2307
        $this->type_ns    = $type_ns;
2308
        $this->attributes = $attributes;
2309
    }
2310
2311
    /**
2312
     * return serialized value
2313
     *
2314
     * @param  string $use The WSDL use value (encoded|literal)
2315
     * @return string XML data
2316
     * @access   public
2317
     */
2318
    public function serialize($use = 'encoded')
2319
    {
2320
        return $this->serialize_val($this->value, $this->name, $this->type, $this->element_ns, $this->type_ns, $this->attributes, $use, true);
2321
    }
2322
2323
    /**
2324
     * decodes a soapval object into a PHP native type
2325
     *
2326
     * @return mixed
2327
     * @access   public
2328
     */
2329
    public function decode()
2330
    {
2331
        return $this->value;
2332
    }
2333
}
2334
2335
?><?php
2336
2337
/**
2338
 * transport class for sending/receiving data via HTTP and HTTPS
2339
 * NOTE: PHP must be compiled with the CURL extension for HTTPS support
2340
 *
2341
 * @author   Dietrich Ayala <[email protected]>
2342
 * @author   Scott Nichol <[email protected]>
2343
 * @access   public
2344
 */
2345
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...
2346
{
2347
    public $url                  = '';
2348
    public $uri                  = '';
2349
    public $digest_uri           = '';
2350
    public $scheme               = '';
2351
    public $host                 = '';
2352
    public $port                 = '';
2353
    public $path                 = '';
2354
    public $request_method       = 'POST';
2355
    public $protocol_version     = '1.0';
2356
    public $encoding             = '';
2357
    public $outgoing_headers     = array();
2358
    public $incoming_headers     = array();
2359
    public $incoming_cookies     = array();
2360
    public $outgoing_payload     = '';
2361
    public $incoming_payload     = '';
2362
    public $response_status_line;    // HTTP response status line
2363
    public $useSOAPAction        = true;
2364
    public $persistentConnection = false;
2365
    public $ch                   = false;    // cURL handle
2366
    public $ch_options           = array();    // cURL custom options
2367
    public $use_curl             = false;        // force cURL use
2368
    public $proxy                = null;            // proxy information (associative array)
2369
    public $username             = '';
2370
    public $password             = '';
2371
    public $authtype             = '';
2372
    public $digestRequest        = array();
2373
    public $certRequest          = array();    // keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional)
2374
    // cainfofile: certificate authority file, e.g. '$pathToPemFiles/rootca.pem'
2375
    // sslcertfile: SSL certificate file, e.g. '$pathToPemFiles/mycert.pem'
2376
    // sslkeyfile: SSL key file, e.g. '$pathToPemFiles/mykey.pem'
2377
    // passphrase: SSL key password/passphrase
2378
    // certpassword: SSL certificate password
2379
    // verifypeer: default is 1
2380
    // verifyhost: default is 1
2381
2382
    /**
2383
     * constructor
2384
     *
2385
     * @param string  $url          The URL to which to connect
2386
     * @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...
2387
     * @param boolean $use_curl     Whether to try to force cURL use
2388
     * @access public
2389
     * @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...
2390
     */
2391
    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...
2392
    {
2393
        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...
2394
        $this->debug("ctor url=$url use_curl=$use_curl curl_options:");
2395
        $this->appendDebug($this->varDump($curl_options));
2396
        $this->setURL($url);
2397
        if (is_array($curl_options)) {
2398
            $this->ch_options = $curl_options;
2399
        }
2400
        $this->use_curl = $use_curl;
2401
        preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
2402
        $this->setHeader('User-Agent', $this->title . '/' . $this->version . ' (' . $rev[1] . ')');
2403
    }
2404
2405
    /**
2406
     * sets a cURL option
2407
     *
2408
     * @param mixed $option The cURL option (always integer?)
2409
     * @param mixed $value  The cURL option value
2410
     * @access   private
2411
     */
2412
    public function setCurlOption($option, $value)
2413
    {
2414
        $this->debug("setCurlOption option=$option, value=");
2415
        $this->appendDebug($this->varDump($value));
2416
        curl_setopt($this->ch, $option, $value);
2417
    }
2418
2419
    /**
2420
     * sets an HTTP header
2421
     *
2422
     * @param string $name  The name of the header
2423
     * @param string $value The value of the header
2424
     * @access private
2425
     */
2426
    public function setHeader($name, $value)
2427
    {
2428
        $this->outgoing_headers[$name] = $value;
2429
        $this->debug("set header $name: $value");
2430
    }
2431
2432
    /**
2433
     * unsets an HTTP header
2434
     *
2435
     * @param string $name The name of the header
2436
     * @access private
2437
     */
2438
    public function unsetHeader($name)
2439
    {
2440
        if (isset($this->outgoing_headers[$name])) {
2441
            $this->debug("unset header $name");
2442
            unset($this->outgoing_headers[$name]);
2443
        }
2444
    }
2445
2446
    /**
2447
     * sets the URL to which to connect
2448
     *
2449
     * @param string $url The URL to which to connect
2450
     * @access private
2451
     */
2452
    public function setURL($url)
2453
    {
2454
        $this->url = $url;
2455
2456
        $u = parse_url($url);
2457
        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...
2458
            $this->debug("parsed URL $k = $v");
2459
            $this->$k = $v;
2460
        }
2461
2462
        // add any GET params to path
2463
        if (isset($u['query']) && $u['query'] != '') {
2464
            $this->path .= '?' . $u['query'];
2465
        }
2466
2467
        // set default port
2468
        if (!isset($u['port'])) {
2469
            if ($u['scheme'] === 'https') {
2470
                $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...
2471
            } else {
2472
                $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...
2473
            }
2474
        }
2475
2476
        $this->uri        = $this->path;
2477
        $this->digest_uri = $this->uri;
2478
2479
        // build headers
2480
        if (!isset($u['port'])) {
2481
            $this->setHeader('Host', $this->host);
2482
        } else {
2483
            $this->setHeader('Host', $this->host . ':' . $this->port);
2484
        }
2485
2486
        if (isset($u['user']) && $u['user'] != '') {
2487
            $this->setCredentials(urldecode($u['user']), isset($u['pass']) ? urldecode($u['pass']) : '');
2488
        }
2489
    }
2490
2491
    /**
2492
     * gets the I/O method to use
2493
     *
2494
     * @return string I/O method to use (socket|curl|unknown)
2495
     * @access   private
2496
     */
2497
    public function io_method()
2498
    {
2499
        if ($this->use_curl || ($this->scheme === 'https') || ($this->scheme === 'http' && $this->authtype === 'ntlm')
2500
            || ($this->scheme === 'http'
2501
                && is_array($this->proxy)
2502
                && $this->proxy['authtype'] === 'ntlm')
2503
        ) {
2504
            return 'curl';
2505
        }
2506
        if (($this->scheme === 'http' || $this->scheme === 'ssl') && $this->authtype !== 'ntlm'
2507
            && (!is_array($this->proxy) || $this->proxy['authtype'] !== 'ntlm')
2508
        ) {
2509
            return 'socket';
2510
        }
2511
2512
        return 'unknown';
2513
    }
2514
2515
    /**
2516
     * establish an HTTP connection
2517
     *
2518
     * @param  int     $connection_timeout
2519
     * @param  integer $response_timeout set response timeout in seconds
2520
     * @return bool    true if connected, false if not
2521
     * @internal param int $timeout set connection timeout in seconds
2522
     * @access   private
2523
     */
2524
    public function connect($connection_timeout = 0, $response_timeout = 30)
2525
    {
2526
        // For PHP 4.3 with OpenSSL, change https scheme to ssl, then treat like
2527
        // "regular" socket.
2528
        // TODO: disabled for now because OpenSSL must be *compiled* in (not just
2529
        //       loaded), and until PHP5 stream_get_wrappers is not available.
2530
        //      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...
2531
        //          if (version_compare(phpversion(), '4.3.0') >= 0) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% 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...
2532
        //              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...
2533
        //                  $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...
2534
        //                  $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...
2535
        //              }
2536
        //          }
2537
        //      }
2538
        $this->debug("connect connection_timeout $connection_timeout, response_timeout $response_timeout, scheme $this->scheme, host $this->host, port $this->port");
2539
        if ($this->io_method() === 'socket') {
2540
            if (!is_array($this->proxy)) {
2541
                $host = $this->host;
2542
                $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...
2543
            } else {
2544
                $host = $this->proxy['host'];
2545
                $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...
2546
            }
2547
2548
            // use persistent connection
2549
            if ($this->persistentConnection && isset($this->fp) && is_resource($this->fp)) {
2550
                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...
2551
                    $this->debug('Re-use persistent connection');
2552
2553
                    return true;
2554
                }
2555
                fclose($this->fp);
2556
                $this->debug('Closed persistent connection at EOF');
2557
            }
2558
2559
            // munge host if using OpenSSL
2560
            if ($this->scheme === 'ssl') {
2561
                $host = 'ssl://' . $host;
2562
            }
2563
            $this->debug('calling fsockopen with host ' . $host . ' connection_timeout ' . $connection_timeout);
2564
2565
            // open socket
2566
            if ($connection_timeout > 0) {
2567
                $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...
2568
            } else {
2569
                $this->fp = @fsockopen($host, $this->port, $this->errno, $this->error_str);
2570
            }
2571
2572
            // test pointer
2573
            if (!$this->fp) {
2574
                $msg = 'Couldn\'t open socket connection to server ' . $this->url;
2575
                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...
2576
                    $msg .= ', Error (' . $this->errno . '): ' . $this->error_str;
2577
                } else {
2578
                    $msg .= ' prior to connect().  This is often a problem looking up the host name.';
2579
                }
2580
                $this->debug($msg);
2581
                $this->setError($msg);
2582
2583
                return false;
2584
            }
2585
2586
            // set response timeout
2587
            $this->debug('set response timeout to ' . $response_timeout);
2588
            socket_set_timeout($this->fp, $response_timeout);
2589
2590
            $this->debug('socket connected');
2591
2592
            return true;
2593
        } elseif ($this->io_method() === 'curl') {
2594
            if (!extension_loaded('curl')) {
2595
                //          $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...
2596
                $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.');
2597
2598
                return false;
2599
            }
2600
            // Avoid warnings when PHP does not have these options
2601
            if (defined('CURLOPT_CONNECTIONTIMEOUT')) {
2602
                $CURLOPT_CONNECTIONTIMEOUT = CURLOPT_CONNECTIONTIMEOUT;
2603
            } else {
2604
                $CURLOPT_CONNECTIONTIMEOUT = 78;
2605
            }
2606
            if (defined('CURLOPT_HTTPAUTH')) {
2607
                $CURLOPT_HTTPAUTH = CURLOPT_HTTPAUTH;
2608
            } else {
2609
                $CURLOPT_HTTPAUTH = 107;
2610
            }
2611
            if (defined('CURLOPT_PROXYAUTH')) {
2612
                $CURLOPT_PROXYAUTH = CURLOPT_PROXYAUTH;
2613
            } else {
2614
                $CURLOPT_PROXYAUTH = 111;
2615
            }
2616
            if (defined('CURLAUTH_BASIC')) {
2617
                $CURLAUTH_BASIC = CURLAUTH_BASIC;
2618
            } else {
2619
                $CURLAUTH_BASIC = 1;
2620
            }
2621
            if (defined('CURLAUTH_DIGEST')) {
2622
                $CURLAUTH_DIGEST = CURLAUTH_DIGEST;
2623
            } else {
2624
                $CURLAUTH_DIGEST = 2;
2625
            }
2626
            if (defined('CURLAUTH_NTLM')) {
2627
                $CURLAUTH_NTLM = CURLAUTH_NTLM;
2628
            } else {
2629
                $CURLAUTH_NTLM = 8;
2630
            }
2631
2632
            $this->debug('connect using cURL');
2633
            // init CURL
2634
            $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...
2635
            // set url
2636
            $hostURL = ($this->port != '') ? "$this->scheme://$this->host:$this->port" : "$this->scheme://$this->host";
2637
            // add path
2638
            $hostURL .= $this->path;
2639
            $this->setCurlOption(CURLOPT_URL, $hostURL);
2640
            // follow location headers (re-directs)
2641
            $this->setCurlOption(CURLOPT_FOLLOWLOCATION, 1);
2642
            // ask for headers in the response output
2643
            $this->setCurlOption(CURLOPT_HEADER, 1);
2644
            // ask for the response output as the return value
2645
            $this->setCurlOption(CURLOPT_RETURNTRANSFER, 1);
2646
            // encode
2647
            // We manage this ourselves through headers and encoding
2648
            //      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...
2649
            //          $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...
2650
            //      }
2651
            // persistent connection
2652
            if ($this->persistentConnection) {
2653
                // I believe the following comment is now bogus, having applied to
2654
                // the code when it used CURLOPT_CUSTOMREQUEST to send the request.
2655
                // The way we send data, we cannot use persistent connections, since
2656
                // there will be some "junk" at the end of our request.
2657
                //$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...
2658
                $this->persistentConnection = false;
2659
                $this->setHeader('Connection', 'close');
2660
            }
2661
            // set timeouts
2662
            if ($connection_timeout != 0) {
2663
                $this->setCurlOption($CURLOPT_CONNECTIONTIMEOUT, $connection_timeout);
2664
            }
2665
            if ($response_timeout != 0) {
2666
                $this->setCurlOption(CURLOPT_TIMEOUT, $response_timeout);
2667
            }
2668
2669
            if ($this->scheme === 'https') {
2670
                $this->debug('set cURL SSL verify options');
2671
                // recent versions of cURL turn on peer/host checking by default,
2672
                // while PHP binaries are not compiled with a default location for the
2673
                // CA cert bundle, so disable peer/host checking.
2674
                //$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...
2675
                $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 0);
2676
                $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 0);
2677
2678
                // support client certificates (thanks Tobias Boes, Doug Anarino, Eryan Ariobowo)
2679
                if ($this->authtype === 'certificate') {
2680
                    $this->debug('set cURL certificate options');
2681
                    if (isset($this->certRequest['cainfofile'])) {
2682
                        $this->setCurlOption(CURLOPT_CAINFO, $this->certRequest['cainfofile']);
2683
                    }
2684
                    if (isset($this->certRequest['verifypeer'])) {
2685
                        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, $this->certRequest['verifypeer']);
2686
                    } else {
2687
                        $this->setCurlOption(CURLOPT_SSL_VERIFYPEER, 1);
2688
                    }
2689
                    if (isset($this->certRequest['verifyhost'])) {
2690
                        $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, $this->certRequest['verifyhost']);
2691
                    } else {
2692
                        $this->setCurlOption(CURLOPT_SSL_VERIFYHOST, 1);
2693
                    }
2694
                    if (isset($this->certRequest['sslcertfile'])) {
2695
                        $this->setCurlOption(CURLOPT_SSLCERT, $this->certRequest['sslcertfile']);
2696
                    }
2697
                    if (isset($this->certRequest['sslkeyfile'])) {
2698
                        $this->setCurlOption(CURLOPT_SSLKEY, $this->certRequest['sslkeyfile']);
2699
                    }
2700
                    if (isset($this->certRequest['passphrase'])) {
2701
                        $this->setCurlOption(CURLOPT_SSLKEYPASSWD, $this->certRequest['passphrase']);
2702
                    }
2703
                    if (isset($this->certRequest['certpassword'])) {
2704
                        $this->setCurlOption(CURLOPT_SSLCERTPASSWD, $this->certRequest['certpassword']);
2705
                    }
2706
                }
2707
            }
2708
            if ($this->authtype && ($this->authtype !== 'certificate')) {
2709
                if ($this->username) {
2710
                    $this->debug('set cURL username/password');
2711
                    $this->setCurlOption(CURLOPT_USERPWD, "$this->username:$this->password");
2712
                }
2713
                if ($this->authtype === 'basic') {
2714
                    $this->debug('set cURL for Basic authentication');
2715
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_BASIC);
2716
                }
2717
                if ($this->authtype === 'digest') {
2718
                    $this->debug('set cURL for digest authentication');
2719
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_DIGEST);
2720
                }
2721
                if ($this->authtype === 'ntlm') {
2722
                    $this->debug('set cURL for NTLM authentication');
2723
                    $this->setCurlOption($CURLOPT_HTTPAUTH, $CURLAUTH_NTLM);
2724
                }
2725
            }
2726
            if (is_array($this->proxy)) {
2727
                $this->debug('set cURL proxy options');
2728
                if ($this->proxy['port'] != '') {
2729
                    $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host'] . ':' . $this->proxy['port']);
2730
                } else {
2731
                    $this->setCurlOption(CURLOPT_PROXY, $this->proxy['host']);
2732
                }
2733
                if ($this->proxy['username'] || $this->proxy['password']) {
2734
                    $this->debug('set cURL proxy authentication options');
2735
                    $this->setCurlOption(CURLOPT_PROXYUSERPWD, $this->proxy['username'] . ':' . $this->proxy['password']);
2736
                    if ($this->proxy['authtype'] === 'basic') {
2737
                        $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_BASIC);
2738
                    }
2739
                    if ($this->proxy['authtype'] === 'ntlm') {
2740
                        $this->setCurlOption($CURLOPT_PROXYAUTH, $CURLAUTH_NTLM);
2741
                    }
2742
                }
2743
            }
2744
            $this->debug('cURL connection set up');
2745
2746
            return true;
2747
        } else {
2748
            $this->setError('Unknown scheme ' . $this->scheme);
2749
            $this->debug('Unknown scheme ' . $this->scheme);
2750
2751
            return false;
2752
        }
2753
    }
2754
2755
    /**
2756
     * sends the SOAP request and gets the SOAP response via HTTP[S]
2757
     *
2758
     * @param  string  $data             message data
2759
     * @param  integer $timeout          set connection timeout in seconds
2760
     * @param  integer $response_timeout set response timeout in seconds
2761
     * @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...
2762
     * @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...
2763
     * @access   public
2764
     */
2765
    public function send($data, $timeout = 0, $response_timeout = 30, $cookies = null)
2766
    {
2767
        $this->debug('entered send() with data of length: ' . strlen($data));
2768
2769
        $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...
2770
        $tries          = 0;
2771
        while ($this->tryagain) {
2772
            $this->tryagain = false;
2773
            if (++$tries < 2) {
2774
                // make connnection
2775
                if (!$this->connect($timeout, $response_timeout)) {
2776
                    return false;
2777
                }
2778
2779
                // send request
2780
                if (!$this->sendRequest($data, $cookies)) {
2781
                    return false;
2782
                }
2783
2784
                // get response
2785
                $respdata = $this->getResponse();
2786
            } else {
2787
                $this->setError("Too many tries to get an OK response ($this->response_status_line)");
2788
            }
2789
        }
2790
        $this->debug('end of send()');
2791
2792
        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...
2793
    }
2794
2795
    /**
2796
     * sends the SOAP request and gets the SOAP response via HTTPS using CURL
2797
     *
2798
     * @param  string  $data             message data
2799
     * @param  integer $timeout          set connection timeout in seconds
2800
     * @param  integer $response_timeout set response timeout in seconds
2801
     * @param  array   $cookies          cookies to send
2802
     * @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...
2803
     * @access   public
2804
     * @deprecated
2805
     */
2806
    public function sendHTTPS($data, $timeout = 0, $response_timeout = 30, $cookies)
2807
    {
2808
        return $this->send($data, $timeout, $response_timeout, $cookies);
2809
    }
2810
2811
    /**
2812
     * if authenticating, set user credentials here
2813
     *
2814
     * @param string $username
2815
     * @param string $password
2816
     * @param string $authtype      (basic|digest|certificate|ntlm)
2817
     * @param array  $digestRequest (keys must be nonce, nc, realm, qop)
2818
     * @param array  $certRequest   (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
2819
     * @access   public
2820
     */
2821
    public function setCredentials(
2822
        $username,
2823
        $password,
2824
        $authtype = 'basic',
2825
        $digestRequest = array(),
2826
        $certRequest = array()
2827
    ) {
2828
        $this->debug("setCredentials username=$username authtype=$authtype digestRequest=");
2829
        $this->appendDebug($this->varDump($digestRequest));
2830
        $this->debug('certRequest=');
2831
        $this->appendDebug($this->varDump($certRequest));
2832
        // cf. RFC 2617
2833
        if ($authtype === 'basic') {
2834
            $this->setHeader('Authorization', 'Basic ' . base64_encode(str_replace(':', '', $username) . ':' . $password));
2835
        } elseif ($authtype === 'digest') {
2836
            if (isset($digestRequest['nonce'])) {
2837
                $digestRequest['nc'] = isset($digestRequest['nc']) ? $digestRequest['nc']++ : 1;
2838
2839
                // calculate the Digest hashes (calculate code based on digest implementation found at: http://www.rassoc.com/gregr/weblog/stories/2002/07/09/webServicesSecurityHttpDigestAuthenticationWithoutActiveDirectory.html)
2840
2841
                // A1 = unq(username-value) ":" unq(realm-value) ":" passwd
2842
                $A1 = $username . ':' . (isset($digestRequest['realm']) ? $digestRequest['realm'] : '') . ':' . $password;
2843
2844
                // H(A1) = MD5(A1)
2845
                $HA1 = md5($A1);
2846
2847
                // A2 = Method ":" digest-uri-value
2848
                $A2 = $this->request_method . ':' . $this->digest_uri;
2849
2850
                // H(A2)
2851
                $HA2 = md5($A2);
2852
2853
                // 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...
2854
                // if qop == auth:
2855
                // request-digest  = <"> < KD ( H(A1),     unq(nonce-value)
2856
                //                              ":" nc-value
2857
                //                              ":" unq(cnonce-value)
2858
                //                              ":" unq(qop-value)
2859
                //                              ":" 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...
2860
                //                            ) <">
2861
                // if qop is missing,
2862
                // request-digest  = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2) ) > <">
2863
2864
                $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...
2865
                $nonce          = isset($digestRequest['nonce']) ? $digestRequest['nonce'] : '';
2866
                $cnonce         = $nonce;
2867
                if ($digestRequest['qop'] != '') {
2868
                    $unhashedDigest = $HA1 . ':' . $nonce . ':' . sprintf('%08d', $digestRequest['nc']) . ':' . $cnonce . ':' . $digestRequest['qop'] . ':' . $HA2;
2869
                } else {
2870
                    $unhashedDigest = $HA1 . ':' . $nonce . ':' . $HA2;
2871
                }
2872
2873
                $hashedDigest = md5($unhashedDigest);
2874
2875
                $opaque = '';
2876
                if (isset($digestRequest['opaque'])) {
2877
                    $opaque = ', opaque="' . $digestRequest['opaque'] . '"';
2878
                }
2879
2880
                $this->setHeader('Authorization',
2881
                                 'Digest username="' . $username . '", realm="' . $digestRequest['realm'] . '", nonce="' . $nonce . '", uri="' . $this->digest_uri . $opaque . '", cnonce="' . $cnonce . '", nc=' . sprintf('%08x', $digestRequest['nc'])
2882
                                 . ', qop="' . $digestRequest['qop'] . '", response="' . $hashedDigest . '"');
2883
            }
2884
        } elseif ($authtype === 'certificate') {
2885
            $this->certRequest = $certRequest;
2886
            $this->debug('Authorization header not set for certificate');
2887
        } elseif ($authtype === 'ntlm') {
2888
            // do nothing
2889
            $this->debug('Authorization header not set for ntlm');
2890
        }
2891
        $this->username      = $username;
2892
        $this->password      = $password;
2893
        $this->authtype      = $authtype;
2894
        $this->digestRequest = $digestRequest;
2895
    }
2896
2897
    /**
2898
     * set the soapaction value
2899
     *
2900
     * @param string $soapaction
2901
     * @access   public
2902
     */
2903
    public function setSOAPAction($soapaction)
2904
    {
2905
        $this->setHeader('SOAPAction', '"' . $soapaction . '"');
2906
    }
2907
2908
    /**
2909
     * use http encoding
2910
     *
2911
     * @param string $enc encoding style. supported values: gzip, deflate, or both
2912
     * @access   public
2913
     */
2914
    public function setEncoding($enc = 'gzip, deflate')
2915
    {
2916
        if (function_exists('gzdeflate')) {
2917
            $this->protocol_version = '1.1';
2918
            $this->setHeader('Accept-Encoding', $enc);
2919
            if (!isset($this->outgoing_headers['Connection'])) {
2920
                $this->setHeader('Connection', 'close');
2921
                $this->persistentConnection = false;
2922
            }
2923
            // deprecated as of PHP 5.3.0
2924
            //set_magic_quotes_runtime(0);
2925
            $this->encoding = $enc;
2926
        }
2927
    }
2928
2929
    /**
2930
     * set proxy info here
2931
     *
2932
     * @param string $proxyhost     use an empty string to remove proxy
2933
     * @param string $proxyport
2934
     * @param string $proxyusername
2935
     * @param string $proxypassword
2936
     * @param string $proxyauthtype (basic|ntlm)
2937
     * @access   public
2938
     */
2939
    public function setProxy(
2940
        $proxyhost,
2941
        $proxyport,
2942
        $proxyusername = '',
2943
        $proxypassword = '',
2944
        $proxyauthtype = 'basic'
2945
    ) {
2946
        if ($proxyhost) {
2947
            $this->proxy = array(
2948
                'host'     => $proxyhost,
2949
                'port'     => $proxyport,
2950
                'username' => $proxyusername,
2951
                'password' => $proxypassword,
2952
                'authtype' => $proxyauthtype
2953
            );
2954
            if ($proxyusername != '' && $proxypassword != '' && $proxyauthtype = 'basic') {
2955
                $this->setHeader('Proxy-Authorization', ' Basic ' . base64_encode($proxyusername . ':' . $proxypassword));
2956
            }
2957
        } else {
2958
            $this->debug('remove proxy');
2959
            $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...
2960
            unsetHeader('Proxy-Authorization');
2961
        }
2962
    }
2963
2964
    /**
2965
     * Test if the given string starts with a header that is to be skipped.
2966
     * Skippable headers result from chunked transfer and proxy requests.
2967
     *
2968
     * @param string $data The string to check.
2969
     * @returns boolean Whether a skippable header was found.
2970
     * @access  private
2971
     */
2972
    public function isSkippableCurlHeader(&$data)
2973
    {
2974
        $skipHeaders = array(
2975
            'HTTP/1.1 100',
2976
            'HTTP/1.0 301',
2977
            'HTTP/1.1 301',
2978
            'HTTP/1.0 302',
2979
            'HTTP/1.1 302',
2980
            'HTTP/1.0 401',
2981
            'HTTP/1.1 401',
2982
            'HTTP/1.0 200 Connection established'
2983
        );
2984
        foreach ($skipHeaders as $hd) {
2985
            $prefix = substr($data, 0, strlen($hd));
2986
            if ($prefix == $hd) {
2987
                return true;
2988
            }
2989
        }
2990
2991
        return false;
2992
    }
2993
2994
    /**
2995
     * decode a string that is encoded w/ "chunked' transfer encoding
2996
     * as defined in RFC2068 19.4.6
2997
     *
2998
     * @param string $buffer
2999
     * @param string $lb
3000
     * @returns  string
3001
     * @access   public
3002
     * @deprecated
3003
     */
3004
    public function decodeChunked($buffer, $lb)
3005
    {
3006
        // length := 0
3007
        $length = 0;
3008
        $new    = '';
3009
3010
        // read chunk-size, chunk-extension (if any) and CRLF
3011
        // get the position of the linebreak
3012
        $chunkend = strpos($buffer, $lb);
3013
        if (false === $chunkend) {
3014
            $this->debug('no linebreak found in decodeChunked');
3015
3016
            return $new;
3017
        }
3018
        $temp       = substr($buffer, 0, $chunkend);
3019
        $chunk_size = hexdec(trim($temp));
3020
        $chunkstart = $chunkend + strlen($lb);
3021
        // 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...
3022
        while ($chunk_size > 0) {
3023
            $this->debug("chunkstart: $chunkstart chunk_size: $chunk_size");
3024
            $chunkend = strpos($buffer, $lb, $chunkstart + $chunk_size);
3025
3026
            // Just in case we got a broken connection
3027
            if (false === $chunkend) {
3028
                $chunk = substr($buffer, $chunkstart);
3029
                // append chunk-data to entity-body
3030
                $new .= $chunk;
3031
                $length += strlen($chunk);
3032
                break;
3033
            }
3034
3035
            // read chunk-data and CRLF
3036
            $chunk = substr($buffer, $chunkstart, $chunkend - $chunkstart);
3037
            // append chunk-data to entity-body
3038
            $new .= $chunk;
3039
            // length := length + chunk-size
3040
            $length += strlen($chunk);
3041
            // read chunk-size and CRLF
3042
            $chunkstart = $chunkend + strlen($lb);
3043
3044
            $chunkend = strpos($buffer, $lb, $chunkstart) + strlen($lb);
3045
            if (false === $chunkend) {
3046
                break; //Just in case we got a broken connection
3047
            }
3048
            $temp       = substr($buffer, $chunkstart, $chunkend - $chunkstart);
3049
            $chunk_size = hexdec(trim($temp));
3050
            $chunkstart = $chunkend;
3051
        }
3052
3053
        return $new;
3054
    }
3055
3056
    /**
3057
     * Writes the payload, including HTTP headers, to $this->outgoing_payload.
3058
     *
3059
     * @param  string $data       HTTP body
3060
     * @param  string $cookie_str data for HTTP Cookie header
3061
     * @return void
3062
     * @access  private
3063
     */
3064
    public function buildPayload($data, $cookie_str = '')
3065
    {
3066
        // Note: for cURL connections, $this->outgoing_payload is ignored,
3067
        // as is the Content-Length header, but these are still created as
3068
        // debugging guides.
3069
3070
        // add content-length header
3071
        if ($this->request_method !== 'GET') {
3072
            $this->setHeader('Content-Length', strlen($data));
3073
        }
3074
3075
        // start building outgoing payload:
3076
        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...
3077
            $uri = $this->url;
3078
        } else {
3079
            $uri = $this->uri;
3080
        }
3081
        $req = "$this->request_method $uri HTTP/$this->protocol_version";
3082
        $this->debug("HTTP request: $req");
3083
        $this->outgoing_payload = "$req\r\n";
3084
3085
        // loop thru headers, serializing
3086
        foreach ($this->outgoing_headers as $k => $v) {
3087
            $hdr = $k . ': ' . $v;
3088
            $this->debug("HTTP header: $hdr");
3089
            $this->outgoing_payload .= "$hdr\r\n";
3090
        }
3091
3092
        // add any cookies
3093
        if ($cookie_str != '') {
3094
            $hdr = 'Cookie: ' . $cookie_str;
3095
            $this->debug("HTTP header: $hdr");
3096
            $this->outgoing_payload .= "$hdr\r\n";
3097
        }
3098
3099
        // header/body separator
3100
        $this->outgoing_payload .= "\r\n";
3101
3102
        // add data
3103
        $this->outgoing_payload .= $data;
3104
    }
3105
3106
    /**
3107
     * sends the SOAP request via HTTP[S]
3108
     *
3109
     * @param  string $data    message data
3110
     * @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...
3111
     * @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...
3112
     * @access   private
3113
     */
3114
    public function sendRequest($data, $cookies = null)
3115
    {
3116
        // build cookie string
3117
        $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 3114 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...
3118
3119
        // build payload
3120
        $this->buildPayload($data, $cookie_str);
3121
3122
        if ($this->io_method() === 'socket') {
3123
            // send payload
3124
            if (!fwrite($this->fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
3125
                $this->setError('couldn\'t write message data to socket');
3126
                $this->debug('couldn\'t write message data to socket');
3127
3128
                return false;
3129
            }
3130
            $this->debug('wrote data to socket, length = ' . strlen($this->outgoing_payload));
3131
3132
            return true;
3133
        } elseif ($this->io_method() === 'curl') {
3134
            // set payload
3135
            // cURL does say this should only be the verb, and in fact it
3136
            // turns out that the URI and HTTP version are appended to this, which
3137
            // some servers refuse to work with (so we no longer use this method!)
3138
            //$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...
3139
            $curl_headers = array();
3140
            foreach ($this->outgoing_headers as $k => $v) {
3141
                if ($k === 'Connection' || $k === 'Content-Length' || $k === 'Host' || $k === 'Authorization'
3142
                    || $k === 'Proxy-Authorization'
3143
                ) {
3144
                    $this->debug("Skip cURL header $k: $v");
3145
                } else {
3146
                    $curl_headers[] = "$k: $v";
3147
                }
3148
            }
3149
            if ($cookie_str != '') {
3150
                $curl_headers[] = 'Cookie: ' . $cookie_str;
3151
            }
3152
            $this->setCurlOption(CURLOPT_HTTPHEADER, $curl_headers);
3153
            $this->debug('set cURL HTTP headers');
3154
            if ($this->request_method === 'POST') {
3155
                $this->setCurlOption(CURLOPT_POST, 1);
3156
                $this->setCurlOption(CURLOPT_POSTFIELDS, $data);
3157
                $this->debug('set cURL POST data');
3158
            } 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...
3159
            }
3160
            // insert custom user-set cURL options
3161
            foreach ($this->ch_options as $key => $val) {
3162
                $this->setCurlOption($key, $val);
3163
            }
3164
3165
            $this->debug('set cURL payload');
3166
3167
            return true;
3168
        }
3169
    }
3170
3171
    /**
3172
     * gets the SOAP response via HTTP[S]
3173
     *
3174
     * @return string the response (also sets member variables like incoming_payload)
3175
     * @access   private
3176
     */
3177
    public function getResponse()
3178
    {
3179
        $this->incoming_payload = '';
3180
3181
        if ($this->io_method() === 'socket') {
3182
            // loop until headers have been retrieved
3183
            $data = '';
3184
            while (!isset($lb)) {
3185
3186
                // We might EOF during header read.
3187 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...
3188
                    $this->incoming_payload = $data;
3189
                    $this->debug('found no headers before EOF after length ' . strlen($data));
3190
                    $this->debug("received before EOF:\n" . $data);
3191
                    $this->setError('server failed to send headers');
3192
3193
                    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...
3194
                }
3195
3196
                $tmp    = fgets($this->fp, 256);
3197
                $tmplen = strlen($tmp);
3198
                $this->debug("read line of $tmplen bytes: " . trim($tmp));
3199
3200 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...
3201
                    $this->incoming_payload = $data;
3202
                    $this->debug('socket read of headers timed out after length ' . strlen($data));
3203
                    $this->debug('read before timeout: ' . $data);
3204
                    $this->setError('socket read of headers timed out');
3205
3206
                    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...
3207
                }
3208
3209
                $data .= $tmp;
3210
                $pos = strpos($data, "\r\n\r\n");
3211
                if ($pos > 1) {
3212
                    $lb = "\r\n";
3213
                } else {
3214
                    $pos = strpos($data, "\n\n");
3215
                    if ($pos > 1) {
3216
                        $lb = "\n";
3217
                    }
3218
                }
3219
                // remove 100 headers
3220
                if (isset($lb) && preg_match('/^HTTP\/1.1 100/', $data)) {
3221
                    unset($lb);
3222
                    $data = '';
3223
                }//
3224
            }
3225
            // store header data
3226
            $this->incoming_payload .= $data;
3227
            $this->debug('found end of headers after length ' . strlen($data));
3228
            // process headers
3229
            $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...
3230
            $header_array           = explode($lb, $header_data);
3231
            $this->incoming_headers = array();
3232
            $this->incoming_cookies = array();
3233 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...
3234
                $arr = explode(':', $header_line, 2);
3235
                if (count($arr) > 1) {
3236
                    $header_name                          = strtolower(trim($arr[0]));
3237
                    $this->incoming_headers[$header_name] = trim($arr[1]);
3238
                    if ($header_name === 'set-cookie') {
3239
                        // TODO: allow multiple cookies from parseCookie
3240
                        $cookie = $this->parseCookie(trim($arr[1]));
3241
                        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...
3242
                            $this->incoming_cookies[] = $cookie;
3243
                            $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3244
                        } else {
3245
                            $this->debug('did not find cookie in ' . trim($arr[1]));
3246
                        }
3247
                    }
3248
                } elseif (isset($header_name)) {
3249
                    // append continuation line to previous header
3250
                    $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3251
                }
3252
            }
3253
3254
            // loop until msg has been received
3255
            if (isset($this->incoming_headers['transfer-encoding'])
3256
                && strtolower($this->incoming_headers['transfer-encoding']) === 'chunked'
3257
            ) {
3258
                $content_length = 2147483647;    // ignore any content-length header
3259
                $chunked        = true;
3260
                $this->debug('want to read chunked content');
3261
            } elseif (isset($this->incoming_headers['content-length'])) {
3262
                $content_length = $this->incoming_headers['content-length'];
3263
                $chunked        = false;
3264
                $this->debug("want to read content of length $content_length");
3265
            } else {
3266
                $content_length = 2147483647;
3267
                $chunked        = false;
3268
                $this->debug('want to read content to EOF');
3269
            }
3270
            $data = '';
3271
            do {
3272
                if ($chunked) {
3273
                    $tmp    = fgets($this->fp, 256);
3274
                    $tmplen = strlen($tmp);
3275
                    $this->debug("read chunk line of $tmplen bytes");
3276 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...
3277
                        $this->incoming_payload = $data;
3278
                        $this->debug('socket read of chunk length timed out after length ' . strlen($data));
3279
                        $this->debug("read before timeout:\n" . $data);
3280
                        $this->setError('socket read of chunk length timed out');
3281
3282
                        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...
3283
                    }
3284
                    $content_length = hexdec(trim($tmp));
3285
                    $this->debug("chunk length $content_length");
3286
                }
3287
                $strlen = 0;
3288
                while (($strlen < $content_length) && (!feof($this->fp))) {
3289
                    $readlen = min(8192, $content_length - $strlen);
3290
                    $tmp     = fread($this->fp, $readlen);
3291
                    $tmplen  = strlen($tmp);
3292
                    $this->debug("read buffer of $tmplen bytes");
3293 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...
3294
                        $this->incoming_payload = $data;
3295
                        $this->debug('socket read of body timed out after length ' . strlen($data));
3296
                        $this->debug("read before timeout:\n" . $data);
3297
                        $this->setError('socket read of body timed out');
3298
3299
                        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...
3300
                    }
3301
                    $strlen += $tmplen;
3302
                    $data .= $tmp;
3303
                }
3304
                if ($chunked && ($content_length > 0)) {
3305
                    $tmp    = fgets($this->fp, 256);
3306
                    $tmplen = strlen($tmp);
3307
                    $this->debug("read chunk terminator of $tmplen bytes");
3308 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...
3309
                        $this->incoming_payload = $data;
3310
                        $this->debug('socket read of chunk terminator timed out after length ' . strlen($data));
3311
                        $this->debug("read before timeout:\n" . $data);
3312
                        $this->setError('socket read of chunk terminator timed out');
3313
3314
                        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...
3315
                    }
3316
                }
3317
            } while ($chunked && ($content_length > 0) && (!feof($this->fp)));
3318
            if (feof($this->fp)) {
3319
                $this->debug('read to EOF');
3320
            }
3321
            $this->debug('read body of length ' . strlen($data));
3322
            $this->incoming_payload .= $data;
3323
            $this->debug('received a total of ' . strlen($this->incoming_payload) . ' bytes of data from server');
3324
3325
            // close filepointer
3326
            if ((isset($this->incoming_headers['connection'])
3327
                 && strtolower($this->incoming_headers['connection']) === 'close')
3328
                || (!$this->persistentConnection)
3329
                || feof($this->fp)
3330
            ) {
3331
                fclose($this->fp);
3332
                $this->fp = false;
3333
                $this->debug('closed socket');
3334
            }
3335
3336
            // connection was closed unexpectedly
3337
            if ($this->incoming_payload == '') {
3338
                $this->setError('no response from server');
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
            // decode transfer-encoding
3344
            //      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...
3345
            //          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...
3346
            //              $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...
3347
            //              return false;
3348
            //          }
3349
            //print "<pre>\nde-chunked:\n---------------\n$data\n\n---------------\n</pre>";
3350
            // set decoded payload
3351
            //          $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...
3352
            //      }
3353
        } elseif ($this->io_method() === 'curl') {
3354
            // send and receive
3355
            $this->debug('send and receive with cURL');
3356
            $this->incoming_payload = curl_exec($this->ch);
3357
            $data                   = $this->incoming_payload;
3358
3359
            $cErr = curl_error($this->ch);
3360
            if ($cErr != '') {
3361
                $err = 'cURL ERROR: ' . curl_errno($this->ch) . ': ' . $cErr . '<br>';
3362
                // TODO: there is a PHP bug that can cause this to SEGV for CURLINFO_CONTENT_TYPE
3363
                foreach (curl_getinfo($this->ch) as $k => $v) {
3364
                    $err .= "$k: $v<br>";
3365
                }
3366
                $this->debug($err);
3367
                $this->setError($err);
3368
                curl_close($this->ch);
3369
3370
                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...
3371
            } 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...
3372
                //echo '<pre>';
3373
                //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...
3374
                //echo '</pre>';
3375
            }
3376
            // close curl
3377
            $this->debug('No cURL error, closing cURL');
3378
            curl_close($this->ch);
3379
3380
            // try removing skippable headers
3381
            $savedata = $data;
3382
            while ($this->isSkippableCurlHeader($data)) {
3383
                $this->debug('Found HTTP header to skip');
3384 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...
3385
                    $data = ltrim(substr($data, $pos));
3386
                } elseif ($pos = strpos($data, "\n\n")) {
3387
                    $data = ltrim(substr($data, $pos));
3388
                }
3389
            }
3390
3391
            if ($data == '') {
3392
                // have nothing left; just remove 100 header(s)
3393
                $data = $savedata;
3394
                while (preg_match('/^HTTP\/1.1 100/', $data)) {
3395 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...
3396
                        $data = ltrim(substr($data, $pos));
3397
                    } elseif ($pos = strpos($data, "\n\n")) {
3398
                        $data = ltrim(substr($data, $pos));
3399
                    }
3400
                }
3401
            }
3402
3403
            // separate content from HTTP headers
3404
            if ($pos = strpos($data, "\r\n\r\n")) {
3405
                $lb = "\r\n";
3406
            } elseif ($pos = strpos($data, "\n\n")) {
3407
                $lb = "\n";
3408
            } else {
3409
                $this->debug('no proper separation of headers and document');
3410
                $this->setError('no proper separation of headers and document');
3411
3412
                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...
3413
            }
3414
            $header_data  = trim(substr($data, 0, $pos));
3415
            $header_array = explode($lb, $header_data);
3416
            $data         = ltrim(substr($data, $pos));
3417
            $this->debug('found proper separation of headers and document');
3418
            $this->debug('cleaned data, stringlen: ' . strlen($data));
3419
            // clean headers
3420 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...
3421
                $arr = explode(':', $header_line, 2);
3422
                if (count($arr) > 1) {
3423
                    $header_name                          = strtolower(trim($arr[0]));
3424
                    $this->incoming_headers[$header_name] = trim($arr[1]);
3425
                    if ($header_name === 'set-cookie') {
3426
                        // TODO: allow multiple cookies from parseCookie
3427
                        $cookie = $this->parseCookie(trim($arr[1]));
3428
                        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...
3429
                            $this->incoming_cookies[] = $cookie;
3430
                            $this->debug('found cookie: ' . $cookie['name'] . ' = ' . $cookie['value']);
3431
                        } else {
3432
                            $this->debug('did not find cookie in ' . trim($arr[1]));
3433
                        }
3434
                    }
3435
                } elseif (isset($header_name)) {
3436
                    // append continuation line to previous header
3437
                    $this->incoming_headers[$header_name] .= $lb . ' ' . $header_line;
3438
                }
3439
            }
3440
        }
3441
3442
        $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...
3443
        $arr                        = explode(' ', $this->response_status_line, 3);
3444
        $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...
3445
        $http_status                = (int)$arr[1];
3446
        $http_reason                = count($arr) > 2 ? $arr[2] : '';
3447
3448
        // see if we need to resend the request with http digest authentication
3449
        if (isset($this->incoming_headers['location']) && ($http_status == 301 || $http_status == 302)) {
3450
            $this->debug("Got $http_status $http_reason with Location: " . $this->incoming_headers['location']);
3451
            $this->setURL($this->incoming_headers['location']);
3452
            $this->tryagain = true;
3453
3454
            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...
3455
        }
3456
3457
        // see if we need to resend the request with http digest authentication
3458
        if (isset($this->incoming_headers['www-authenticate']) && $http_status == 401) {
3459
            $this->debug("Got 401 $http_reason with WWW-Authenticate: " . $this->incoming_headers['www-authenticate']);
3460
            if (false !== strpos($this->incoming_headers['www-authenticate'], 'Digest ')) {
3461
                $this->debug('Server wants digest authentication');
3462
                // remove "Digest " from our elements
3463
                $digestString = str_replace('Digest ', '', $this->incoming_headers['www-authenticate']);
3464
3465
                // parse elements into array
3466
                $digestElements = explode(',', $digestString);
3467
                foreach ($digestElements as $val) {
3468
                    $tempElement                    = explode('=', trim($val), 2);
3469
                    $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...
3470
                }
3471
3472
                // should have (at least) qop, realm, nonce
3473
                if (isset($digestRequest['nonce'])) {
3474
                    $this->setCredentials($this->username, $this->password, 'digest', $digestRequest);
3475
                    $this->tryagain = true;
3476
3477
                    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...
3478
                }
3479
            }
3480
            $this->debug('HTTP authentication failed');
3481
            $this->setError('HTTP authentication failed');
3482
3483
            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...
3484
        }
3485
3486
        if (($http_status >= 300 && $http_status <= 307) || ($http_status >= 400 && $http_status <= 417)
3487
            || ($http_status >= 501 && $http_status <= 505)
3488
        ) {
3489
            $this->setError("Unsupported HTTP response status $http_status $http_reason (soapclient->response has contents of the response)");
3490
3491
            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...
3492
        }
3493
3494
        // decode content-encoding
3495
        if (isset($this->incoming_headers['content-encoding']) && $this->incoming_headers['content-encoding'] != '') {
3496
            if (strtolower($this->incoming_headers['content-encoding']) === 'deflate'
3497
                || strtolower($this->incoming_headers['content-encoding']) === 'gzip'
3498
            ) {
3499
                // if decoding works, use it. else assume data wasn't gzencoded
3500
                if (function_exists('gzinflate')) {
3501
                    //$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...
3502
                    // IIS 5 requires gzinflate instead of gzuncompress (similar to IE 5 and gzdeflate v. gzcompress)
3503
                    // this means there are no Zlib headers, although there should be
3504
                    $this->debug('The gzinflate function exists');
3505
                    $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...
3506
                    if ($this->incoming_headers['content-encoding'] === 'deflate') {
3507
                        if ($degzdata = @gzinflate($data)) {
3508
                            $data = $degzdata;
3509
                            $this->debug('The payload has been inflated to ' . strlen($data) . ' bytes');
3510 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...
3511
                                // test for the case that the payload has been compressed twice
3512
                                $this->debug('The inflated payload is smaller than the gzipped one; try again');
3513
                                if ($degzdata = @gzinflate($data)) {
3514
                                    $data = $degzdata;
3515
                                    $this->debug('The payload has been inflated again to ' . strlen($data) . ' bytes');
3516
                                }
3517
                            }
3518
                        } else {
3519
                            $this->debug('Error using gzinflate to inflate the payload');
3520
                            $this->setError('Error using gzinflate to inflate the payload');
3521
                        }
3522
                    } elseif ($this->incoming_headers['content-encoding'] === 'gzip') {
3523
                        if ($degzdata = @gzinflate(substr($data, 10))) {    // do our best
3524
                            $data = $degzdata;
3525
                            $this->debug('The payload has been un-gzipped to ' . strlen($data) . ' bytes');
3526 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...
3527
                                // test for the case that the payload has been compressed twice
3528
                                $this->debug('The un-gzipped payload is smaller than the gzipped one; try again');
3529
                                if ($degzdata = @gzinflate(substr($data, 10))) {
3530
                                    $data = $degzdata;
3531
                                    $this->debug('The payload has been un-gzipped again to ' . strlen($data) . ' bytes');
3532
                                }
3533
                            }
3534
                        } else {
3535
                            $this->debug('Error using gzinflate to un-gzip the payload');
3536
                            $this->setError('Error using gzinflate to un-gzip the payload');
3537
                        }
3538
                    }
3539
                    //$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...
3540
                    //print "<xmp>\nde-inflated:\n---------------\n$data\n-------------\n</xmp>";
3541
                    // set decoded payload
3542
                    $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...
3543
                } else {
3544
                    $this->debug('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3545
                    $this->setError('The server sent compressed data. Your php install must have the Zlib extension compiled in to support this.');
3546
                }
3547
            } else {
3548
                $this->debug('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3549
                $this->setError('Unsupported Content-Encoding ' . $this->incoming_headers['content-encoding']);
3550
            }
3551
        } else {
3552
            $this->debug('No Content-Encoding header');
3553
        }
3554
3555
        if ('' === $data) {
3556
            $this->debug('no data after headers!');
3557
            $this->setError('no data present after HTTP headers');
3558
3559
            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...
3560
        }
3561
3562
        return $data;
3563
    }
3564
3565
    /**
3566
     * sets the content-type for the SOAP message to be sent
3567
     *
3568
     * @param string $type    the content type, MIME style
3569
     * @param mixed  $charset character set used for encoding (or false)
3570
     * @access  public
3571
     */
3572
    public function setContentType($type, $charset = false)
3573
    {
3574
        $this->setHeader('Content-Type', $type . ($charset ? '; charset=' . $charset : ''));
3575
    }
3576
3577
    /**
3578
     * specifies that an HTTP persistent connection should be used
3579
     *
3580
     * @return boolean whether the request was honored by this method.
3581
     * @access  public
3582
     */
3583
    public function usePersistentConnection()
3584
    {
3585
        if (isset($this->outgoing_headers['Accept-Encoding'])) {
3586
            return false;
3587
        }
3588
        $this->protocol_version     = '1.1';
3589
        $this->persistentConnection = true;
3590
        $this->setHeader('Connection', 'Keep-Alive');
3591
3592
        return true;
3593
    }
3594
3595
    /**
3596
     * parse an incoming Cookie into it's parts
3597
     *
3598
     * @param  string $cookie_str content of cookie
3599
     * @return array  with data of that cookie
3600
     * @access  private
3601
     */
3602
    /*
3603
     * TODO: allow a Set-Cookie string to be parsed into multiple cookies
3604
     */
3605
    public function parseCookie($cookie_str)
3606
    {
3607
        $cookie_str = str_replace('; ', ';', $cookie_str) . ';';
3608
        $data       = preg_split('/;/', $cookie_str);
3609
        $value_str  = $data[0];
3610
3611
        $cookie_param = 'domain=';
3612
        $start        = strpos($cookie_str, $cookie_param);
3613 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...
3614
            $domain = substr($cookie_str, $start + strlen($cookie_param));
3615
            $domain = substr($domain, 0, strpos($domain, ';'));
3616
        } else {
3617
            $domain = '';
3618
        }
3619
3620
        $cookie_param = 'expires=';
3621
        $start        = strpos($cookie_str, $cookie_param);
3622 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...
3623
            $expires = substr($cookie_str, $start + strlen($cookie_param));
3624
            $expires = substr($expires, 0, strpos($expires, ';'));
3625
        } else {
3626
            $expires = '';
3627
        }
3628
3629
        $cookie_param = 'path=';
3630
        $start        = strpos($cookie_str, $cookie_param);
3631 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...
3632
            $path = substr($cookie_str, $start + strlen($cookie_param));
3633
            $path = substr($path, 0, strpos($path, ';'));
3634
        } else {
3635
            $path = '/';
3636
        }
3637
3638
        $cookie_param = ';secure;';
3639
        if (strpos($cookie_str, $cookie_param) !== false) {
3640
            $secure = true;
3641
        } else {
3642
            $secure = false;
3643
        }
3644
3645
        $sep_pos = strpos($value_str, '=');
3646
3647
        if ($sep_pos) {
3648
            $name   = substr($value_str, 0, $sep_pos);
3649
            $value  = substr($value_str, $sep_pos + 1);
3650
            $cookie = array(
3651
                'name'    => $name,
3652
                'value'   => $value,
3653
                'domain'  => $domain,
3654
                'path'    => $path,
3655
                'expires' => $expires,
3656
                'secure'  => $secure
3657
            );
3658
3659
            return $cookie;
3660
        }
3661
3662
        return false;
3663
    }
3664
3665
    /**
3666
     * sort out cookies for the current request
3667
     *
3668
     * @param  array   $cookies array with all cookies
3669
     * @param  boolean $secure  is the send-content secure or not?
3670
     * @return string  for Cookie-HTTP-Header
3671
     * @access  private
3672
     */
3673
    public function getCookiesForRequest($cookies, $secure = false)
3674
    {
3675
        $cookie_str = '';
3676
        if ((null !== $cookies) && is_array($cookies)) {
3677
            foreach ($cookies as $cookie) {
3678
                if (!is_array($cookie)) {
3679
                    continue;
3680
                }
3681
                $this->debug('check cookie for validity: ' . $cookie['name'] . '=' . $cookie['value']);
3682
                if (isset($cookie['expires']) && (!empty($cookie['expires']))) {
3683
                    if (strtotime($cookie['expires']) <= time()) {
3684
                        $this->debug('cookie has expired');
3685
                        continue;
3686
                    }
3687
                }
3688 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...
3689
                    $domain = preg_quote($cookie['domain']);
3690
                    if (!preg_match("'.*$domain$'i", $this->host)) {
3691
                        $this->debug('cookie has different domain');
3692
                        continue;
3693
                    }
3694
                }
3695 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...
3696
                    $path = preg_quote($cookie['path']);
3697
                    if (!preg_match("'^$path.*'i", $this->path)) {
3698
                        $this->debug('cookie is for a different path');
3699
                        continue;
3700
                    }
3701
                }
3702
                if ((!$secure) && isset($cookie['secure']) && $cookie['secure']) {
3703
                    $this->debug('cookie is secure, transport is not');
3704
                    continue;
3705
                }
3706
                $cookie_str .= $cookie['name'] . '=' . $cookie['value'] . '; ';
3707
                $this->debug('add cookie to Cookie-String: ' . $cookie['name'] . '=' . $cookie['value']);
3708
            }
3709
        }
3710
3711
        return $cookie_str;
3712
    }
3713
}
3714
3715
?><?php
3716
3717
/**
3718
 *
3719
 * nusoap_server allows the user to create a SOAP server
3720
 * that is capable of receiving messages and returning responses
3721
 *
3722
 * @author   Dietrich Ayala <[email protected]>
3723
 * @author   Scott Nichol <[email protected]>
3724
 * @access   public
3725
 */
3726
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...
3727
{
3728
    /**
3729
     * HTTP headers of request
3730
     * @var array
3731
     * @access private
3732
     */
3733
    public $headers = array();
3734
    /**
3735
     * HTTP request
3736
     * @var string
3737
     * @access private
3738
     */
3739
    public $request = '';
3740
    /**
3741
     * SOAP headers from request (incomplete namespace resolution; special characters not escaped) (text)
3742
     * @var string
3743
     * @access public
3744
     */
3745
    public $requestHeaders = '';
3746
    /**
3747
     * SOAP Headers from request (parsed)
3748
     * @var mixed
3749
     * @access public
3750
     */
3751
    public $requestHeader = null;
3752
    /**
3753
     * SOAP body request portion (incomplete namespace resolution; special characters not escaped) (text)
3754
     * @var string
3755
     * @access public
3756
     */
3757
    public $document = '';
3758
    /**
3759
     * SOAP payload for request (text)
3760
     * @var string
3761
     * @access public
3762
     */
3763
    public $requestSOAP = '';
3764
    /**
3765
     * requested method namespace URI
3766
     * @var string
3767
     * @access private
3768
     */
3769
    public $methodURI = '';
3770
    /**
3771
     * name of method requested
3772
     * @var string
3773
     * @access private
3774
     */
3775
    public $methodname = '';
3776
    /**
3777
     * method parameters from request
3778
     * @var array
3779
     * @access private
3780
     */
3781
    public $methodparams = array();
3782
    /**
3783
     * SOAP Action from request
3784
     * @var string
3785
     * @access private
3786
     */
3787
    public $SOAPAction = '';
3788
    /**
3789
     * character set encoding of incoming (request) messages
3790
     * @var string
3791
     * @access public
3792
     */
3793
    public $xml_encoding = '';
3794
    /**
3795
     * toggles whether the parser decodes element content w/ utf8_decode()
3796
     * @var boolean
3797
     * @access public
3798
     */
3799
    public $decode_utf8 = true;
3800
3801
    /**
3802
     * HTTP headers of response
3803
     * @var array
3804
     * @access public
3805
     */
3806
    public $outgoing_headers = array();
3807
    /**
3808
     * HTTP response
3809
     * @var string
3810
     * @access private
3811
     */
3812
    public $response = '';
3813
    /**
3814
     * SOAP headers for response (text or array of soapval or associative array)
3815
     * @var mixed
3816
     * @access public
3817
     */
3818
    public $responseHeaders = '';
3819
    /**
3820
     * SOAP payload for response (text)
3821
     * @var string
3822
     * @access private
3823
     */
3824
    public $responseSOAP = '';
3825
    /**
3826
     * method return value to place in response
3827
     * @var mixed
3828
     * @access private
3829
     */
3830
    public $methodreturn = false;
3831
    /**
3832
     * whether $methodreturn is a string of literal XML
3833
     * @var boolean
3834
     * @access public
3835
     */
3836
    public $methodreturnisliteralxml = false;
3837
    /**
3838
     * SOAP fault for response (or false)
3839
     * @var mixed
3840
     * @access private
3841
     */
3842
    public $fault = false;
3843
    /**
3844
     * text indication of result (for debugging)
3845
     * @var string
3846
     * @access private
3847
     */
3848
    public $result = 'successful';
3849
3850
    /**
3851
     * assoc array of operations => opData; operations are added by the register()
3852
     * method or by parsing an external WSDL definition
3853
     * @var array
3854
     * @access private
3855
     */
3856
    public $operations = array();
3857
    /**
3858
     * wsdl instance (if one)
3859
     * @var mixed
3860
     * @access private
3861
     */
3862
    public $wsdl = false;
3863
    /**
3864
     * URL for WSDL (if one)
3865
     * @var mixed
3866
     * @access private
3867
     */
3868
    public $externalWSDLURL = false;
3869
    /**
3870
     * whether to append debug to response as XML comment
3871
     * @var boolean
3872
     * @access public
3873
     */
3874
    public $debug_flag = false;
3875
3876
    /**
3877
     * constructor
3878
     * the optional parameter is a path to a WSDL file that you'd like to bind the server instance to.
3879
     *
3880
     * @param mixed $wsdl file path or URL (string) , or wsdl instance (object)
3881
     * @access   public
3882
     * @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...
3883
     */
3884
    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...
3885
    {
3886
        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...
3887
        // turn on debugging?
3888
        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...
3889
        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...
3890
3891
        if (isset($_SERVER)) {
3892
            $this->debug('_SERVER is defined:');
3893
            $this->appendDebug($this->varDump($_SERVER));
3894
        } elseif (isset($HTTP_SERVER_VARS)) {
3895
            $this->debug('HTTP_SERVER_VARS is defined:');
3896
            $this->appendDebug($this->varDump($HTTP_SERVER_VARS));
3897
        } else {
3898
            $this->debug('Neither _SERVER nor HTTP_SERVER_VARS is defined.');
3899
        }
3900
3901
        if (isset($debug)) {
3902
            $this->debug("In nusoap_server, set debug_flag=$debug based on global flag");
3903
            $this->debug_flag = $debug;
3904
        } elseif (isset($_SERVER['QUERY_STRING'])) {
3905
            $qs = explode('&', $_SERVER['QUERY_STRING']);
3906 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...
3907
                if (substr($v, 0, 6) === 'debug=') {
3908
                    $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #1');
3909
                    $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...
3910
                }
3911
            }
3912
        } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3913
            $qs = explode('&', $HTTP_SERVER_VARS['QUERY_STRING']);
3914 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...
3915
                if (substr($v, 0, 6) === 'debug=') {
3916
                    $this->debug('In nusoap_server, set debug_flag=' . substr($v, 6) . ' based on query string #2');
3917
                    $this->debug_flag = substr($v, 6);
3918
                }
3919
            }
3920
        }
3921
3922
        // wsdl
3923
        if ($wsdl) {
3924
            $this->debug('In nusoap_server, WSDL is specified');
3925
            if (is_object($wsdl) && (get_class($wsdl) === 'wsdl')) {
3926
                $this->wsdl            = $wsdl;
3927
                $this->externalWSDLURL = $this->wsdl->wsdl;
3928
                $this->debug('Use existing wsdl instance from ' . $this->externalWSDLURL);
3929
            } else {
3930
                $this->debug('Create wsdl from ' . $wsdl);
3931
                $this->wsdl            = new wsdl($wsdl);
3932
                $this->externalWSDLURL = $wsdl;
3933
            }
3934
            $this->appendDebug($this->wsdl->getDebug());
3935
            $this->wsdl->clearDebug();
3936
            if ($err = $this->wsdl->getError()) {
3937
                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...
3938
            }
3939
        }
3940
    }
3941
3942
    /**
3943
     * processes request and returns response
3944
     *
3945
     * @param string $data usually is the value of $HTTP_RAW_POST_DATA
3946
     * @access   public
3947
     */
3948
    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...
3949
    {
3950
        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...
3951
3952 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...
3953
            $rm = $_SERVER['REQUEST_METHOD'];
3954
        } elseif (isset($HTTP_SERVER_VARS['REQUEST_METHOD'])) {
3955
            $rm = $HTTP_SERVER_VARS['REQUEST_METHOD'];
3956
        } else {
3957
            $rm = '';
3958
        }
3959
3960 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...
3961
            $qs = $_SERVER['QUERY_STRING'];
3962
        } elseif (isset($HTTP_SERVER_VARS['QUERY_STRING'])) {
3963
            $qs = $HTTP_SERVER_VARS['QUERY_STRING'];
3964
        } else {
3965
            $qs = '';
3966
        }
3967
        $this->debug("In service, request method=$rm query string=$qs strlen(\$data)=" . strlen($data));
3968
3969
        if ($rm === 'POST') {
3970
            $this->debug('In service, invoke the request');
3971
            $this->parse_request($data);
3972
            if (!$this->fault) {
3973
                $this->invoke_method();
3974
            }
3975
            if (!$this->fault) {
3976
                $this->serialize_return();
3977
            }
3978
            $this->send_response();
3979
        } elseif (preg_match('/wsdl/', $qs)) {
3980
            $this->debug('In service, this is a request for WSDL');
3981
            if ($this->externalWSDLURL) {
3982
                if (strpos($this->externalWSDLURL, 'http://') !== false) { // assume URL
3983
                    $this->debug('In service, re-direct for WSDL');
3984
                    header('Location: ' . $this->externalWSDLURL);
3985
                } else { // assume file
3986
                    $this->debug('In service, use file passthru for WSDL');
3987
                    header("Content-Type: text/xml\r\n");
3988
                    $pos = strpos($this->externalWSDLURL, 'file://');
3989
                    if ($pos === false) {
3990
                        $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...
3991
                    } else {
3992
                        $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...
3993
                    }
3994
                    $fp = fopen($this->externalWSDLURL, 'r');
3995
                    fpassthru($fp);
3996
                }
3997
            } elseif ($this->wsdl) {
3998
                $this->debug('In service, serialize WSDL');
3999
                header("Content-Type: text/xml; charset=ISO-8859-1\r\n");
4000
                print $this->wsdl->serialize($this->debug_flag);
4001
                if ($this->debug_flag) {
4002
                    $this->debug('wsdl:');
4003
                    $this->appendDebug($this->varDump($this->wsdl));
4004
                    print $this->getDebugAsXMLComment();
4005
                }
4006
            } else {
4007
                $this->debug('In service, there is no WSDL');
4008
                header("Content-Type: text/html; charset=ISO-8859-1\r\n");
4009
                print 'This service does not provide WSDL';
4010
            }
4011
        } elseif ($this->wsdl) {
4012
            $this->debug('In service, return Web description');
4013
            print $this->wsdl->webDescription();
4014
        } else {
4015
            $this->debug('In service, no Web description');
4016
            header("Content-Type: text/html; charset=ISO-8859-1\r\n");
4017
            print 'This service does not provide a Web description';
4018
        }
4019
    }
4020
4021
    /**
4022
     * parses HTTP request headers.
4023
     *
4024
     * The following fields are set by this function (when successful)
4025
     *
4026
     * headers
4027
     * request
4028
     * xml_encoding
4029
     * SOAPAction
4030
     *
4031
     * @access   private
4032
     */
4033
    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...
4034
    {
4035
        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...
4036
4037
        $this->request    = '';
4038
        $this->SOAPAction = '';
4039
        if (function_exists('getallheaders')) {
4040
            $this->debug('In parse_http_headers, use getallheaders');
4041
            $headers = getallheaders();
4042
            foreach ($headers as $k => $v) {
4043
                $k                 = strtolower($k);
4044
                $this->headers[$k] = $v;
4045
                $this->request .= "$k: $v\r\n";
4046
                $this->debug("$k: $v");
4047
            }
4048
            // get SOAPAction header
4049
            if (isset($this->headers['soapaction'])) {
4050
                $this->SOAPAction = str_replace('"', '', $this->headers['soapaction']);
4051
            }
4052
            // get the character encoding of the incoming request
4053
            if (isset($this->headers['content-type']) && strpos($this->headers['content-type'], '=')) {
4054
                $enc = str_replace('"', '', substr(strstr($this->headers['content-type'], '='), 1));
4055
                if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4056
                    $this->xml_encoding = strtoupper($enc);
4057
                } else {
4058
                    $this->xml_encoding = 'US-ASCII';
4059
                }
4060
            } else {
4061
                // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4062
                $this->xml_encoding = 'ISO-8859-1';
4063
            }
4064
        } elseif (isset($_SERVER) && is_array($_SERVER)) {
4065
            $this->debug('In parse_http_headers, use _SERVER');
4066
            foreach ($_SERVER as $k => $v) {
4067
                if (substr($k, 0, 5) === 'HTTP_') {
4068
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
4069
                } else {
4070
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
4071
                }
4072 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...
4073
                    // get SOAPAction header
4074
                    $k                = 'SOAPAction';
4075
                    $v                = str_replace('"', '', $v);
4076
                    $v                = str_replace('\\', '', $v);
4077
                    $this->SOAPAction = $v;
4078
                } elseif ($k === 'content-type') {
4079
                    // get the character encoding of the incoming request
4080
                    if (strpos($v, '=')) {
4081
                        $enc = substr(strstr($v, '='), 1);
4082
                        $enc = str_replace('"', '', $enc);
4083
                        $enc = str_replace('\\', '', $enc);
4084
                        if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4085
                            $this->xml_encoding = strtoupper($enc);
4086
                        } else {
4087
                            $this->xml_encoding = 'US-ASCII';
4088
                        }
4089
                    } else {
4090
                        // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4091
                        $this->xml_encoding = 'ISO-8859-1';
4092
                    }
4093
                }
4094
                $this->headers[$k] = $v;
4095
                $this->request .= "$k: $v\r\n";
4096
                $this->debug("$k: $v");
4097
            }
4098
        } elseif (is_array($HTTP_SERVER_VARS)) {
4099
            $this->debug('In parse_http_headers, use HTTP_SERVER_VARS');
4100
            foreach ($HTTP_SERVER_VARS as $k => $v) {
4101
                if (substr($k, 0, 5) === 'HTTP_') {
4102
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', substr($k, 5))));
4103
                    $k = strtolower(substr($k, 5));
4104
                } else {
4105
                    $k = str_replace(' ', '-', strtolower(str_replace('_', ' ', $k)));
4106
                    $k = strtolower($k);
4107
                }
4108 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...
4109
                    // get SOAPAction header
4110
                    $k                = 'SOAPAction';
4111
                    $v                = str_replace('"', '', $v);
4112
                    $v                = str_replace('\\', '', $v);
4113
                    $this->SOAPAction = $v;
4114
                } elseif ($k === 'content-type') {
4115
                    // get the character encoding of the incoming request
4116
                    if (strpos($v, '=')) {
4117
                        $enc = substr(strstr($v, '='), 1);
4118
                        $enc = str_replace('"', '', $enc);
4119
                        $enc = str_replace('\\', '', $enc);
4120
                        if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4121
                            $this->xml_encoding = strtoupper($enc);
4122
                        } else {
4123
                            $this->xml_encoding = 'US-ASCII';
4124
                        }
4125
                    } else {
4126
                        // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4127
                        $this->xml_encoding = 'ISO-8859-1';
4128
                    }
4129
                }
4130
                $this->headers[$k] = $v;
4131
                $this->request .= "$k: $v\r\n";
4132
                $this->debug("$k: $v");
4133
            }
4134
        } else {
4135
            $this->debug('In parse_http_headers, HTTP headers not accessible');
4136
            $this->setError('HTTP headers not accessible');
4137
        }
4138
    }
4139
4140
    /**
4141
     * parses a request
4142
     *
4143
     * The following fields are set by this function (when successful)
4144
     *
4145
     * headers
4146
     * request
4147
     * xml_encoding
4148
     * SOAPAction
4149
     * request
4150
     * requestSOAP
4151
     * methodURI
4152
     * methodname
4153
     * methodparams
4154
     * requestHeaders
4155
     * document
4156
     *
4157
     * This sets the fault field on error
4158
     *
4159
     * @param string $data XML string
4160
     * @access   private
4161
     */
4162
    public function parse_request($data = '')
4163
    {
4164
        $this->debug('entering parse_request()');
4165
        $this->parse_http_headers();
4166
        $this->debug('got character encoding: ' . $this->xml_encoding);
4167
        // uncompress if necessary
4168
        if (isset($this->headers['content-encoding']) && $this->headers['content-encoding'] != '') {
4169
            $this->debug('got content encoding: ' . $this->headers['content-encoding']);
4170
            if ($this->headers['content-encoding'] === 'deflate' || $this->headers['content-encoding'] === 'gzip') {
4171
                // if decoding works, use it. else assume data wasn't gzencoded
4172
                if (function_exists('gzuncompress')) {
4173
                    if ($this->headers['content-encoding'] === 'deflate' && $degzdata = @gzuncompress($data)) {
4174
                        $data = $degzdata;
4175
                    } elseif ($this->headers['content-encoding'] === 'gzip'
4176
                              && $degzdata = gzinflate(substr($data, 10))
4177
                    ) {
4178
                        $data = $degzdata;
4179
                    } else {
4180
                        $this->fault('SOAP-ENV:Client', 'Errors occurred when trying to decode the data');
4181
4182
                        return;
4183
                    }
4184
                } else {
4185
                    $this->fault('SOAP-ENV:Client', 'This Server does not support compressed data');
4186
4187
                    return;
4188
                }
4189
            }
4190
        }
4191
        $this->request .= "\r\n" . $data;
4192
        $data              = $this->parseRequest($this->headers, $data);
4193
        $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...
4194
        $this->debug('leaving parse_request');
4195
    }
4196
4197
    /**
4198
     * invokes a PHP function for the requested SOAP method
4199
     *
4200
     * The following fields are set by this function (when successful)
4201
     *
4202
     * methodreturn
4203
     *
4204
     * Note that the PHP function that is called may also set the following
4205
     * fields to affect the response sent to the client
4206
     *
4207
     * responseHeaders
4208
     * outgoing_headers
4209
     *
4210
     * This sets the fault field on error
4211
     *
4212
     * @access   private
4213
     */
4214
    public function invoke_method()
4215
    {
4216
        $this->debug('in invoke_method, methodname=' . $this->methodname . ' methodURI=' . $this->methodURI . ' SOAPAction=' . $this->SOAPAction);
4217
4218
        //
4219
        // if you are debugging in this area of the code, your service uses a class to implement methods,
4220
        // you use SOAP RPC, and the client is .NET, please be aware of the following...
4221
        // when the .NET wsdl.exe utility generates a proxy, it will remove the '.' or '..' from the
4222
        // method name.  that is fine for naming the .NET methods.  it is not fine for properly constructing
4223
        // the XML request and reading the XML response.  you need to add the RequestElementName and
4224
        // ResponseElementName to the System.Web.Services.Protocols.SoapRpcMethodAttribute that wsdl.exe
4225
        // generates for the method.  these parameters are used to specify the correct XML element names
4226
        // for .NET to use, i.e. the names with the '.' in them.
4227
        //
4228
        $orig_methodname = $this->methodname;
4229
        if ($this->wsdl) {
4230
            if ($this->opData = $this->wsdl->getOperationData($this->methodname)) {
4231
                $this->debug('in invoke_method, found WSDL operation=' . $this->methodname);
4232
                $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...
4233
            } elseif ($this->opData = $this->wsdl->getOperationDataForSoapAction($this->SOAPAction)) {
4234
                // Note: hopefully this case will only be used for doc/lit, since rpc services should have wrapper element
4235
                $this->debug('in invoke_method, found WSDL soapAction=' . $this->SOAPAction . ' for operation=' . $this->opData['name']);
4236
                $this->appendDebug('opData=' . $this->varDump($this->opData));
4237
                $this->methodname = $this->opData['name'];
4238
            } else {
4239
                $this->debug('in invoke_method, no WSDL for operation=' . $this->methodname);
4240
                $this->fault('SOAP-ENV:Client', "Operation '" . $this->methodname . "' is not defined in the WSDL for this service");
4241
4242
                return;
4243
            }
4244
        } else {
4245
            $this->debug('in invoke_method, no WSDL to validate method');
4246
        }
4247
4248
        // if a . is present in $this->methodname, we see if there is a class in scope,
4249
        // which could be referred to. We will also distinguish between two deliminators,
4250
        // to allow methods to be called a the class or an instance
4251
        if (strpos($this->methodname, '..') > 0) {
4252
            $delim = '..';
4253
        } elseif (strpos($this->methodname, '.') > 0) {
4254
            $delim = '.';
4255
        } else {
4256
            $delim = '';
4257
        }
4258
        $this->debug("in invoke_method, delim=$delim");
4259
4260
        $class  = '';
4261
        $method = '';
4262
        if (strlen($delim) > 0 && substr_count($this->methodname, $delim) == 1) {
4263
            $try_class = substr($this->methodname, 0, strpos($this->methodname, $delim));
4264
            if (class_exists($try_class)) {
4265
                // get the class and method name
4266
                $class  = $try_class;
4267
                $method = substr($this->methodname, strpos($this->methodname, $delim) + strlen($delim));
4268
                $this->debug("in invoke_method, class=$class method=$method delim=$delim");
4269
            } else {
4270
                $this->debug("in invoke_method, class=$try_class not found");
4271
            }
4272
        } else {
4273
            $try_class = '';
4274
            $this->debug('in invoke_method, no class to try');
4275
        }
4276
4277
        // does method exist?
4278
        if ($class == '') {
4279
            if (!function_exists($this->methodname)) {
4280
                $this->debug("in invoke_method, function '$this->methodname' not found!");
4281
                $this->result = 'fault: method not found';
4282
                $this->fault('SOAP-ENV:Client', "method '$this->methodname'('$orig_methodname') not defined in service('$try_class' '$delim')");
4283
4284
                return;
4285
            }
4286
        } else {
4287
            $method_to_compare = (substr(phpversion(), 0, 2) === '4.') ? strtolower($method) : $method;
4288
            if (!in_array($method_to_compare, get_class_methods($class))) {
4289
                $this->debug("in invoke_method, method '$this->methodname' not found in class '$class'!");
4290
                $this->result = 'fault: method not found';
4291
                $this->fault('SOAP-ENV:Client', "method '$this->methodname'/'$method_to_compare'('$orig_methodname') not defined in service/'$class'('$try_class' '$delim')");
4292
4293
                return;
4294
            }
4295
        }
4296
4297
        // evaluate message, getting back parameters
4298
        // verify that request parameters match the method's signature
4299
        if (!$this->verify_method($this->methodname, $this->methodparams)) {
4300
            // debug
4301
            $this->debug('ERROR: request not verified against method signature');
4302
            $this->result = 'fault: request failed validation against method signature';
4303
            // return fault
4304
            $this->fault('SOAP-ENV:Client', "Operation '$this->methodname' not defined in service.");
4305
4306
            return;
4307
        }
4308
4309
        // if there are parameters to pass
4310
        $this->debug('in invoke_method, params:');
4311
        $this->appendDebug($this->varDump($this->methodparams));
4312
        $this->debug("in invoke_method, calling '$this->methodname'");
4313
        if (!function_exists('call_user_func_array')) {
4314
            if ($class == '') {
4315
                $this->debug('in invoke_method, calling function using eval()');
4316
                $funcCall = "\$this->methodreturn = $this->methodname(";
4317
            } else {
4318
                if ($delim === '..') {
4319
                    $this->debug('in invoke_method, calling class method using eval()');
4320
                    $funcCall = "\$this->methodreturn = " . $class . '::' . $method . '(';
4321
                } else {
4322
                    $this->debug('in invoke_method, calling instance method using eval()');
4323
                    // generate unique instance name
4324
                    $instname = "\$inst_" . time();
4325
                    $funcCall = $instname . ' = new ' . $class . '(); ';
4326
                    $funcCall .= "\$this->methodreturn = " . $instname . '->' . $method . '(';
4327
                }
4328
            }
4329
            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...
4330
                foreach ($this->methodparams as $param) {
4331
                    if (is_array($param) || is_object($param)) {
4332
                        $this->fault('SOAP-ENV:Client', 'NuSOAP does not handle complexType parameters correctly when using eval; call_user_func_array must be available');
4333
4334
                        return;
4335
                    }
4336
                    $funcCall .= "\"$param\",";
4337
                }
4338
                $funcCall = substr($funcCall, 0, -1);
4339
            }
4340
            $funcCall .= ');';
4341
            $this->debug('in invoke_method, function call: ' . $funcCall);
4342
            @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...
4343
        } else {
4344
            if ($class == '') {
4345
                $this->debug('in invoke_method, calling function using call_user_func_array()');
4346
                $call_arg = "$this->methodname";    // straight assignment changes $this->methodname to lower case after call_user_func_array()
4347
            } elseif ($delim === '..') {
4348
                $this->debug('in invoke_method, calling class method using call_user_func_array()');
4349
                $call_arg = array($class, $method);
4350
            } else {
4351
                $this->debug('in invoke_method, calling instance method using call_user_func_array()');
4352
                $instance = new $class ();
4353
                $call_arg = array(&$instance, $method);
4354
            }
4355
            if (is_array($this->methodparams)) {
4356
                $this->methodreturn = call_user_func_array($call_arg, array_values($this->methodparams));
4357
            } else {
4358
                $this->methodreturn = call_user_func_array($call_arg, array());
4359
            }
4360
        }
4361
        $this->debug('in invoke_method, methodreturn:');
4362
        $this->appendDebug($this->varDump($this->methodreturn));
4363
        $this->debug("in invoke_method, called method $this->methodname, received data of type " . gettype($this->methodreturn));
4364
    }
4365
4366
    /**
4367
     * serializes the return value from a PHP function into a full SOAP Envelope
4368
     *
4369
     * The following fields are set by this function (when successful)
4370
     *
4371
     * responseSOAP
4372
     *
4373
     * This sets the fault field on error
4374
     *
4375
     * @access   private
4376
     */
4377
    public function serialize_return()
4378
    {
4379
        $this->debug('Entering serialize_return methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4380
        // if fault
4381
        if (isset($this->methodreturn) && is_object($this->methodreturn)
4382
            && ((get_class($this->methodreturn) === 'soap_fault')
4383
                || (get_class($this->methodreturn) === 'nusoap_fault'))
4384
        ) {
4385
            $this->debug('got a fault object from method');
4386
            $this->fault = $this->methodreturn;
4387
4388
            return;
4389
        } elseif ($this->methodreturnisliteralxml) {
4390
            $return_val = $this->methodreturn;
4391
            // returned value(s)
4392
        } else {
4393
            $this->debug('got a(n) ' . gettype($this->methodreturn) . ' from method');
4394
            $this->debug('serializing return value');
4395
            if ($this->wsdl) {
4396
                if (count($this->opData['output']['parts']) > 1) {
4397
                    $this->debug('more than one output part, so use the method return unchanged');
4398
                    $opParams = $this->methodreturn;
4399
                } elseif (count($this->opData['output']['parts']) == 1) {
4400
                    $this->debug('exactly one output part, so wrap the method return in a simple array');
4401
                    // TODO: verify that it is not already wrapped!
4402
                    //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...
4403
                    //  $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...
4404
                    //}
4405
                    $opParams = array($this->methodreturn);
4406
                }
4407
                $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...
4408
                $this->appendDebug($this->wsdl->getDebug());
4409
                $this->wsdl->clearDebug();
4410
                if ($errstr = $this->wsdl->getError()) {
4411
                    $this->debug('got wsdl error: ' . $errstr);
4412
                    $this->fault('SOAP-ENV:Server', 'unable to serialize result');
4413
4414
                    return;
4415
                }
4416
            } else {
4417
                if (isset($this->methodreturn)) {
4418
                    $return_val = $this->serialize_val($this->methodreturn, 'return');
4419
                } else {
4420
                    $return_val = '';
4421
                    $this->debug('in absence of WSDL, assume void return for backward compatibility');
4422
                }
4423
            }
4424
        }
4425
        $this->debug('return value:');
4426
        $this->appendDebug($this->varDump($return_val));
4427
4428
        $this->debug('serializing response');
4429
        if ($this->wsdl) {
4430
            $this->debug('have WSDL for serialization: style is ' . $this->opData['style']);
4431
            if ($this->opData['style'] === 'rpc') {
4432
                $this->debug('style is rpc for serialization: use is ' . $this->opData['output']['use']);
4433
                if ($this->opData['output']['use'] === 'literal') {
4434
                    // 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
4435 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...
4436
                        $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4437
                    } else {
4438
                        $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4439
                    }
4440 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...
4441
                    if ($this->methodURI) {
4442
                        $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4443
                    } else {
4444
                        $payload = '<' . $this->methodname . 'Response>' . $return_val . '</' . $this->methodname . 'Response>';
4445
                    }
4446
                }
4447
            } else {
4448
                $this->debug('style is not rpc for serialization: assume document');
4449
                $payload = $return_val;
4450
            }
4451
        } else {
4452
            $this->debug('do not have WSDL for serialization: assume rpc/encoded');
4453
            $payload = '<ns1:' . $this->methodname . 'Response xmlns:ns1="' . $this->methodURI . '">' . $return_val . '</ns1:' . $this->methodname . 'Response>';
4454
        }
4455
        $this->result = 'successful';
4456
        if ($this->wsdl) {
4457
            //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...
4458
            $this->appendDebug($this->wsdl->getDebug());
4459
            //  }
4460
            if (isset($this->opData['output']['encodingStyle'])) {
4461
                $encodingStyle = $this->opData['output']['encodingStyle'];
4462
            } else {
4463
                $encodingStyle = '';
4464
            }
4465
            // Added: In case we use a WSDL, return a serialized env. WITH the usedNamespaces.
4466
            $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders, $this->wsdl->usedNamespaces, $this->opData['style'], $this->opData['output']['use'], $encodingStyle);
4467
        } else {
4468
            $this->responseSOAP = $this->serializeEnvelope($payload, $this->responseHeaders);
4469
        }
4470
        $this->debug('Leaving serialize_return');
4471
    }
4472
4473
    /**
4474
     * sends an HTTP response
4475
     *
4476
     * The following fields are set by this function (when successful)
4477
     *
4478
     * outgoing_headers
4479
     * response
4480
     *
4481
     * @access   private
4482
     */
4483
    public function send_response()
4484
    {
4485
        $this->debug('Enter send_response');
4486
        if ($this->fault) {
4487
            $payload                  = $this->fault->serialize();
4488
            $this->outgoing_headers[] = 'HTTP/1.0 500 Internal Server Error';
4489
            $this->outgoing_headers[] = 'Status: 500 Internal Server Error';
4490
        } else {
4491
            $payload = $this->responseSOAP;
4492
            // Some combinations of PHP+Web server allow the Status
4493
            // to come through as a header.  Since OK is the default
4494
            // just do nothing.
4495
            // $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...
4496
            // $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...
4497
        }
4498
        // add debug data if in debug mode
4499
        if (isset($this->debug_flag) && $this->debug_flag) {
4500
            $payload .= $this->getDebugAsXMLComment();
4501
        }
4502
        $this->outgoing_headers[] = "Server: $this->title Server v$this->version";
4503
        preg_match('/\$Revisio' . 'n: ([^ ]+)/', $this->revision, $rev);
4504
        $this->outgoing_headers[] = "X-SOAP-Server: $this->title/$this->version (" . $rev[1] . ')';
4505
        // Let the Web server decide about this
4506
        //$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...
4507
        $payload                  = $this->getHTTPBody($payload);
4508
        $type                     = $this->getHTTPContentType();
4509
        $charset                  = $this->getHTTPContentTypeCharset();
4510
        $this->outgoing_headers[] = "Content-Type: $type" . ($charset ? '; charset=' . $charset : '');
4511
        //begin code to compress payload - by John
4512
        // NOTE: there is no way to know whether the Web server will also compress
4513
        // this data.
4514
        if (strlen($payload) > 1024 && isset($this->headers) && isset($this->headers['accept-encoding'])) {
4515
            if (false !== strpos($this->headers['accept-encoding'], 'gzip')) {
4516 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...
4517
                    if (isset($this->debug_flag) && $this->debug_flag) {
4518
                        $payload .= '<!-- Content being gzipped -->';
4519
                    }
4520
                    $this->outgoing_headers[] = 'Content-Encoding: gzip';
4521
                    $payload                  = gzencode($payload);
4522
                } else {
4523
                    if (isset($this->debug_flag) && $this->debug_flag) {
4524
                        $payload .= '<!-- Content will not be gzipped: no gzencode -->';
4525
                    }
4526
                }
4527
            } elseif (false !== strpos($this->headers['accept-encoding'], 'deflate')) {
4528
                // Note: MSIE requires gzdeflate output (no Zlib header and checksum),
4529
                // instead of gzcompress output,
4530
                // which conflicts with HTTP 1.1 spec (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.5)
4531 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...
4532
                    if (isset($this->debug_flag) && $this->debug_flag) {
4533
                        $payload .= '<!-- Content being deflated -->';
4534
                    }
4535
                    $this->outgoing_headers[] = 'Content-Encoding: deflate';
4536
                    $payload                  = gzdeflate($payload);
4537
                } else {
4538
                    if (isset($this->debug_flag) && $this->debug_flag) {
4539
                        $payload .= '<!-- Content will not be deflated: no gzcompress -->';
4540
                    }
4541
                }
4542
            }
4543
        }
4544
        //end code
4545
        $this->outgoing_headers[] = 'Content-Length: ' . strlen($payload);
4546
        reset($this->outgoing_headers);
4547
        foreach ($this->outgoing_headers as $hdr) {
4548
            header($hdr, false);
4549
        }
4550
        print $payload;
4551
        $this->response = implode("\r\n", $this->outgoing_headers) . "\r\n\r\n" . $payload;
4552
    }
4553
4554
    /**
4555
     * takes the value that was created by parsing the request
4556
     * and compares to the method's signature, if available.
4557
     *
4558
     * @param  string $operation The operation to be invoked
4559
     * @param  array  $request   The array of parameter values
4560
     * @return boolean Whether the operation was found
4561
     * @access   private
4562
     */
4563
    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...
4564
    {
4565
        if (isset($this->wsdl) && is_object($this->wsdl)) {
4566
            if ($this->wsdl->getOperationData($operation)) {
4567
                return true;
4568
            }
4569
        } elseif (isset($this->operations[$operation])) {
4570
            return true;
4571
        }
4572
4573
        return false;
4574
    }
4575
4576
    /**
4577
     * processes SOAP message received from client
4578
     *
4579
     * @param  array  $headers The HTTP headers
4580
     * @param  string $data    unprocessed request data from client
4581
     * @return mixed  value of the message, decoded into a PHP type
4582
     * @access   private
4583
     */
4584
    public function parseRequest($headers, $data)
4585
    {
4586
        $this->debug('Entering parseRequest() for data of length ' . strlen($data) . ' headers:');
4587
        $this->appendDebug($this->varDump($headers));
4588
        if (!isset($headers['content-type'])) {
4589
            $this->setError('Request not of type text/xml (no content-type header)');
4590
4591
            return false;
4592
        }
4593 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...
4594
            $this->setError('Request not of type text/xml');
4595
4596
            return false;
4597
        }
4598 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...
4599
            $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
4600
            $this->debug('Got response encoding: ' . $enc);
4601
            if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
4602
                $this->xml_encoding = strtoupper($enc);
4603
            } else {
4604
                $this->xml_encoding = 'US-ASCII';
4605
            }
4606
        } else {
4607
            // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
4608
            $this->xml_encoding = 'ISO-8859-1';
4609
        }
4610
        $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
4611
        // parse response, get soap parser obj
4612
        $parser = new nusoap_parser($data, $this->xml_encoding, '', $this->decode_utf8);
4613
        // parser debug
4614
        $this->debug("parser debug: \n" . $parser->getDebug());
4615
        // if fault occurred during message parsing
4616
        if ($err = $parser->getError()) {
4617
            $this->result = 'fault: error in msg parsing: ' . $err;
4618
            $this->fault('SOAP-ENV:Client', "error in msg parsing:\n" . $err);
4619
            // else successfully parsed request into soapval object
4620
        } else {
4621
            // get/set methodname
4622
            $this->methodURI  = $parser->root_struct_namespace;
4623
            $this->methodname = $parser->root_struct_name;
4624
            $this->debug('methodname: ' . $this->methodname . ' methodURI: ' . $this->methodURI);
4625
            $this->debug('calling parser->get_soapbody()');
4626
            $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...
4627
            // get SOAP headers
4628
            $this->requestHeaders = $parser->getHeaders();
4629
            // get SOAP Header
4630
            $this->requestHeader = $parser->get_soapheader();
4631
            // add document for doclit support
4632
            $this->document = $parser->document;
4633
        }
4634
    }
4635
4636
    /**
4637
     * gets the HTTP body for the current response.
4638
     *
4639
     * @param  string $soapmsg The SOAP payload
4640
     * @return string The HTTP body, which includes the SOAP payload
4641
     * @access private
4642
     */
4643
    public function getHTTPBody($soapmsg)
4644
    {
4645
        return $soapmsg;
4646
    }
4647
4648
    /**
4649
     * gets the HTTP content type for the current response.
4650
     *
4651
     * Note: getHTTPBody must be called before this.
4652
     *
4653
     * @return string the HTTP content type for the current response.
4654
     * @access private
4655
     */
4656
    public function getHTTPContentType()
4657
    {
4658
        return 'text/xml';
4659
    }
4660
4661
    /**
4662
     * gets the HTTP content type charset for the current response.
4663
     * returns false for non-text content types.
4664
     *
4665
     * Note: getHTTPBody must be called before this.
4666
     *
4667
     * @return string the HTTP content type charset for the current response.
4668
     * @access private
4669
     */
4670
    public function getHTTPContentTypeCharset()
4671
    {
4672
        return $this->soap_defencoding;
4673
    }
4674
4675
    /**
4676
     * add a method to the dispatch map (this has been replaced by the register method)
4677
     *
4678
     * @param string $methodname
4679
     * @param string $in  array of input values
4680
     * @param string $out array of output values
4681
     * @access   public
4682
     * @deprecated
4683
     */
4684
    public function add_to_map($methodname, $in, $out)
4685
    {
4686
        $this->operations[$methodname] = array('name' => $methodname, 'in' => $in, 'out' => $out);
4687
    }
4688
4689
    /**
4690
     * register a service function with the server
4691
     *
4692
     * @param string $name          the name of the PHP function, class.method or class..method
4693
     * @param array  $in            assoc array of input values: key = param name, value = param type
4694
     * @param array  $out           assoc array of output values: key = param name, value = param type
4695
     * @param mixed  $namespace     the element namespace for the method or false
4696
     * @param mixed  $soapaction    the soapaction for the method or false
4697
     * @param mixed  $style         optional (rpc|document) or false Note: when 'document' is specified, parameter and return wrappers are created for you automatically
4698
     * @param mixed  $use           optional (encoded|literal) or false
4699
     * @param string $documentation optional Description to include in WSDL
4700
     * @param string $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
4701
     * @access   public
4702
     * @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...
4703
     */
4704
    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...
4705
        $name,
4706
        $in = array(),
4707
        $out = array(),
4708
        $namespace = false,
4709
        $soapaction = false,
4710
        $style = false,
4711
        $use = false,
4712
        $documentation = '',
4713
        $encodingStyle = ''
4714
    ) {
4715
        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...
4716
4717
        if ($this->externalWSDLURL) {
4718
            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...
4719
        }
4720
        if (!$name) {
4721
            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...
4722
        }
4723
        if (!is_array($in)) {
4724
            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...
4725
        }
4726
        if (!is_array($out)) {
4727
            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...
4728
        }
4729
        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...
4730
        }
4731
        if (false == $soapaction) {
4732
            if (isset($_SERVER)) {
4733
                $SERVER_NAME = $_SERVER['SERVER_NAME'];
4734
                $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4735
                $HTTPS       = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4736 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...
4737
                $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4738
                $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4739
                $HTTPS       = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4740
            } else {
4741
                $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4742
            }
4743
            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...
4744
                $SCHEME = 'https';
4745
            } else {
4746
                $SCHEME = 'http';
4747
            }
4748
            $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...
4749
        }
4750
        if (false == $style) {
4751
            $style = 'rpc';
4752
        }
4753
        if (false == $use) {
4754
            $use = 'encoded';
4755
        }
4756
        if ($use === 'encoded' && $encodingStyle == '') {
4757
            $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
4758
        }
4759
4760
        $this->operations[$name] = array(
4761
            'name'       => $name,
4762
            'in'         => $in,
4763
            'out'        => $out,
4764
            'namespace'  => $namespace,
4765
            'soapaction' => $soapaction,
4766
            'style'      => $style
4767
        );
4768
        if ($this->wsdl) {
4769
            $this->wsdl->addOperation($name, $in, $out, $namespace, $soapaction, $style, $use, $documentation, $encodingStyle);
4770
        }
4771
4772
        return true;
4773
    }
4774
4775
    /**
4776
     * Specify a fault to be returned to the client.
4777
     * This also acts as a flag to the server that a fault has occured.
4778
     *
4779
     * @param string $faultcode
4780
     * @param string $faultstring
4781
     * @param string $faultactor
4782
     * @param string $faultdetail
4783
     * @access   public
4784
     */
4785
    public function fault($faultcode, $faultstring, $faultactor = '', $faultdetail = '')
4786
    {
4787
        if ($faultdetail == '' && $this->debug_flag) {
4788
            $faultdetail = $this->getDebug();
4789
        }
4790
        $this->fault                   = new nusoap_fault($faultcode, $faultactor, $faultstring, $faultdetail);
4791
        $this->fault->soap_defencoding = $this->soap_defencoding;
4792
    }
4793
4794
    /**
4795
     * Sets up wsdl object.
4796
     * Acts as a flag to enable internal WSDL generation
4797
     *
4798
     * @param string $serviceName           , name of the service
4799
     * @param mixed  $namespace             optional 'tns' service namespace or false
4800
     * @param mixed  $endpoint              optional URL of service endpoint or false
4801
     * @param string $style                 optional (rpc|document) WSDL style (also specified by operation)
4802
     * @param string $transport             optional SOAP transport
4803
     * @param mixed  $schemaTargetNamespace optional 'types' targetNamespace for service schema or false
4804
     */
4805
    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...
4806
        $serviceName,
4807
        $namespace = false,
4808
        $endpoint = false,
4809
        $style = 'rpc',
4810
        $transport = 'http://schemas.xmlsoap.org/soap/http',
4811
        $schemaTargetNamespace = false
4812
    ) {
4813
        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...
4814
4815
        if (isset($_SERVER)) {
4816
            $SERVER_NAME = $_SERVER['SERVER_NAME'];
4817
            $SERVER_PORT = $_SERVER['SERVER_PORT'];
4818
            $SCRIPT_NAME = isset($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME'];
4819
            $HTTPS       = isset($_SERVER['HTTPS']) ? $_SERVER['HTTPS'] : (isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off');
4820 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...
4821
            $SERVER_NAME = $HTTP_SERVER_VARS['SERVER_NAME'];
4822
            $SERVER_PORT = $HTTP_SERVER_VARS['SERVER_PORT'];
4823
            $SCRIPT_NAME = isset($HTTP_SERVER_VARS['PHP_SELF']) ? $HTTP_SERVER_VARS['PHP_SELF'] : $HTTP_SERVER_VARS['SCRIPT_NAME'];
4824
            $HTTPS       = isset($HTTP_SERVER_VARS['HTTPS']) ? $HTTP_SERVER_VARS['HTTPS'] : 'off';
4825
        } else {
4826
            $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
4827
        }
4828
        // If server name has port number attached then strip it (else port number gets duplicated in WSDL output) (occurred using lighttpd and FastCGI)
4829
        $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...
4830
        if ($colon) {
4831
            $SERVER_NAME = substr($SERVER_NAME, 0, $colon);
4832
        }
4833
        if ($SERVER_PORT == 80) {
4834
            $SERVER_PORT = '';
4835
        } else {
4836
            $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...
4837
        }
4838
        if (false == $namespace) {
4839
            $namespace = "http://$SERVER_NAME/soap/$serviceName";
4840
        }
4841
4842
        if (false == $endpoint) {
4843
            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...
4844
                $SCHEME = 'https';
4845
            } else {
4846
                $SCHEME = 'http';
4847
            }
4848
            $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...
4849
        }
4850
4851
        if (false == $schemaTargetNamespace) {
4852
            $schemaTargetNamespace = $namespace;
4853
        }
4854
4855
        $this->wsdl                     = new wsdl;
4856
        $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...
4857
        $this->wsdl->endpoint           = $endpoint;
4858
        $this->wsdl->namespaces['tns']  = $namespace;
4859
        $this->wsdl->namespaces['soap'] = 'http://schemas.xmlsoap.org/wsdl/soap/';
4860
        $this->wsdl->namespaces['wsdl'] = 'http://schemas.xmlsoap.org/wsdl/';
4861
        if ($schemaTargetNamespace != $namespace) {
4862
            $this->wsdl->namespaces['types'] = $schemaTargetNamespace;
4863
        }
4864
        $this->wsdl->schemas[$schemaTargetNamespace][0] = new nusoap_xmlschema('', '', $this->wsdl->namespaces);
4865
        if ($style === 'document') {
4866
            $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaInfo['elementFormDefault'] = 'qualified';
4867
        }
4868
        $this->wsdl->schemas[$schemaTargetNamespace][0]->schemaTargetNamespace                                   = $schemaTargetNamespace;
4869
        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/soap/encoding/'][0] = array(
4870
            'location' => '',
4871
            'loaded'   => true
4872
        );
4873
        $this->wsdl->schemas[$schemaTargetNamespace][0]->imports['http://schemas.xmlsoap.org/wsdl/'][0]          = array(
4874
            'location' => '',
4875
            'loaded'   => true
4876
        );
4877
        $this->wsdl->bindings[$serviceName . 'Binding']                                                          = array(
4878
            'name'      => $serviceName . 'Binding',
4879
            'style'     => $style,
4880
            'transport' => $transport,
4881
            'portType'  => $serviceName . 'PortType'
4882
        );
4883
        $this->wsdl->ports[$serviceName . 'Port']                                                                = array(
4884
            'binding'     => $serviceName . 'Binding',
4885
            'location'    => $endpoint,
4886
            'bindingType' => 'http://schemas.xmlsoap.org/wsdl/soap/'
4887
        );
4888
    }
4889
}
4890
4891
/**
4892
 * Backward compatibility
4893
 */
4894
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...
4895
{
4896
}
4897
4898
?><?php
4899
4900
/**
4901
 * parses a WSDL file, allows access to it's data, other utility methods.
4902
 * also builds WSDL structures programmatically.
4903
 *
4904
 * @author   Dietrich Ayala <[email protected]>
4905
 * @author   Scott Nichol <[email protected]>
4906
 * @access   public
4907
 */
4908
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...
4909
{
4910
    // URL or filename of the root of this WSDL
4911
    public $wsdl;
4912
    // define internal arrays of bindings, ports, operations, messages, etc.
4913
    public $schemas       = array();
4914
    public $currentSchema;
4915
    public $message       = array();
4916
    public $complexTypes  = array();
4917
    public $messages      = array();
4918
    public $currentMessage;
4919
    public $currentOperation;
4920
    public $portTypes     = array();
4921
    public $currentPortType;
4922
    public $bindings      = array();
4923
    public $currentBinding;
4924
    public $ports         = array();
4925
    public $currentPort;
4926
    public $opData        = array();
4927
    public $status        = '';
4928
    public $documentation = false;
4929
    public $endpoint      = '';
4930
    // array of wsdl docs to import
4931
    public $import = array();
4932
    // parser vars
4933
    public $parser;
4934
    public $position    = 0;
4935
    public $depth       = 0;
4936
    public $depth_array = array();
4937
    // for getting wsdl
4938
    public $proxyhost        = '';
4939
    public $proxyport        = '';
4940
    public $proxyusername    = '';
4941
    public $proxypassword    = '';
4942
    public $timeout          = 0;
4943
    public $response_timeout = 30;
4944
    public $curl_options     = array();    // User-specified cURL options
4945
    public $use_curl         = false;            // whether to always try to use cURL
4946
    // for HTTP authentication
4947
    public $username    = '';                // Username for HTTP authentication
4948
    public $password    = '';                // Password for HTTP authentication
4949
    public $authtype    = '';                // Type of HTTP authentication
4950
    public $certRequest = array();        // Certificate for HTTP SSL authentication
4951
4952
    /**
4953
     * constructor
4954
     *
4955
     * @param string      $wsdl             WSDL document URL
4956
     * @param bool|string $proxyhost
4957
     * @param bool|string $proxyport
4958
     * @param bool|string $proxyusername
4959
     * @param bool|string $proxypassword
4960
     * @param integer     $timeout          set the connection timeout
4961
     * @param integer     $response_timeout set the response timeout
4962
     * @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...
4963
     * @param boolean     $use_curl         try to use cURL
4964
     * @access public
4965
     * @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...
4966
     */
4967
    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...
4968
        $wsdl = '',
4969
        $proxyhost = false,
4970
        $proxyport = false,
4971
        $proxyusername = false,
4972
        $proxypassword = false,
4973
        $timeout = 0,
4974
        $response_timeout = 30,
4975
        $curl_options = null,
4976
        $use_curl = false
4977
    ) {
4978
        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...
4979
        $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
4980
        $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...
4981
        $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...
4982
        $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...
4983
        $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...
4984
        $this->timeout          = $timeout;
4985
        $this->response_timeout = $response_timeout;
4986
        if (is_array($curl_options)) {
4987
            $this->curl_options = $curl_options;
4988
        }
4989
        $this->use_curl = $use_curl;
4990
        $this->fetchWSDL($wsdl);
4991
    }
4992
4993
    /**
4994
     * fetches the WSDL document and parses it
4995
     *
4996
     * @access public
4997
     * @param $wsdl
4998
     */
4999
    public function fetchWSDL($wsdl)
5000
    {
5001
        $this->debug("parse and process WSDL path=$wsdl");
5002
        $this->wsdl = $wsdl;
5003
        // parse wsdl file
5004
        if ($this->wsdl != '') {
5005
            $this->parseWSDL($this->wsdl);
5006
        }
5007
        // imports
5008
        // TODO: handle imports more properly, grabbing them in-line and nesting them
5009
        $imported_urls = array();
5010
        $imported      = 1;
5011
        while ($imported > 0) {
5012
            $imported = 0;
5013
            // Schema imports
5014
            foreach ($this->schemas as $ns => $list) {
5015
                foreach ($list as $xs) {
5016
                    $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
5017 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...
5018
                        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...
5019
                            if (!$list2[$ii]['loaded']) {
5020
                                $this->schemas[$ns]->imports[$ns2][$ii]['loaded'] = true;
5021
                                $url                                              = $list2[$ii]['location'];
5022
                                if ($url != '') {
5023
                                    $urlparts = parse_url($url);
5024
                                    if (!isset($urlparts['host'])) {
5025
                                        $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
5026
                                    }
5027
                                    if (!in_array($url, $imported_urls)) {
5028
                                        $this->parseWSDL($url);
5029
                                        ++$imported;
5030
                                        $imported_urls[] = $url;
5031
                                    }
5032
                                } else {
5033
                                    $this->debug('Unexpected scenario: empty URL for unloaded import');
5034
                                }
5035
                            }
5036
                        }
5037
                    }
5038
                }
5039
            }
5040
            // WSDL imports
5041
            $wsdlparts = parse_url($this->wsdl);    // this is bogusly simple!
5042 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...
5043
                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...
5044
                    if (!$list[$ii]['loaded']) {
5045
                        $this->import[$ns][$ii]['loaded'] = true;
5046
                        $url                              = $list[$ii]['location'];
5047
                        if ($url != '') {
5048
                            $urlparts = parse_url($url);
5049
                            if (!isset($urlparts['host'])) {
5050
                                $url = $wsdlparts['scheme'] . '://' . $wsdlparts['host'] . (isset($wsdlparts['port']) ? ':' . $wsdlparts['port'] : '') . substr($wsdlparts['path'], 0, strrpos($wsdlparts['path'], '/') + 1) . $urlparts['path'];
5051
                            }
5052
                            if (!in_array($url, $imported_urls)) {
5053
                                $this->parseWSDL($url);
5054
                                ++$imported;
5055
                                $imported_urls[] = $url;
5056
                            }
5057
                        } else {
5058
                            $this->debug('Unexpected scenario: empty URL for unloaded import');
5059
                        }
5060
                    }
5061
                }
5062
            }
5063
        }
5064
        // add new data to operation data
5065
        foreach ($this->bindings as $binding => $bindingData) {
5066
            if (isset($bindingData['operations']) && is_array($bindingData['operations'])) {
5067
                foreach ($bindingData['operations'] as $operation => $data) {
5068
                    $this->debug('post-parse data gathering for ' . $operation);
5069
                    $this->bindings[$binding]['operations'][$operation]['input']  = isset($this->bindings[$binding]['operations'][$operation]['input']) ? array_merge($this->bindings[$binding]['operations'][$operation]['input'],
5070
                                                                                                                                                                      $this->portTypes[$bindingData['portType']][$operation]['input']) : $this->portTypes[$bindingData['portType']][$operation]['input'];
5071
                    $this->bindings[$binding]['operations'][$operation]['output'] = isset($this->bindings[$binding]['operations'][$operation]['output']) ? array_merge($this->bindings[$binding]['operations'][$operation]['output'],
5072
                                                                                                                                                                       $this->portTypes[$bindingData['portType']][$operation]['output']) : $this->portTypes[$bindingData['portType']][$operation]['output'];
5073 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...
5074
                        $this->bindings[$binding]['operations'][$operation]['input']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['input']['message']];
5075
                    }
5076 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...
5077
                        $this->bindings[$binding]['operations'][$operation]['output']['parts'] = $this->messages[$this->bindings[$binding]['operations'][$operation]['output']['message']];
5078
                    }
5079
                    // Set operation style if necessary, but do not override one already provided
5080
                    if (isset($bindingData['style'])
5081
                        && !isset($this->bindings[$binding]['operations'][$operation]['style'])
5082
                    ) {
5083
                        $this->bindings[$binding]['operations'][$operation]['style'] = $bindingData['style'];
5084
                    }
5085
                    $this->bindings[$binding]['operations'][$operation]['transport']     = isset($bindingData['transport']) ? $bindingData['transport'] : '';
5086
                    $this->bindings[$binding]['operations'][$operation]['documentation'] = isset($this->portTypes[$bindingData['portType']][$operation]['documentation']) ? $this->portTypes[$bindingData['portType']][$operation]['documentation'] : '';
5087
                    $this->bindings[$binding]['operations'][$operation]['endpoint']      = isset($bindingData['endpoint']) ? $bindingData['endpoint'] : '';
5088
                }
5089
            }
5090
        }
5091
    }
5092
5093
    /**
5094
     * parses the wsdl document
5095
     *
5096
     * @param string $wsdl path or URL
5097
     * @access private
5098
     * @return bool
5099
     */
5100
    public function parseWSDL($wsdl = '')
5101
    {
5102
        $this->debug("parse WSDL at path=$wsdl");
5103
5104
        if ($wsdl == '') {
5105
            $this->debug('no wsdl passed to parseWSDL()!!');
5106
            $this->setError('no wsdl passed to parseWSDL()!!');
5107
5108
            return false;
5109
        }
5110
5111
        // parse $wsdl for url format
5112
        $wsdl_props = parse_url($wsdl);
5113
5114
        if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] === 'http' || $wsdl_props['scheme'] === 'https')) {
5115
            $this->debug('getting WSDL http(s) URL ' . $wsdl);
5116
            // get wsdl
5117
            $tr                 = new soap_transport_http($wsdl, $this->curl_options, $this->use_curl);
5118
            $tr->request_method = 'GET';
5119
            $tr->useSOAPAction  = false;
5120 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...
5121
                $tr->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
5122
            }
5123
            if ($this->authtype != '') {
5124
                $tr->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
5125
            }
5126
            $tr->setEncoding('gzip, deflate');
5127
            $wsdl_string = $tr->send('', $this->timeout, $this->response_timeout);
5128
            //$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...
5129
            //$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...
5130
            $this->appendDebug($tr->getDebug());
5131
            // catch errors
5132
            if ($err = $tr->getError()) {
5133
                $errstr = 'Getting ' . $wsdl . ' - HTTP ERROR: ' . $err;
5134
                $this->debug($errstr);
5135
                $this->setError($errstr);
5136
                unset($tr);
5137
5138
                return false;
5139
            }
5140
            unset($tr);
5141
            $this->debug('got WSDL URL');
5142
        } else {
5143
            // $wsdl is not http(s), so treat it as a file URL or plain file path
5144
            if (isset($wsdl_props['scheme']) && ($wsdl_props['scheme'] === 'file') && isset($wsdl_props['path'])) {
5145
                $path = isset($wsdl_props['host']) ? ($wsdl_props['host'] . ':' . $wsdl_props['path']) : $wsdl_props['path'];
5146
            } else {
5147
                $path = $wsdl;
5148
            }
5149
            $this->debug('getting WSDL file ' . $path);
5150
            if ($fp = @fopen($path, 'r')) {
5151
                $wsdl_string = '';
5152
                while ($data = fread($fp, 32768)) {
5153
                    $wsdl_string .= $data;
5154
                }
5155
                fclose($fp);
5156
            } else {
5157
                $errstr = "Bad path to WSDL file $path";
5158
                $this->debug($errstr);
5159
                $this->setError($errstr);
5160
5161
                return false;
5162
            }
5163
        }
5164
        $this->debug('Parse WSDL');
5165
        // end new code added
5166
        // Create an XML parser.
5167
        $this->parser = xml_parser_create();
5168
        // Set the options for parsing the XML data.
5169
        // 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...
5170
        xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
5171
        // Set the object for the parser.
5172
        xml_set_object($this->parser, $this);
5173
        // Set the element handlers for the parser.
5174
        xml_set_element_handler($this->parser, 'start_element', 'end_element');
5175
        xml_set_character_data_handler($this->parser, 'character_data');
5176
        // Parse the XML file.
5177 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...
5178
            // Display an error message.
5179
            $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)));
5180
            $this->debug($errstr);
5181
            $this->debug("XML payload:\n" . $wsdl_string);
5182
            $this->setError($errstr);
5183
5184
            return false;
5185
        }
5186
        // free the parser
5187
        xml_parser_free($this->parser);
5188
        $this->debug('Parsing WSDL done');
5189
        // catch wsdl parse errors
5190
        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...
5191
            return false;
5192
        }
5193
5194
        return true;
5195
    }
5196
5197
    /**
5198
     * start-element handler
5199
     *
5200
     * @param string $parser XML parser object
5201
     * @param string $name   element name
5202
     * @param string $attrs  associative array of attributes
5203
     * @access private
5204
     */
5205
    public function start_element($parser, $name, $attrs)
5206
    {
5207
        if ($this->status === 'schema') {
5208
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5209
            $this->appendDebug($this->currentSchema->getDebug());
5210
            $this->currentSchema->clearDebug();
5211
        } elseif (preg_match('/schema$/', $name)) {
5212
            $this->debug('Parsing WSDL schema');
5213
            // $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...
5214
            $this->status        = 'schema';
5215
            $this->currentSchema = new nusoap_xmlschema('', '', $this->namespaces);
5216
            $this->currentSchema->schemaStartElement($parser, $name, $attrs);
5217
            $this->appendDebug($this->currentSchema->getDebug());
5218
            $this->currentSchema->clearDebug();
5219
        } else {
5220
            // position in the total number of elements, starting from 0
5221
            $pos   = $this->position++;
5222
            $depth = $this->depth++;
5223
            // set self as current value for this depth
5224
            $this->depth_array[$depth] = $pos;
5225
            $this->message[$pos]       = array('cdata' => '');
5226
            // process attributes
5227
            if (count($attrs) > 0) {
5228
                // register namespace declarations
5229
                foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
5230
                    if (preg_match('/^xmlns/', $k)) {
5231
                        if ($ns_prefix = substr(strrchr($k, ':'), 1)) {
5232
                            $this->namespaces[$ns_prefix] = $v;
5233
                        } else {
5234
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $v;
5235
                        }
5236 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...
5237
                            || $v === 'http://www.w3.org/2000/10/XMLSchema'
5238
                        ) {
5239
                            $this->XMLSchemaVersion  = $v;
5240
                            $this->namespaces['xsi'] = $v . '-instance';
5241
                        }
5242
                    }
5243
                }
5244
                // expand each attribute prefix to its namespace
5245
                foreach ($attrs as $k => $v) {
0 ignored issues
show
Bug introduced by
The expression $attrs of type string is not traversable.
Loading history...
5246
                    $k = strpos($k, ':') ? $this->expandQname($k) : $k;
5247
                    if ($k !== 'location' && $k !== 'soapAction' && $k !== 'namespace') {
5248
                        $v = strpos($v, ':') ? $this->expandQname($v) : $v;
5249
                    }
5250
                    $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...
5251
                }
5252
                $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...
5253
            } else {
5254
                $attrs = array();
5255
            }
5256
            // get element prefix, namespace and name
5257
            if (preg_match('/:/', $name)) {
5258
                // get ns prefix
5259
                $prefix = substr($name, 0, strpos($name, ':'));
5260
                // get ns
5261
                $namespace = isset($this->namespaces[$prefix]) ? $this->namespaces[$prefix] : '';
5262
                // get unqualified name
5263
                $name = substr(strstr($name, ':'), 1);
5264
            }
5265
            // process attributes, expanding any prefixes to namespaces
5266
            // find status, register data
5267
            switch ($this->status) {
5268
                case 'message':
5269
                    if ($name === 'part') {
5270 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...
5271
                            $this->debug('msg ' . $this->currentMessage . ": found part (with type) $attrs[name]: " . implode(',', $attrs));
5272
                            $this->messages[$this->currentMessage][$attrs['name']] = $attrs['type'];
5273
                        }
5274 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...
5275
                            $this->debug('msg ' . $this->currentMessage . ": found part (with element) $attrs[name]: " . implode(',', $attrs));
5276
                            $this->messages[$this->currentMessage][$attrs['name']] = $attrs['element'] . '^';
5277
                        }
5278
                    }
5279
                    break;
5280
                case 'portType':
5281
                    switch ($name) {
5282
                        case 'operation':
5283
                            $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...
5284
                            $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...
5285
                            if (isset($attrs['parameterOrder'])) {
5286
                                $this->portTypes[$this->currentPortType][$attrs['name']]['parameterOrder'] = $attrs['parameterOrder'];
5287
                            }
5288
                            break;
5289
                        case 'documentation':
5290
                            $this->documentation = true;
5291
                            break;
5292
                        // merge input/output data
5293
                        default:
5294
                            $m                                                                                      = isset($attrs['message']) ? $this->getLocalPart($attrs['message']) : '';
5295
                            $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...
5296
                            break;
5297
                    }
5298
                    break;
5299
                case 'binding':
5300
                    switch ($name) {
5301
                        case 'binding':
5302
                            // get ns prefix
5303
                            if (isset($attrs['style'])) {
5304
                                $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...
5305
                            }
5306
                            $this->bindings[$this->currentBinding] = array_merge($this->bindings[$this->currentBinding], $attrs);
5307
                            break;
5308
                        case 'header':
5309
                            $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...
5310
                            break;
5311
                        case 'operation':
5312 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...
5313
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['soapAction'] = $attrs['soapAction'];
5314
                            }
5315 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...
5316
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['style'] = $attrs['style'];
5317
                            }
5318
                            if (isset($attrs['name'])) {
5319
                                $this->currentOperation = $attrs['name'];
5320
                                $this->debug("current binding operation: $this->currentOperation");
5321
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['name']     = $attrs['name'];
5322
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['binding']  = $this->currentBinding;
5323
                                $this->bindings[$this->currentBinding]['operations'][$this->currentOperation]['endpoint'] = isset($this->bindings[$this->currentBinding]['endpoint']) ? $this->bindings[$this->currentBinding]['endpoint'] : '';
5324
                            }
5325
                            break;
5326
                        case 'input':
5327
                            $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...
5328
                            break;
5329
                        case 'output':
5330
                            $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...
5331
                            break;
5332
                        case 'body':
5333
                            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...
5334
                                $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...
5335
                            } else {
5336
                                $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...
5337
                            }
5338
                            break;
5339
                    }
5340
                    break;
5341
                case 'service':
5342
                    switch ($name) {
5343
                        case 'port':
5344
                            $this->currentPort = $attrs['name'];
5345
                            $this->debug('current port: ' . $this->currentPort);
5346
                            $this->ports[$this->currentPort]['binding'] = $this->getLocalPart($attrs['binding']);
5347
5348
                            break;
5349
                        case 'address':
5350
                            $this->ports[$this->currentPort]['location']                                = $attrs['location'];
5351
                            $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...
5352
                            $this->bindings[$this->ports[$this->currentPort]['binding']]['bindingType'] = $namespace;
5353
                            $this->bindings[$this->ports[$this->currentPort]['binding']]['endpoint']    = $attrs['location'];
5354
                            break;
5355
                    }
5356
                    break;
5357
            }
5358
            // set status
5359
            switch ($name) {
5360
                case 'import':
5361
                    if (isset($attrs['location'])) {
5362
                        $this->import[$attrs['namespace']][] = array(
5363
                            'location' => $attrs['location'],
5364
                            'loaded'   => false
5365
                        );
5366
                        $this->debug('parsing import ' . $attrs['namespace'] . ' - ' . $attrs['location'] . ' (' . count($this->import[$attrs['namespace']]) . ')');
5367
                    } else {
5368
                        $this->import[$attrs['namespace']][] = array('location' => '', 'loaded' => true);
5369 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...
5370
                            $this->namespaces['ns' . (count($this->namespaces) + 1)] = $attrs['namespace'];
5371
                        }
5372
                        $this->debug('parsing import ' . $attrs['namespace'] . ' - [no location] (' . count($this->import[$attrs['namespace']]) . ')');
5373
                    }
5374
                    break;
5375
                //wait for schema
5376
                //case 'types':
5377
                //  $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...
5378
                //  break;
5379
                case 'message':
5380
                    $this->status                   = 'message';
5381
                    $this->messages[$attrs['name']] = array();
5382
                    $this->currentMessage           = $attrs['name'];
5383
                    break;
5384
                case 'portType':
5385
                    $this->status                    = 'portType';
5386
                    $this->portTypes[$attrs['name']] = array();
5387
                    $this->currentPortType           = $attrs['name'];
5388
                    break;
5389
                case 'binding':
5390
                    if (isset($attrs['name'])) {
5391
                        // get binding name
5392
                        if (strpos($attrs['name'], ':')) {
5393
                            $this->currentBinding = $this->getLocalPart($attrs['name']);
5394
                        } else {
5395
                            $this->currentBinding = $attrs['name'];
5396
                        }
5397
                        $this->status                                      = 'binding';
5398
                        $this->bindings[$this->currentBinding]['portType'] = $this->getLocalPart($attrs['type']);
5399
                        $this->debug("current binding: $this->currentBinding of portType: " . $attrs['type']);
5400
                    }
5401
                    break;
5402
                case 'service':
5403
                    $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...
5404
                    $this->status      = 'service';
5405
                    $this->debug('current service: ' . $this->serviceName);
5406
                    break;
5407
                case 'definitions':
5408
                    foreach ($attrs as $name => $value) {
5409
                        $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...
5410
                    }
5411
                    break;
5412
            }
5413
        }
5414
    }
5415
5416
    /**
5417
     * end-element handler
5418
     *
5419
     * @param string $parser XML parser object
5420
     * @param string $name   element name
5421
     * @access private
5422
     */
5423
    public function end_element($parser, $name)
5424
    {
5425
        // unset schema status
5426
        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...
5427
        preg_match('/schema$/', $name)
5428
        ) {
5429
            $this->status = '';
5430
            $this->appendDebug($this->currentSchema->getDebug());
5431
            $this->currentSchema->clearDebug();
5432
            $this->schemas[$this->currentSchema->schemaTargetNamespace][] = $this->currentSchema;
5433
            $this->debug('Parsing WSDL schema done');
5434
        }
5435
        if ($this->status === 'schema') {
5436
            $this->currentSchema->schemaEndElement($parser, $name);
5437
        } else {
5438
            // bring depth down a notch
5439
            $this->depth--;
5440
        }
5441
        // end documentation
5442
        if ($this->documentation) {
5443
            //TODO: track the node to which documentation should be assigned; it can be a part, message, etc.
5444
            //$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...
5445
            $this->documentation = false;
5446
        }
5447
    }
5448
5449
    /**
5450
     * element content handler
5451
     *
5452
     * @param string $parser XML parser object
5453
     * @param string $data   element content
5454
     * @access private
5455
     */
5456
    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...
5457
    {
5458
        $pos = isset($this->depth_array[$this->depth]) ? $this->depth_array[$this->depth] : 0;
5459 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...
5460
            $this->message[$pos]['cdata'] .= $data;
5461
        }
5462
        if ($this->documentation) {
5463
            $this->documentation .= $data;
5464
        }
5465
    }
5466
5467
    /**
5468
     * if authenticating, set user credentials here
5469
     *
5470
     * @param string $username
5471
     * @param string $password
5472
     * @param string $authtype    (basic|digest|certificate|ntlm)
5473
     * @param array  $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, certpassword (optional), verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
5474
     * @access   public
5475
     */
5476 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...
5477
    {
5478
        $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
5479
        $this->appendDebug($this->varDump($certRequest));
5480
        $this->username    = $username;
5481
        $this->password    = $password;
5482
        $this->authtype    = $authtype;
5483
        $this->certRequest = $certRequest;
5484
    }
5485
5486
    /**
5487
     * @param $binding
5488
     * @return mixed
5489
     */
5490
    public function getBindingData($binding)
5491
    {
5492
        if (is_array($this->bindings[$binding])) {
5493
            return $this->bindings[$binding];
5494
        }
5495
    }
5496
5497
    /**
5498
     * returns an assoc array of operation names => operation data
5499
     *
5500
     * @param  string $portName    WSDL port name
5501
     * @param  string $bindingType eg: soap, smtp, dime (only soap and soap12 are currently supported)
5502
     * @return array
5503
     * @access public
5504
     */
5505
    public function getOperations($portName = '', $bindingType = 'soap')
5506
    {
5507
        $ops = array();
5508
        if ($bindingType === 'soap') {
5509
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5510
        } elseif ($bindingType === 'soap12') {
5511
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5512
        } else {
5513
            $this->debug("getOperations bindingType $bindingType may not be supported");
5514
        }
5515
        $this->debug("getOperations for port '$portName' bindingType $bindingType");
5516
        // loop thru ports
5517
        foreach ($this->ports as $port => $portData) {
5518
            $this->debug("getOperations checking port $port bindingType " . $portData['bindingType']);
5519
            if ($portName == '' || $port == $portName) {
5520
                // binding type of port matches parameter
5521
                if ($portData['bindingType'] == $bindingType) {
5522
                    $this->debug("getOperations found port $port bindingType $bindingType");
5523
                    //$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...
5524
                    //$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...
5525
                    // merge bindings
5526
                    if (isset($this->bindings[$portData['binding']]['operations'])) {
5527
                        $ops = array_merge($ops, $this->bindings[$portData['binding']]['operations']);
5528
                    }
5529
                }
5530
            }
5531
        }
5532
        if (count($ops) == 0) {
5533
            $this->debug("getOperations found no operations for port '$portName' bindingType $bindingType");
5534
        }
5535
5536
        return $ops;
5537
    }
5538
5539
    /**
5540
     * returns an associative array of data necessary for calling an operation
5541
     *
5542
     * @param  string $operation   name of operation
5543
     * @param  string $bindingType type of binding eg: soap, soap12
5544
     * @return array
5545
     * @access public
5546
     */
5547
    public function getOperationData($operation, $bindingType = 'soap')
5548
    {
5549
        if ($bindingType === 'soap') {
5550
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5551
        } elseif ($bindingType === 'soap12') {
5552
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5553
        }
5554
        // loop thru ports
5555
        foreach ($this->ports as $port => $portData) {
5556
            // binding type of port matches parameter
5557
            if ($portData['bindingType'] == $bindingType) {
5558
                // get binding
5559
                //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...
5560
                foreach (array_keys($this->bindings[$portData['binding']]['operations']) as $bOperation) {
5561
                    // note that we could/should also check the namespace here
5562
                    if ($operation == $bOperation) {
5563
                        $opData = $this->bindings[$portData['binding']]['operations'][$operation];
5564
5565
                        return $opData;
5566
                    }
5567
                }
5568
            }
5569
        }
5570
    }
5571
5572
    /**
5573
     * returns an associative array of data necessary for calling an operation
5574
     *
5575
     * @param  string $soapAction  soapAction for operation
5576
     * @param  string $bindingType type of binding eg: soap, soap12
5577
     * @return array
5578
     * @access public
5579
     */
5580
    public function getOperationDataForSoapAction($soapAction, $bindingType = 'soap')
5581
    {
5582
        if ($bindingType === 'soap') {
5583
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap/';
5584
        } elseif ($bindingType === 'soap12') {
5585
            $bindingType = 'http://schemas.xmlsoap.org/wsdl/soap12/';
5586
        }
5587
        // loop thru ports
5588
        foreach ($this->ports as $port => $portData) {
5589
            // binding type of port matches parameter
5590
            if ($portData['bindingType'] == $bindingType) {
5591
                // loop through operations for the binding
5592
                foreach ($this->bindings[$portData['binding']]['operations'] as $bOperation => $opData) {
5593
                    if ($opData['soapAction'] == $soapAction) {
5594
                        return $opData;
5595
                    }
5596
                }
5597
            }
5598
        }
5599
    }
5600
5601
    /**
5602
     * returns an array of information about a given type
5603
     * returns false if no type exists by the given name
5604
     *
5605
     *    typeDef = array(
5606
     *    'elements' => array(), // refs to elements array
5607
     *   'restrictionBase' => '',
5608
     *   'phpType' => '',
5609
     *   'order' => '(sequence|all)',
5610
     *   'attrs' => array() // refs to attributes array
5611
     *   )
5612
     *
5613
     * @param  string $type the type
5614
     * @param  string $ns   namespace (not prefix) of the type
5615
     * @return mixed
5616
     * @access public
5617
     * @see    nusoap_xmlschema
5618
     */
5619
    public function getTypeDef($type, $ns)
5620
    {
5621
        $this->debug("in getTypeDef: type=$type, ns=$ns");
5622
        if ((!$ns) && isset($this->namespaces['tns'])) {
5623
            $ns = $this->namespaces['tns'];
5624
            $this->debug("in getTypeDef: type namespace forced to $ns");
5625
        }
5626
        if (!isset($this->schemas[$ns])) {
5627
            foreach ($this->schemas as $ns0 => $schema0) {
5628
                if (strcasecmp($ns, $ns0) == 0) {
5629
                    $this->debug("in getTypeDef: replacing schema namespace $ns with $ns0");
5630
                    $ns = $ns0;
5631
                    break;
5632
                }
5633
            }
5634
        }
5635
        if (isset($this->schemas[$ns])) {
5636
            $this->debug("in getTypeDef: have schema for namespace $ns");
5637
            for ($i = 0, $iMax = count($this->schemas[$ns]); $i < $iMax; ++$i) {
5638
                $xs = &$this->schemas[$ns][$i];
5639
                $t  = $xs->getTypeDef($type);
5640
                $this->appendDebug($xs->getDebug());
5641
                $xs->clearDebug();
5642
                if ($t) {
5643
                    $this->debug("in getTypeDef: found type $type");
5644
                    if (!isset($t['phpType'])) {
5645
                        // get info for type to tack onto the element
5646
                        $uqType = substr($t['type'], strrpos($t['type'], ':') + 1);
5647
                        $ns     = substr($t['type'], 0, strrpos($t['type'], ':'));
5648
                        $etype  = $this->getTypeDef($uqType, $ns);
5649
                        if ($etype) {
5650
                            $this->debug("found type for [element] $type:");
5651
                            $this->debug($this->varDump($etype));
5652
                            if (isset($etype['phpType'])) {
5653
                                $t['phpType'] = $etype['phpType'];
5654
                            }
5655
                            if (isset($etype['elements'])) {
5656
                                $t['elements'] = $etype['elements'];
5657
                            }
5658
                            if (isset($etype['attrs'])) {
5659
                                $t['attrs'] = $etype['attrs'];
5660
                            }
5661
                        } else {
5662
                            $this->debug("did not find type for [element] $type");
5663
                        }
5664
                    }
5665
5666
                    return $t;
5667
                }
5668
            }
5669
            $this->debug("in getTypeDef: did not find type $type");
5670
        } else {
5671
            $this->debug("in getTypeDef: do not have schema for namespace $ns");
5672
        }
5673
5674
        return false;
5675
    }
5676
5677
    /**
5678
     * prints html description of services
5679
     *
5680
     * @access private
5681
     */
5682
    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...
5683
    {
5684
        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...
5685
5686
        if (isset($_SERVER)) {
5687
            $PHP_SELF = $_SERVER['PHP_SELF'];
5688
        } elseif (isset($HTTP_SERVER_VARS)) {
5689
            $PHP_SELF = $HTTP_SERVER_VARS['PHP_SELF'];
5690
        } else {
5691
            $this->setError('Neither _SERVER nor HTTP_SERVER_VARS is available');
5692
        }
5693
5694
        $b = '
5695
        <html><head><title>NuSOAP: ' . $this->serviceName . '</title>
5696
        <style type="text/css">
5697
            body    { font-family: arial; color: #000000; background-color: #ffffff; margin: 0 0 0 0; }
5698
            p       { font-family: arial; color: #000000; margin-top: 0; margin-bottom: 12px; }
5699
            pre { background-color: silver; padding: 5px; font-family: Courier New; font-size: x-small; color: #000000;}
5700
            ul      { margin-top: 10px; margin-left: 20px; }
5701
            li      { list-style-type: none; margin-top: 10px; color: #000000; }
5702
            .content{
5703
            margin-left: 0; padding-bottom: 2em; }
5704
            .nav {
5705
            padding-top: 10px; padding-bottom: 10px; padding-left: 15px; font-size: .70em;
5706
            margin-top: 10px; margin-left: 0; color: #000000;
5707
            background-color: #ccccff; width: 20%; margin-left: 20px; margin-top: 20px; }
5708
            .title {
5709
            font-family: arial; font-size: 26px; color: #ffffff;
5710
            background-color: #999999; width: 100%;
5711
            margin-left: 0; margin-right: 0;
5712
            padding-top: 10px; padding-bottom: 10px;}
5713
            .hidden {
5714
            position: absolute; visibility: hidden; z-index: 200; left: 250px; top: 100px;
5715
            font-family: arial; overflow: hidden; width: 600;
5716
            padding: 20px; font-size: 10px; background-color: #999999;
5717
            layer-background-color:#FFFFFF; }
5718
            a,a:active  { color: charcoal; font-weight: bold; }
5719
            a:visited   { color: #666666; font-weight: bold; }
5720
            a:hover     { color: cc3300; font-weight: bold; }
5721
        </style>
5722
        <script language="JavaScript" type="text/javascript">
5723
        <!--
5724
        // POP-UP CAPTIONS...
5725
        function lib_bwcheck(){ //Browsercheck (needed)
5726
            this.ver=navigator.appVersion
5727
            this.agent=navigator.userAgent
5728
            this.dom=document.getElementById?1:0
5729
            this.opera5=this.agent.indexOf("Opera 5")>-1
5730
            this.ie5=(this.ver.indexOf("MSIE 5")>-1 && this.dom && !this.opera5)?1:0;
5731
            this.ie6=(this.ver.indexOf("MSIE 6")>-1 && this.dom && !this.opera5)?1:0;
5732
            this.ie4=(document.all && !this.dom && !this.opera5)?1:0;
5733
            this.ie=this.ie4||this.ie5||this.ie6
5734
            this.mac=this.agent.indexOf("Mac")>-1
5735
            this.ns6=(this.dom && parseInt(this.ver) >= 5) ?1:0;
5736
            this.ns4=(document.layers && !this.dom)?1:0;
5737
            this.bw=(this.ie6 || this.ie5 || this.ie4 || this.ns4 || this.ns6 || this.opera5)
5738
5739
            return this
5740
        }
5741
        var bw = new Lib_bwcheck()
5742
        //Makes crossbrowser object.
5743
        function makeObj(obj){
5744
            this.evnt=bw.dom? document.getElementById(obj):bw.ie4?document.all[obj]:bw.ns4?document.layers[obj]:0;
5745
            if(!this.evnt) return false
5746
            this.css=bw.dom||bw.ie4?this.evnt.style:bw.ns4?this.evnt:0;
5747
            this.wref=bw.dom||bw.ie4?this.evnt:bw.ns4?this.css.document:0;
5748
            this.writeIt=b_writeIt;
5749
5750
            return this
5751
        }
5752
        // A unit of measure that will be added when setting the position of a layer.
5753
        //var px = bw.ns4||window.opera?"":"px";
5754
        function b_writeIt(text){
5755
            if (bw.ns4) {this.wref.write(text);this.wref.close()}
5756
            else this.wref.innerHTML = text
5757
        }
5758
        //Shows the messages
5759
        var oDesc;
5760
        function popup(divid){
5761
            if (oDesc = new MakeObj(divid)) {
5762
            oDesc.css.visibility = "visible"
5763
            }
5764
        }
5765
        function popout(){ // Hides message
5766
            if(oDesc) oDesc.css.visibility = "hidden"
5767
        }
5768
        //-->
5769
        </script>
5770
        </head>
5771
        <body>
5772
        <div class=content>
5773
            <br><br>
5774
            <div class=title>' . $this->serviceName . '</div>
5775
            <div class=nav>
5776
                <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...
5777
                Click on an operation name to view it&apos;s details.</p>
5778
                <ul>';
5779
        foreach ($this->getOperations() as $op => $data) {
5780
            $b .= "<li><a href='#' onclick=\"popout();popup('$op')\">$op</a></li>";
5781
            // create hidden div
5782
            $b .= "<div id='$op' class='hidden'>
5783
                    <a href='#' onclick='popout()'><span style='color: #ffffff;'>Close</span></a><br><br>";
5784
            foreach ($data as $donnie => $marie) { // loop through opdata
5785
                if ($donnie === 'input' || $donnie === 'output') { // show input/output data
5786
                    $b .= "<font color='white'>" . ucfirst($donnie) . ':</font><br>';
5787
                    foreach ($marie as $captain => $tenille) { // loop through data
5788
                        if ($captain === 'parts') { // loop thru parts
5789
                            $b .= "&nbsp;&nbsp;$captain:<br>";
5790
                            //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...
5791
                            foreach ($tenille as $joanie => $chachi) {
5792
                                $b .= "&nbsp;&nbsp;&nbsp;&nbsp;$joanie: $chachi<br>";
5793
                            }
5794
                            //}
5795
                        } else {
5796
                            $b .= "&nbsp;&nbsp;$captain: $tenille<br>";
5797
                        }
5798
                    }
5799
                } else {
5800
                    $b .= "<font color='white'>" . ucfirst($donnie) . ":</font> $marie<br>";
5801
                }
5802
            }
5803
            $b .= '</div>';
5804
        }
5805
        $b .= '
5806
                <ul>
5807
            </div>
5808
        </div></body></html>';
5809
5810
        return $b;
5811
    }
5812
5813
    /**
5814
     * serialize the parsed wsdl
5815
     *
5816
     * @param  mixed $debug whether to put debug=1 in endpoint URL
5817
     * @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...
5818
     * @access public
5819
     */
5820
    public function serialize($debug = 0)
5821
    {
5822
        $xml = '<?xml version="1.0" encoding="ISO-8859-1"?>';
5823
        $xml .= "\n<definitions";
5824
        foreach ($this->namespaces as $k => $v) {
5825
            $xml .= " xmlns:$k=\"$v\"";
5826
        }
5827
        // 10.9.02 - add poulter fix for wsdl and tns declarations
5828 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...
5829
            $xml .= " xmlns=\"" . $this->namespaces['wsdl'] . "\"";
5830
        }
5831 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...
5832
            $xml .= " targetNamespace=\"" . $this->namespaces['tns'] . "\"";
5833
        }
5834
        $xml .= '>';
5835
        // imports
5836 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...
5837
            foreach ($this->import as $ns => $list) {
5838
                foreach ($list as $ii) {
5839
                    if ($ii['location'] != '') {
5840
                        $xml .= '<import location="' . $ii['location'] . '" namespace="' . $ns . '" />';
5841
                    } else {
5842
                        $xml .= '<import namespace="' . $ns . '" />';
5843
                    }
5844
                }
5845
            }
5846
        }
5847
        // types
5848
        if (count($this->schemas) >= 1) {
5849
            $xml .= "\n<types>\n";
5850
            foreach ($this->schemas as $ns => $list) {
5851
                foreach ($list as $xs) {
5852
                    $xml .= $xs->serializeSchema();
5853
                }
5854
            }
5855
            $xml .= '</types>';
5856
        }
5857
        // messages
5858
        if (count($this->messages) >= 1) {
5859
            foreach ($this->messages as $msgName => $msgParts) {
5860
                $xml .= "\n<message name=\"" . $msgName . '">';
5861
                if (is_array($msgParts)) {
5862
                    foreach ($msgParts as $partName => $partType) {
5863
                        // 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...
5864
                        if (strpos($partType, ':')) {
5865
                            $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...
5866
                        } elseif (isset($this->typemap[$this->namespaces['xsd']][$partType])) {
5867
                            // 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...
5868
                            $typePrefix = 'xsd';
5869
                        } else {
5870
                            foreach ($this->typemap as $ns => $types) {
5871
                                if (isset($types[$partType])) {
5872
                                    $typePrefix = $this->getPrefixFromNamespace($ns);
5873
                                }
5874
                            }
5875
                            if (!isset($typePrefix)) {
5876
                                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...
5877
                            }
5878
                        }
5879
                        $ns        = $this->getNamespaceFromPrefix($typePrefix);
5880
                        $localPart = $this->getLocalPart($partType);
5881
                        $typeDef   = $this->getTypeDef($localPart, $ns);
5882
                        if ($typeDef['typeClass'] === 'element') {
5883
                            $elementortype = 'element';
5884
                            if (substr($localPart, -1) === '^') {
5885
                                $localPart = substr($localPart, 0, -1);
5886
                            }
5887
                        } else {
5888
                            $elementortype = 'type';
5889
                        }
5890
                        $xml .= "\n" . '  <part name="' . $partName . '" ' . $elementortype . '="' . $typePrefix . ':' . $localPart . '" />';
5891
                    }
5892
                }
5893
                $xml .= '</message>';
5894
            }
5895
        }
5896
        // bindings & porttypes
5897
        if (count($this->bindings) >= 1) {
5898
            $binding_xml  = '';
5899
            $portType_xml = '';
5900
            foreach ($this->bindings as $bindingName => $attrs) {
5901
                $binding_xml .= "\n<binding name=\"" . $bindingName . '" type="tns:' . $attrs['portType'] . '">';
5902
                $binding_xml .= "\n" . '  <soap:binding style="' . $attrs['style'] . '" transport="' . $attrs['transport'] . '"/>';
5903
                $portType_xml .= "\n<portType name=\"" . $attrs['portType'] . '">';
5904
                foreach ($attrs['operations'] as $opName => $opParts) {
5905
                    $binding_xml .= "\n" . '  <operation name="' . $opName . '">';
5906
                    $binding_xml .= "\n" . '    <soap:operation soapAction="' . $opParts['soapAction'] . '" style="' . $opParts['style'] . '"/>';
5907 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...
5908
                        $enc_style = ' encodingStyle="' . $opParts['input']['encodingStyle'] . '"';
5909
                    } else {
5910
                        $enc_style = '';
5911
                    }
5912
                    $binding_xml .= "\n" . '    <input><soap:body use="' . $opParts['input']['use'] . '" namespace="' . $opParts['input']['namespace'] . '"' . $enc_style . '/></input>';
5913 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...
5914
                        $enc_style = ' encodingStyle="' . $opParts['output']['encodingStyle'] . '"';
5915
                    } else {
5916
                        $enc_style = '';
5917
                    }
5918
                    $binding_xml .= "\n" . '    <output><soap:body use="' . $opParts['output']['use'] . '" namespace="' . $opParts['output']['namespace'] . '"' . $enc_style . '/></output>';
5919
                    $binding_xml .= "\n" . '  </operation>';
5920
                    $portType_xml .= "\n" . '  <operation name="' . $opParts['name'] . '"';
5921
                    if (isset($opParts['parameterOrder'])) {
5922
                        $portType_xml .= ' parameterOrder="' . $opParts['parameterOrder'] . '"';
5923
                    }
5924
                    $portType_xml .= '>';
5925
                    if (isset($opParts['documentation']) && $opParts['documentation'] != '') {
5926
                        $portType_xml .= "\n" . '    <documentation>' . htmlspecialchars($opParts['documentation']) . '</documentation>';
5927
                    }
5928
                    $portType_xml .= "\n" . '    <input message="tns:' . $opParts['input']['message'] . '"/>';
5929
                    $portType_xml .= "\n" . '    <output message="tns:' . $opParts['output']['message'] . '"/>';
5930
                    $portType_xml .= "\n" . '  </operation>';
5931
                }
5932
                $portType_xml .= "\n" . '</portType>';
5933
                $binding_xml .= "\n" . '</binding>';
5934
            }
5935
            $xml .= $portType_xml . $binding_xml;
5936
        }
5937
        // services
5938
        $xml .= "\n<service name=\"" . $this->serviceName . '">';
5939
        if (count($this->ports) >= 1) {
5940
            foreach ($this->ports as $pName => $attrs) {
5941
                $xml .= "\n" . '  <port name="' . $pName . '" binding="tns:' . $attrs['binding'] . '">';
5942
                $xml .= "\n" . '    <soap:address location="' . $attrs['location'] . ($debug ? '?debug=1' : '') . '"/>';
5943
                $xml .= "\n" . '  </port>';
5944
            }
5945
        }
5946
        $xml .= "\n" . '</service>';
5947
5948
        return $xml . "\n</definitions>";
5949
    }
5950
5951
    /**
5952
     * determine whether a set of parameters are unwrapped
5953
     * when they are expect to be wrapped, Microsoft-style.
5954
     *
5955
     * @param  string $type       the type (element name) of the wrapper
5956
     * @param  array  $parameters the parameter values for the SOAP call
5957
     * @return boolean whether they parameters are unwrapped (and should be wrapped)
5958
     * @access private
5959
     */
5960
    public function parametersMatchWrapped($type, &$parameters)
5961
    {
5962
        $this->debug("in parametersMatchWrapped type=$type, parameters=");
5963
        $this->appendDebug($this->varDump($parameters));
5964
5965
        // split type into namespace:unqualified-type
5966
        if (strpos($type, ':')) {
5967
            $uqType = substr($type, strrpos($type, ':') + 1);
5968
            $ns     = substr($type, 0, strrpos($type, ':'));
5969
            $this->debug("in parametersMatchWrapped: got a prefixed type: $uqType, $ns");
5970
            if ($this->getNamespaceFromPrefix($ns)) {
5971
                $ns = $this->getNamespaceFromPrefix($ns);
5972
                $this->debug("in parametersMatchWrapped: expanded prefixed type: $uqType, $ns");
5973
            }
5974
        } else {
5975
            // TODO: should the type be compared to types in XSD, and the namespace
5976
            // set to XSD if the type matches?
5977
            $this->debug("in parametersMatchWrapped: No namespace for type $type");
5978
            $ns     = '';
5979
            $uqType = $type;
5980
        }
5981
5982
        // get the type information
5983
        if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
5984
            $this->debug("in parametersMatchWrapped: $type ($uqType) is not a supported type.");
5985
5986
            return false;
5987
        }
5988
        $this->debug('in parametersMatchWrapped: found typeDef=');
5989
        $this->appendDebug($this->varDump($typeDef));
5990 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...
5991
            $uqType = substr($uqType, 0, -1);
5992
        }
5993
        $phpType   = $typeDef['phpType'];
5994
        $arrayType = (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : '');
5995
        $this->debug("in parametersMatchWrapped: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: $arrayType");
5996
5997
        // we expect a complexType or element of complexType
5998
        if ($phpType !== 'struct') {
5999
            $this->debug('in parametersMatchWrapped: not a struct');
6000
6001
            return false;
6002
        }
6003
6004
        // see whether the parameter names match the elements
6005
        if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6006
            $elements = 0;
6007
            $matches  = 0;
6008
            foreach ($typeDef['elements'] as $name => $attrs) {
6009
                if (isset($parameters[$name])) {
6010
                    $this->debug("in parametersMatchWrapped: have parameter named $name");
6011
                    ++$matches;
6012
                } else {
6013
                    $this->debug("in parametersMatchWrapped: do not have parameter named $name");
6014
                }
6015
                ++$elements;
6016
            }
6017
6018
            $this->debug("in parametersMatchWrapped: $matches parameter names match $elements wrapped parameter names");
6019
            if ($matches == 0) {
6020
                return false;
6021
            }
6022
6023
            return true;
6024
        }
6025
6026
        // since there are no elements for the type, if the user passed no
6027
        // parameters, the parameters match wrapped.
6028
        $this->debug("in parametersMatchWrapped: no elements type $ns:$uqType");
6029
6030
        return count($parameters) == 0;
6031
    }
6032
6033
    /**
6034
     * serialize PHP values according to a WSDL message definition
6035
     * contrary to the method name, this is not limited to RPC
6036
     *
6037
     * TODO
6038
     * - multi-ref serialization
6039
     * - validate PHP values against type definitions, return errors if invalid
6040
     *
6041
     * @param  string $operation   operation name
6042
     * @param  string $direction   (input|output)
6043
     * @param  mixed  $parameters  parameter value(s)
6044
     * @param  string $bindingType (soap|soap12)
6045
     * @return mixed  parameters serialized as XML or false on error (e.g. operation not found)
6046
     * @access public
6047
     */
6048
    public function serializeRPCParameters($operation, $direction, $parameters, $bindingType = 'soap')
6049
    {
6050
        $this->debug("in serializeRPCParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion, bindingType=$bindingType");
6051
        $this->appendDebug('parameters=' . $this->varDump($parameters));
6052
6053 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...
6054
            $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
6055
            $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
6056
6057
            return false;
6058
        }
6059
        if (!$opData = $this->getOperationData($operation, $bindingType)) {
6060
            $this->debug('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
6061
            $this->setError('Unable to retrieve WSDL data for operation: ' . $operation . ' bindingType: ' . $bindingType);
6062
6063
            return false;
6064
        }
6065
        $this->debug('in serializeRPCParameters: opData:');
6066
        $this->appendDebug($this->varDump($opData));
6067
6068
        // Get encoding style for output and set to current
6069
        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6070 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...
6071
            && ($opData['output']['encodingStyle'] != $encodingStyle)
6072
        ) {
6073
            $encodingStyle = $opData['output']['encodingStyle'];
6074
            $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...
6075
        }
6076
6077
        // set input params
6078
        $xml = '';
6079
        if (isset($opData[$direction]['parts']) && count($opData[$direction]['parts']) > 0) {
6080
            $parts      = &$opData[$direction]['parts'];
6081
            $part_count = count($parts);
6082
            $style      = $opData['style'];
6083
            $use        = $opData[$direction]['use'];
6084
            $this->debug("have $part_count part(s) to serialize using $style/$use");
6085
            if (is_array($parameters)) {
6086
                $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
6087
                $parameter_count     = count($parameters);
6088
                $this->debug("have $parameter_count parameter(s) provided as $parametersArrayType to serialize");
6089
                // check for Microsoft-style wrapped parameters
6090
                if ($style === 'document' && $use === 'literal' && $part_count == 1 && isset($parts['parameters'])) {
6091
                    $this->debug('check whether the caller has wrapped the parameters');
6092
                    if ($direction === 'output' && $parametersArrayType === 'arraySimple' && $parameter_count == 1) {
6093
                        // TODO: consider checking here for double-wrapping, when
6094
                        // service function wraps, then NuSOAP wraps again
6095
                        $this->debug("change simple array to associative with 'parameters' element");
6096
                        $parameters['parameters'] = $parameters[0];
6097
                        unset($parameters[0]);
6098
                    }
6099
                    if (($parametersArrayType === 'arrayStruct' || $parameter_count == 0)
6100
                        && !isset($parameters['parameters'])
6101
                    ) {
6102
                        $this->debug('check whether caller\'s parameters match the wrapped ones');
6103
                        if ($this->parametersMatchWrapped($parts['parameters'], $parameters)) {
6104
                            $this->debug('wrap the parameters for the caller');
6105
                            $parameters      = array('parameters' => $parameters);
6106
                            $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...
6107
                        }
6108
                    }
6109
                }
6110
                foreach ($parts as $name => $type) {
6111
                    $this->debug("serializing part $name of type $type");
6112
                    // Track encoding style
6113 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...
6114
                        && $encodingStyle != $opData[$direction]['encodingStyle']
6115
                    ) {
6116
                        $encodingStyle = $opData[$direction]['encodingStyle'];
6117
                        $enc_style     = $encodingStyle;
6118
                    } else {
6119
                        $enc_style = false;
6120
                    }
6121
                    // NOTE: add error handling here
6122
                    // if serializeType returns false, then catch global error and fault
6123 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...
6124
                        $p = array_shift($parameters);
6125
                        $this->debug('calling serializeType w/indexed param');
6126
                        $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
6127
                    } elseif (isset($parameters[$name])) {
6128
                        $this->debug('calling serializeType w/named param');
6129
                        $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
6130
                    } else {
6131
                        // TODO: only send nillable
6132
                        $this->debug('calling serializeType w/null param');
6133
                        $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
6134
                    }
6135
                }
6136
            } else {
6137
                $this->debug('no parameters passed.');
6138
            }
6139
        }
6140
        $this->debug("serializeRPCParameters returning: $xml");
6141
6142
        return $xml;
6143
    }
6144
6145
    /**
6146
     * serialize a PHP value according to a WSDL message definition
6147
     *
6148
     * TODO
6149
     * - multi-ref serialization
6150
     * - validate PHP values against type definitions, return errors if invalid
6151
     *
6152
     * @param  string $operation  operation name
6153
     * @param  string $direction  (input|output)
6154
     * @param  mixed  $parameters parameter value(s)
6155
     * @return mixed  parameters serialized as XML or false on error (e.g. operation not found)
6156
     * @access public
6157
     * @deprecated
6158
     */
6159
    public function serializeParameters($operation, $direction, $parameters)
6160
    {
6161
        $this->debug("in serializeParameters: operation=$operation, direction=$direction, XMLSchemaVersion=$this->XMLSchemaVersion");
6162
        $this->appendDebug('parameters=' . $this->varDump($parameters));
6163
6164 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...
6165
            $this->debug('The value of the \$direction argument needs to be either "input" or "output"');
6166
            $this->setError('The value of the \$direction argument needs to be either "input" or "output"');
6167
6168
            return false;
6169
        }
6170
        if (!$opData = $this->getOperationData($operation)) {
6171
            $this->debug('Unable to retrieve WSDL data for operation: ' . $operation);
6172
            $this->setError('Unable to retrieve WSDL data for operation: ' . $operation);
6173
6174
            return false;
6175
        }
6176
        $this->debug('opData:');
6177
        $this->appendDebug($this->varDump($opData));
6178
6179
        // Get encoding style for output and set to current
6180
        $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6181 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...
6182
            && ($opData['output']['encodingStyle'] != $encodingStyle)
6183
        ) {
6184
            $encodingStyle = $opData['output']['encodingStyle'];
6185
            $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...
6186
        }
6187
6188
        // set input params
6189
        $xml = '';
6190
        if (isset($opData[$direction]['parts']) && count($opData[$direction]['parts']) > 0) {
6191
            $use = $opData[$direction]['use'];
6192
            $this->debug("use=$use");
6193
            $this->debug('got ' . count($opData[$direction]['parts']) . ' part(s)');
6194
            if (is_array($parameters)) {
6195
                $parametersArrayType = $this->isArraySimpleOrStruct($parameters);
6196
                $this->debug('have ' . $parametersArrayType . ' parameters');
6197
                foreach ($opData[$direction]['parts'] as $name => $type) {
6198
                    $this->debug('serializing part "' . $name . '" of type "' . $type . '"');
6199
                    // Track encoding style
6200 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...
6201
                        && $encodingStyle != $opData[$direction]['encodingStyle']
6202
                    ) {
6203
                        $encodingStyle = $opData[$direction]['encodingStyle'];
6204
                        $enc_style     = $encodingStyle;
6205
                    } else {
6206
                        $enc_style = false;
6207
                    }
6208
                    // NOTE: add error handling here
6209
                    // if serializeType returns false, then catch global error and fault
6210 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...
6211
                        $p = array_shift($parameters);
6212
                        $this->debug('calling serializeType w/indexed param');
6213
                        $xml .= $this->serializeType($name, $type, $p, $use, $enc_style);
6214
                    } elseif (isset($parameters[$name])) {
6215
                        $this->debug('calling serializeType w/named param');
6216
                        $xml .= $this->serializeType($name, $type, $parameters[$name], $use, $enc_style);
6217
                    } else {
6218
                        // TODO: only send nillable
6219
                        $this->debug('calling serializeType w/null param');
6220
                        $xml .= $this->serializeType($name, $type, null, $use, $enc_style);
6221
                    }
6222
                }
6223
            } else {
6224
                $this->debug('no parameters passed.');
6225
            }
6226
        }
6227
        $this->debug("serializeParameters returning: $xml");
6228
6229
        return $xml;
6230
    }
6231
6232
    /**
6233
     * serializes a PHP value according a given type definition
6234
     *
6235
     * @param  string      $name          name of value (part or element)
6236
     * @param  string      $type          XML schema type of value (type or element)
6237
     * @param  mixed       $value         a native PHP value (parameter value)
6238
     * @param  string      $use           use for part (encoded|literal)
6239
     * @param  bool|string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6240
     * @param  boolean     $unqualified   a kludge for what should be XML namespace form handling
6241
     * @return string      value serialized as an XML string
6242
     * @access private
6243
     */
6244
    public function serializeType(
6245
        $name,
6246
        $type,
6247
        $value,
6248
        $use = 'encoded',
6249
        $encodingStyle = false,
6250
        $unqualified = false
6251
    ) {
6252
        $this->debug("in serializeType: name=$name, type=$type, use=$use, encodingStyle=$encodingStyle, unqualified=" . ($unqualified ? 'unqualified' : 'qualified'));
6253
        $this->appendDebug('value=' . $this->varDump($value));
6254
        if ($use === 'encoded' && $encodingStyle) {
6255
            $encodingStyle = ' SOAP-ENV:encodingStyle="' . $encodingStyle . '"';
6256
        }
6257
6258
        // if a soapval has been supplied, let its type override the WSDL
6259
        if (is_object($value) && get_class($value) === 'soapval') {
6260
            if ($value->type_ns) {
6261
                $type      = $value->type_ns . ':' . $value->type;
6262
                $forceType = true;
6263
                $this->debug("in serializeType: soapval overrides type to $type");
6264
            } elseif ($value->type) {
6265
                $type      = $value->type;
6266
                $forceType = true;
6267
                $this->debug("in serializeType: soapval overrides type to $type");
6268
            } else {
6269
                $forceType = false;
6270
                $this->debug('in serializeType: soapval does not override type');
6271
            }
6272
            $attrs = $value->attributes;
6273
            $value = $value->value;
6274
            $this->debug("in serializeType: soapval overrides value to $value");
6275
            if ($attrs) {
6276
                if (!is_array($value)) {
6277
                    $value['!'] = $value;
6278
                }
6279
                foreach ($attrs as $n => $v) {
6280
                    $value['!' . $n] = $v;
6281
                }
6282
                $this->debug('in serializeType: soapval provides attributes');
6283
            }
6284
        } else {
6285
            $forceType = false;
6286
        }
6287
6288
        $xml = '';
6289
        if (strpos($type, ':')) {
6290
            $uqType = substr($type, strrpos($type, ':') + 1);
6291
            $ns     = substr($type, 0, strrpos($type, ':'));
6292
            $this->debug("in serializeType: got a prefixed type: $uqType, $ns");
6293
            if ($this->getNamespaceFromPrefix($ns)) {
6294
                $ns = $this->getNamespaceFromPrefix($ns);
6295
                $this->debug("in serializeType: expanded prefixed type: $uqType, $ns");
6296
            }
6297
6298
            if ($ns == $this->XMLSchemaVersion || $ns === 'http://schemas.xmlsoap.org/soap/encoding/') {
6299
                $this->debug('in serializeType: type namespace indicates XML Schema or SOAP Encoding type');
6300
                if ($unqualified && $use === 'literal') {
6301
                    $elementNS = " xmlns=\"\"";
6302
                } else {
6303
                    $elementNS = '';
6304
                }
6305 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...
6306
                    if ($use === 'literal') {
6307
                        // TODO: depends on minOccurs
6308
                        $xml = "<$name$elementNS/>";
6309
                    } else {
6310
                        // TODO: depends on nillable, which should be checked before calling this method
6311
                        $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6312
                    }
6313
                    $this->debug("in serializeType: returning: $xml");
6314
6315
                    return $xml;
6316
                }
6317
                if ($uqType === 'Array') {
6318
                    // JBoss/Axis does this sometimes
6319
                    return $this->serialize_val($value, $name, false, false, false, false, $use);
6320
                }
6321
                if ($uqType === 'boolean') {
6322
                    if ((is_string($value) && $value === 'false') || (!$value)) {
6323
                        $value = 'false';
6324
                    } else {
6325
                        $value = 'true';
6326
                    }
6327
                }
6328
                if ($uqType === 'string' && gettype($value) === 'string') {
6329
                    $value = $this->expandEntities($value);
6330
                }
6331
                if (($uqType === 'long' || $uqType === 'unsignedLong') && gettype($value) === 'double') {
6332
                    $value = sprintf('%.0lf', $value);
6333
                }
6334
                // it's a scalar
6335
                // TODO: what about null/nil values?
6336
                // check type isn't a custom type extending xmlschema namespace
6337
                if (!$this->getTypeDef($uqType, $ns)) {
6338
                    if ($use === 'literal') {
6339
                        if ($forceType) {
6340
                            $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6341
                        } else {
6342
                            $xml = "<$name$elementNS>$value</$name>";
6343
                        }
6344
                    } else {
6345
                        $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6346
                    }
6347
                    $this->debug("in serializeType: returning: $xml");
6348
6349
                    return $xml;
6350
                }
6351
                $this->debug('custom type extends XML Schema or SOAP Encoding namespace (yuck)');
6352
            } elseif ($ns === 'http://xml.apache.org/xml-soap') {
6353
                $this->debug('in serializeType: appears to be Apache SOAP type');
6354
                if ($uqType === 'Map') {
6355
                    $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6356
                    if (!$tt_prefix) {
6357
                        $this->debug('in serializeType: Add namespace for Apache SOAP type');
6358
                        $tt_prefix                    = 'ns' . mt_rand(1000, 9999);
6359
                        $this->namespaces[$tt_prefix] = 'http://xml.apache.org/xml-soap';
6360
                        // force this to be added to usedNamespaces
6361
                        $tt_prefix = $this->getPrefixFromNamespace('http://xml.apache.org/xml-soap');
6362
                    }
6363
                    $contents = '';
6364
                    foreach ($value as $k => $v) {
6365
                        $this->debug("serializing map element: key $k, value $v");
6366
                        $contents .= '<item>';
6367
                        $contents .= $this->serialize_val($k, 'key', false, false, false, false, $use);
6368
                        $contents .= $this->serialize_val($v, 'value', false, false, false, false, $use);
6369
                        $contents .= '</item>';
6370
                    }
6371 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...
6372
                        if ($forceType) {
6373
                            $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\">$contents</$name>";
6374
                        } else {
6375
                            $xml = "<$name>$contents</$name>";
6376
                        }
6377
                    } else {
6378
                        $xml = "<$name xsi:type=\"" . $tt_prefix . ":$uqType\"$encodingStyle>$contents</$name>";
6379
                    }
6380
                    $this->debug("in serializeType: returning: $xml");
6381
6382
                    return $xml;
6383
                }
6384
                $this->debug('in serializeType: Apache SOAP type, but only support Map');
6385
            }
6386
        } else {
6387
            // TODO: should the type be compared to types in XSD, and the namespace
6388
            // set to XSD if the type matches?
6389
            $this->debug("in serializeType: No namespace for type $type");
6390
            $ns     = '';
6391
            $uqType = $type;
6392
        }
6393
        if (!$typeDef = $this->getTypeDef($uqType, $ns)) {
6394
            $this->setError("$type ($uqType) is not a supported type.");
6395
            $this->debug("in serializeType: $type ($uqType) is not a supported type.");
6396
6397
            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...
6398
        } else {
6399
            $this->debug('in serializeType: found typeDef');
6400
            $this->appendDebug('typeDef=' . $this->varDump($typeDef));
6401 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...
6402
                $uqType = substr($uqType, 0, -1);
6403
            }
6404
        }
6405
        if (!isset($typeDef['phpType'])) {
6406
            $this->setError("$type ($uqType) has no phpType.");
6407
            $this->debug("in serializeType: $type ($uqType) has no phpType.");
6408
6409
            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...
6410
        }
6411
        $phpType = $typeDef['phpType'];
6412
        $this->debug("in serializeType: uqType: $uqType, ns: $ns, phptype: $phpType, arrayType: " . (isset($typeDef['arrayType']) ? $typeDef['arrayType'] : ''));
6413
        // if php type == struct, map value to the <all> element names
6414
        if ($phpType === 'struct') {
6415
            if (isset($typeDef['typeClass']) && $typeDef['typeClass'] === 'element') {
6416
                $elementName = $uqType;
6417 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...
6418
                    $elementNS = " xmlns=\"$ns\"";
6419
                } else {
6420
                    $elementNS = " xmlns=\"\"";
6421
                }
6422
            } else {
6423
                $elementName = $name;
6424
                if ($unqualified) {
6425
                    $elementNS = " xmlns=\"\"";
6426
                } else {
6427
                    $elementNS = '';
6428
                }
6429
            }
6430 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...
6431
                if ($use === 'literal') {
6432
                    // TODO: depends on minOccurs and nillable
6433
                    $xml = "<$elementName$elementNS/>";
6434
                } else {
6435
                    $xml = "<$elementName$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"/>";
6436
                }
6437
                $this->debug("in serializeType: returning: $xml");
6438
6439
                return $xml;
6440
            }
6441
            if (is_object($value)) {
6442
                $value = get_object_vars($value);
6443
            }
6444
            if (is_array($value)) {
6445
                $elementAttrs = $this->serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType);
6446 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...
6447
                    if ($forceType) {
6448
                        $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">";
6449
                    } else {
6450
                        $xml = "<$elementName$elementNS$elementAttrs>";
6451
                    }
6452
                } else {
6453
                    $xml = "<$elementName$elementNS$elementAttrs xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>";
6454
                }
6455
6456
                if (isset($typeDef['simpleContent']) && $typeDef['simpleContent'] === 'true') {
6457
                    if (isset($value['!'])) {
6458
                        $xml .= $value['!'];
6459
                        $this->debug("in serializeType: serialized simpleContent for type $type");
6460
                    } else {
6461
                        $this->debug("in serializeType: no simpleContent to serialize for type $type");
6462
                    }
6463
                } else {
6464
                    // complexContent
6465
                    $xml .= $this->serializeComplexTypeElements($typeDef, $value, $ns, $uqType, $use, $encodingStyle);
6466
                }
6467
                $xml .= "</$elementName>";
6468
            } else {
6469
                $this->debug('in serializeType: phpType is struct, but value is not an array');
6470
                $this->setError('phpType is struct, but value is not an array: see debug output for details');
6471
                $xml = '';
6472
            }
6473
        } elseif ($phpType === 'array') {
6474 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...
6475
                $elementNS = " xmlns=\"$ns\"";
6476
            } else {
6477
                if ($unqualified) {
6478
                    $elementNS = " xmlns=\"\"";
6479
                } else {
6480
                    $elementNS = '';
6481
                }
6482
            }
6483
            if (null === $value) {
6484 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...
6485
                    // TODO: depends on minOccurs
6486
                    $xml = "<$name$elementNS/>";
6487
                } else {
6488
                    $xml = "<$name$elementNS xsi:nil=\"true\" xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ":Array\" " . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/')
6489
                           . ':arrayType="' . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . ':' . $this->getLocalPart($typeDef['arrayType']) . "[0]\"/>";
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...
6490
                }
6491
                $this->debug("in serializeType: returning: $xml");
6492
6493
                return $xml;
6494
            }
6495
            if (isset($typeDef['multidimensional'])) {
6496
                $nv = array();
6497
                foreach ($value as $v) {
6498
                    $cols = ',' . count($v);
6499
                    $nv   = array_merge($nv, $v);
6500
                }
6501
                $value = $nv;
6502
            } else {
6503
                $cols = '';
6504
            }
6505
            if (is_array($value) && count($value) >= 1) {
6506
                $rows     = count($value);
6507
                $contents = '';
6508
                foreach ($value as $k => $v) {
6509
                    $this->debug("serializing array element: $k, $v of type: $typeDef[arrayType]");
6510
                    //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...
6511
                    if (!in_array($typeDef['arrayType'], $this->typemap['http://www.w3.org/2001/XMLSchema'])) {
6512
                        $contents .= $this->serializeType('item', $typeDef['arrayType'], $v, $use);
6513
                    } else {
6514
                        $contents .= $this->serialize_val($v, 'item', $typeDef['arrayType'], null, $this->XMLSchemaVersion, false, $use);
6515
                    }
6516
                }
6517
            } else {
6518
                $rows     = 0;
6519
                $contents = null;
6520
            }
6521
            // TODO: for now, an empty value will be serialized as a zero element
6522
            // array.  Revisit this when coding the handling of null/nil values.
6523
            if ($use === 'literal') {
6524
                $xml = "<$name$elementNS>" . $contents . "</$name>";
6525 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...
6526
                $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':Array" ' . $this->getPrefixFromNamespace('http://schemas.xmlsoap.org/soap/encoding/') . ':arrayType="'
6527
                       . $this->getPrefixFromNamespace($this->getPrefix($typeDef['arrayType'])) . ':' . $this->getLocalPart($typeDef['arrayType']) . "[$rows$cols]\">" . $contents . "</$name>";
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...
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...
6528
            }
6529
        } elseif ($phpType === 'scalar') {
6530 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...
6531
                $elementNS = " xmlns=\"$ns\"";
6532
            } else {
6533
                if ($unqualified) {
6534
                    $elementNS = " xmlns=\"\"";
6535
                } else {
6536
                    $elementNS = '';
6537
                }
6538
            }
6539
            if ($use === 'literal') {
6540
                if ($forceType) {
6541
                    $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\">$value</$name>";
6542
                } else {
6543
                    $xml = "<$name$elementNS>$value</$name>";
6544
                }
6545
            } else {
6546
                $xml = "<$name$elementNS xsi:type=\"" . $this->getPrefixFromNamespace($ns) . ":$uqType\"$encodingStyle>$value</$name>";
6547
            }
6548
        }
6549
        $this->debug("in serializeType: returning: $xml");
6550
6551
        return $xml;
6552
    }
6553
6554
    /**
6555
     * serializes the attributes for a complexType
6556
     *
6557
     * @param  array  $typeDef our internal representation of an XML schema type (or element)
6558
     * @param  mixed  $value   a native PHP value (parameter value)
6559
     * @param  string $ns      the namespace of the type
6560
     * @param  string $uqType  the local part of the type
6561
     * @return string value serialized as an XML string
6562
     * @access private
6563
     */
6564
    public function serializeComplexTypeAttributes($typeDef, $value, $ns, $uqType)
6565
    {
6566
        $this->debug("serializeComplexTypeAttributes for XML Schema type $ns:$uqType");
6567
        $xml = '';
6568 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...
6569
            $nsx     = $this->getPrefix($typeDef['extensionBase']);
6570
            $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6571
            if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 6569 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...
6572
                $nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 6572 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...
6573
            }
6574
            if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6575
                $this->debug("serialize attributes for extension base $nsx:$uqTypex");
6576
                $xml .= $this->serializeComplexTypeAttributes($typeDefx, $value, $nsx, $uqTypex);
6577
            } else {
6578
                $this->debug("extension base $nsx:$uqTypex is not a supported type");
6579
            }
6580
        }
6581
        if (isset($typeDef['attrs']) && is_array($typeDef['attrs'])) {
6582
            $this->debug("serialize attributes for XML Schema type $ns:$uqType");
6583 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...
6584
                $xvalue = $value;
6585
            } elseif (is_object($value)) {
6586
                $xvalue = get_object_vars($value);
6587
            } else {
6588
                $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6589
                $xvalue = array();
6590
            }
6591
            foreach ($typeDef['attrs'] as $aName => $attrs) {
6592
                if (isset($xvalue['!' . $aName])) {
6593
                    $xname = '!' . $aName;
6594
                    $this->debug("value provided for attribute $aName with key $xname");
6595
                } elseif (isset($xvalue[$aName])) {
6596
                    $xname = $aName;
6597
                    $this->debug("value provided for attribute $aName with key $xname");
6598 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...
6599
                    $xname          = '!' . $aName;
6600
                    $xvalue[$xname] = $attrs['default'];
6601
                    $this->debug('use default value of ' . $xvalue[$aName] . ' for attribute ' . $aName);
6602
                } else {
6603
                    $xname = '';
6604
                    $this->debug("no value provided for attribute $aName");
6605
                }
6606
                if ($xname) {
6607
                    $xml .= " $aName=\"" . $this->expandEntities($xvalue[$xname]) . "\"";
6608
                }
6609
            }
6610
        } else {
6611
            $this->debug("no attributes to serialize for XML Schema type $ns:$uqType");
6612
        }
6613
6614
        return $xml;
6615
    }
6616
6617
    /**
6618
     * serializes the elements for a complexType
6619
     *
6620
     * @param  array       $typeDef       our internal representation of an XML schema type (or element)
6621
     * @param  mixed       $value         a native PHP value (parameter value)
6622
     * @param  string      $ns            the namespace of the type
6623
     * @param  string      $uqType        the local part of the type
6624
     * @param  string      $use           use for part (encoded|literal)
6625
     * @param  bool|string $encodingStyle SOAP encoding style for the value (if different than the enclosing style)
6626
     * @return string      value serialized as an XML string
6627
     * @access private
6628
     */
6629
    public function serializeComplexTypeElements(
6630
        $typeDef,
6631
        $value,
6632
        $ns,
6633
        $uqType,
6634
        $use = 'encoded',
6635
        $encodingStyle = false
6636
    ) {
6637
        $this->debug("in serializeComplexTypeElements for XML Schema type $ns:$uqType");
6638
        $xml = '';
6639 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...
6640
            $nsx     = $this->getPrefix($typeDef['extensionBase']);
6641
            $uqTypex = $this->getLocalPart($typeDef['extensionBase']);
6642
            if ($this->getNamespaceFromPrefix($nsx)) {
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getPrefix($typeDef['extensionBase']) on line 6640 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...
6643
                $nsx = $this->getNamespaceFromPrefix($nsx);
0 ignored issues
show
Security Bug introduced by
It seems like $nsx defined by $this->getNamespaceFromPrefix($nsx) on line 6643 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...
6644
            }
6645
            if ($typeDefx = $this->getTypeDef($uqTypex, $nsx)) {
6646
                $this->debug("serialize elements for extension base $nsx:$uqTypex");
6647
                $xml .= $this->serializeComplexTypeElements($typeDefx, $value, $nsx, $uqTypex, $use, $encodingStyle);
6648
            } else {
6649
                $this->debug("extension base $nsx:$uqTypex is not a supported type");
6650
            }
6651
        }
6652
        if (isset($typeDef['elements']) && is_array($typeDef['elements'])) {
6653
            $this->debug("in serializeComplexTypeElements, serialize elements for XML Schema type $ns:$uqType");
6654 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...
6655
                $xvalue = $value;
6656
            } elseif (is_object($value)) {
6657
                $xvalue = get_object_vars($value);
6658
            } else {
6659
                $this->debug("value is neither an array nor an object for XML Schema type $ns:$uqType");
6660
                $xvalue = array();
6661
            }
6662
            // toggle whether all elements are present - ideally should validate against schema
6663
            if (count($typeDef['elements']) != count($xvalue)) {
6664
                $optionals = true;
6665
            }
6666
            foreach ($typeDef['elements'] as $eName => $attrs) {
6667
                if (!isset($xvalue[$eName])) {
6668 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...
6669
                        $xvalue[$eName] = $attrs['default'];
6670
                        $this->debug('use default value of ' . $xvalue[$eName] . ' for element ' . $eName);
6671
                    }
6672
                }
6673
                // if user took advantage of a minOccurs=0, then only serialize named parameters
6674
                if (isset($optionals) && (!isset($xvalue[$eName]))
6675
                    && ((!isset($attrs['nillable']))
6676
                        || $attrs['nillable'] !== 'true')
6677
                ) {
6678
                    if (isset($attrs['minOccurs']) && $attrs['minOccurs'] <> '0') {
6679
                        $this->debug("apparent error: no value provided for element $eName with minOccurs=" . $attrs['minOccurs']);
6680
                    }
6681
                    // do nothing
6682
                    $this->debug("no value provided for complexType element $eName and element is not nillable, so serialize nothing");
6683
                } else {
6684
                    // get value
6685
                    if (isset($xvalue[$eName])) {
6686
                        $v = $xvalue[$eName];
6687
                    } else {
6688
                        $v = null;
6689
                    }
6690
                    if (isset($attrs['form'])) {
6691
                        $unqualified = ($attrs['form'] === 'unqualified');
6692
                    } else {
6693
                        $unqualified = false;
6694
                    }
6695
                    if (isset($attrs['maxOccurs']) && ($attrs['maxOccurs'] === 'unbounded' || $attrs['maxOccurs'] > 1)
6696
                        && isset($v)
6697
                        && is_array($v)
6698
                        && $this->isArraySimpleOrStruct($v) === 'arraySimple'
6699
                    ) {
6700
                        $vv = $v;
6701
                        foreach ($vv as $k => $v) {
6702
                            if (isset($attrs['type']) || isset($attrs['ref'])) {
6703
                                // serialize schema-defined type
6704
                                $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6705 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...
6706
                                // serialize generic type (can this ever really happen?)
6707
                                $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6708
                                $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6709
                            }
6710
                        }
6711
                    } else {
6712
                        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...
6713
                            // do nothing
6714
                        } elseif (null === $v && isset($attrs['nillable']) && $attrs['nillable'] === 'true') {
6715
                            // TODO: serialize a nil correctly, but for now serialize schema-defined type
6716
                            $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6717
                        } elseif (isset($attrs['type']) || isset($attrs['ref'])) {
6718
                            // serialize schema-defined type
6719
                            $xml .= $this->serializeType($eName, isset($attrs['type']) ? $attrs['type'] : $attrs['ref'], $v, $use, $encodingStyle, $unqualified);
6720 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...
6721
                            // serialize generic type (can this ever really happen?)
6722
                            $this->debug("calling serialize_val() for $v, $eName, false, false, false, false, $use");
6723
                            $xml .= $this->serialize_val($v, $eName, false, false, false, false, $use);
6724
                        }
6725
                    }
6726
                }
6727
            }
6728
        } else {
6729
            $this->debug("no elements to serialize for XML Schema type $ns:$uqType");
6730
        }
6731
6732
        return $xml;
6733
    }
6734
6735
    /**
6736
     * adds an XML Schema complex type to the WSDL types
6737
     *
6738
     * @param string $name
6739
     * @param string $typeClass       (complexType|simpleType|attribute)
6740
     * @param string $phpType         currently supported are array and struct (php assoc array)
6741
     * @param string $compositor      (all|sequence|choice)
6742
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6743
     * @param array  $elements        e.g. array ( name => array(name=>'',type=>'') )
6744
     * @param array  $attrs           e.g. array(array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'xsd:string[]'))
6745
     * @param string $arrayType       as namespace:name (xsd:string)
6746
     * @see    nusoap_xmlschema
6747
     * @access public
6748
     */
6749
    public function addComplexType(
6750
        $name,
6751
        $typeClass = 'complexType',
6752
        $phpType = 'array',
6753
        $compositor = '',
6754
        $restrictionBase = '',
6755
        $elements = array(),
6756
        $attrs = array(),
6757
        $arrayType = ''
6758
    ) {
6759
        if (count($elements) > 0) {
6760
            $eElements = array();
6761 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...
6762
                // expand each element
6763
                $ee = array();
6764
                foreach ($e as $k => $v) {
6765
                    $k      = strpos($k, ':') ? $this->expandQname($k) : $k;
6766
                    $v      = strpos($v, ':') ? $this->expandQname($v) : $v;
6767
                    $ee[$k] = $v;
6768
                }
6769
                $eElements[$n] = $ee;
6770
            }
6771
            $elements = $eElements;
6772
        }
6773
6774
        if (count($attrs) > 0) {
6775 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...
6776
                // expand each attribute
6777
                foreach ($a as $k => $v) {
6778
                    $k      = strpos($k, ':') ? $this->expandQname($k) : $k;
6779
                    $v      = strpos($v, ':') ? $this->expandQname($v) : $v;
6780
                    $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...
6781
                }
6782
                $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...
6783
            }
6784
            $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...
6785
        }
6786
6787
        $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6788
        $arrayType       = strpos($arrayType, ':') ? $this->expandQname($arrayType) : $arrayType;
6789
6790
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6791
        $this->schemas[$typens][0]->addComplexType($name, $typeClass, $phpType, $compositor, $restrictionBase, $elements, $attrs, $arrayType);
6792
    }
6793
6794
    /**
6795
     * adds an XML Schema simple type to the WSDL types
6796
     *
6797
     * @param string $name
6798
     * @param string $restrictionBase namespace:name (http://schemas.xmlsoap.org/soap/encoding/:Array)
6799
     * @param string $typeClass       (should always be simpleType)
6800
     * @param string $phpType         (should always be scalar)
6801
     * @param array  $enumeration     array of values
6802
     * @see    nusoap_xmlschema
6803
     * @access public
6804
     */
6805
    public function addSimpleType(
6806
        $name,
6807
        $restrictionBase = '',
6808
        $typeClass = 'simpleType',
6809
        $phpType = 'scalar',
6810
        $enumeration = array()
6811
    ) {
6812
        $restrictionBase = strpos($restrictionBase, ':') ? $this->expandQname($restrictionBase) : $restrictionBase;
6813
6814
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6815
        $this->schemas[$typens][0]->addSimpleType($name, $restrictionBase, $typeClass, $phpType, $enumeration);
6816
    }
6817
6818
    /**
6819
     * adds an element to the WSDL types
6820
     *
6821
     * @param array $attrs attributes that must include name and type
6822
     * @see    nusoap_xmlschema
6823
     * @access public
6824
     */
6825
    public function addElement($attrs)
6826
    {
6827
        $typens = isset($this->namespaces['types']) ? $this->namespaces['types'] : $this->namespaces['tns'];
6828
        $this->schemas[$typens][0]->addElement($attrs);
6829
    }
6830
6831
    /**
6832
     * register an operation with the server
6833
     *
6834
     * @param  string      $name          operation (method) name
6835
     * @param  array|bool  $in            assoc array of input values: key = param name, value = param type
6836
     * @param  array|bool  $out           assoc array of output values: key = param name, value = param type
6837
     * @param  bool|string $namespace     optional The namespace for the operation
6838
     * @param  bool|string $soapaction    optional The soapaction for the operation
6839
     * @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
6840
     * @param  string      $use           (encoded|literal) optional The use for the parameters (cannot mix right now)
6841
     * @param  string      $documentation optional The description to include in the WSDL
6842
     * @param  string      $encodingStyle optional (usually 'http://schemas.xmlsoap.org/soap/encoding/' for encoded)
6843
     * @return bool
6844
     * @access public
6845
     */
6846
    public function addOperation(
6847
        $name,
6848
        $in = false,
6849
        $out = false,
6850
        $namespace = false,
6851
        $soapaction = false,
6852
        $style = 'rpc',
6853
        $use = 'encoded',
6854
        $documentation = '',
6855
        $encodingStyle = ''
6856
    ) {
6857
        if ($use === 'encoded' && $encodingStyle == '') {
6858
            $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
6859
        }
6860
6861
        if ($style === 'document') {
6862
            $elements = array();
6863 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...
6864
                $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6865
            }
6866
            $this->addComplexType($name . 'RequestType', 'complexType', 'struct', 'all', '', $elements);
6867
            $this->addElement(array('name' => $name, 'type' => $name . 'RequestType'));
6868
            $in = array('parameters' => 'tns:' . $name . '^');
6869
6870
            $elements = array();
6871 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...
6872
                $elements[$n] = array('name' => $n, 'type' => $t, 'form' => 'unqualified');
6873
            }
6874
            $this->addComplexType($name . 'ResponseType', 'complexType', 'struct', 'all', '', $elements);
6875
            $this->addElement(array(
6876
                                  'name' => $name . 'Response',
6877
                                  'type' => $name . 'ResponseType',
6878
                                  'form' => 'qualified'
6879
                              ));
6880
            $out = array('parameters' => 'tns:' . $name . 'Response' . '^');
6881
        }
6882
6883
        // get binding
6884
        $this->bindings[$this->serviceName . 'Binding']['operations'][$name] = array(
6885
            'name'          => $name,
6886
            'binding'       => $this->serviceName . 'Binding',
6887
            'endpoint'      => $this->endpoint,
6888
            'soapAction'    => $soapaction,
6889
            'style'         => $style,
6890
            'input'         => array(
6891
                'use'           => $use,
6892
                'namespace'     => $namespace,
6893
                'encodingStyle' => $encodingStyle,
6894
                'message'       => $name . 'Request',
6895
                'parts'         => $in
6896
            ),
6897
            'output'        => array(
6898
                'use'           => $use,
6899
                'namespace'     => $namespace,
6900
                'encodingStyle' => $encodingStyle,
6901
                'message'       => $name . 'Response',
6902
                'parts'         => $out
6903
            ),
6904
            'namespace'     => $namespace,
6905
            'transport'     => 'http://schemas.xmlsoap.org/soap/http',
6906
            'documentation' => $documentation
6907
        );
6908
        // add portTypes
6909
        // add messages
6910 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...
6911
            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...
6912
                if (strpos($pType, ':')) {
6913
                    $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...
6914
                }
6915
                $this->messages[$name . 'Request'][$pName] = $pType;
6916
            }
6917
        } else {
6918
            $this->messages[$name . 'Request'] = '0';
6919
        }
6920 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...
6921
            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...
6922
                if (strpos($pType, ':')) {
6923
                    $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...
6924
                }
6925
                $this->messages[$name . 'Response'][$pName] = $pType;
6926
            }
6927
        } else {
6928
            $this->messages[$name . 'Response'] = '0';
6929
        }
6930
6931
        return true;
6932
    }
6933
}
6934
6935
?><?php
6936
6937
/**
6938
 *
6939
 * nusoap_parser class parses SOAP XML messages into native PHP values
6940
 *
6941
 * @author   Dietrich Ayala <[email protected]>
6942
 * @author   Scott Nichol <[email protected]>
6943
 * @access   public
6944
 */
6945
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...
6946
{
6947
    public $xml                   = '';
6948
    public $xml_encoding          = '';
6949
    public $method                = '';
6950
    public $root_struct           = '';
6951
    public $root_struct_name      = '';
6952
    public $root_struct_namespace = '';
6953
    public $root_header           = '';
6954
    public $document              = '';            // incoming SOAP body (text)
6955
    // determines where in the message we are (envelope,header,body,method)
6956
    public $status            = '';
6957
    public $position          = 0;
6958
    public $depth             = 0;
6959
    public $default_namespace = '';
6960
    public $namespaces        = array();
6961
    public $message           = array();
6962
    public $parent            = '';
6963
    public $fault             = false;
6964
    public $fault_code        = '';
6965
    public $fault_str         = '';
6966
    public $fault_detail      = '';
6967
    public $depth_array       = array();
6968
    public $debug_flag        = true;
6969
    public $soapresponse      = null;    // parsed SOAP Body
6970
    public $soapheader        = null;        // parsed SOAP Header
6971
    public $responseHeaders   = '';    // incoming SOAP headers (text)
6972
    public $body_position     = 0;
6973
    // for multiref parsing:
6974
    // array of id => pos
6975
    public $ids = array();
6976
    // array of id => hrefs => pos
6977
    public $multirefs = array();
6978
    // toggle for auto-decoding element content
6979
    public $decode_utf8 = true;
6980
6981
    /**
6982
     * constructor that actually does the parsing
6983
     *
6984
     * @param string      $xml         SOAP message
6985
     * @param string      $encoding    character encoding scheme of message
6986
     * @param string      $method      method for which XML is parsed (unused?)
6987
     * @param bool|string $decode_utf8 whether to decode UTF-8 to ISO-8859-1
6988
     * @access   public
6989
     * @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...
6990
     */
6991
    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...
6992
    {
6993
        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...
6994
        $this->xml          = $xml;
6995
        $this->xml_encoding = $encoding;
6996
        $this->method       = $method;
6997
        $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...
6998
6999
        // Check whether content has been read.
7000
        if (!empty($xml)) {
7001
            // Check XML encoding
7002
            $pos_xml = strpos($xml, '<?xml');
7003
            if ($pos_xml !== false) {
7004
                $xml_decl = substr($xml, $pos_xml, strpos($xml, '?>', $pos_xml + 2) - $pos_xml + 1);
7005
                if (preg_match("/encoding=[\"']([^\"']*)[\"']/", $xml_decl, $res)) {
7006
                    $xml_encoding = $res[1];
7007
                    if (strtoupper($xml_encoding) != $encoding) {
7008
                        $err = "Charset from HTTP Content-Type '" . $encoding . "' does not match encoding from XML declaration '" . $xml_encoding . "'";
7009
                        $this->debug($err);
7010
                        if ($encoding !== 'ISO-8859-1' || strtoupper($xml_encoding) !== 'UTF-8') {
7011
                            $this->setError($err);
7012
7013
                            return;
7014
                        }
7015
                        // when HTTP says ISO-8859-1 (the default) and XML says UTF-8 (the typical), assume the other endpoint is just sloppy and proceed
7016
                    } else {
7017
                        $this->debug('Charset from HTTP Content-Type matches encoding from XML declaration');
7018
                    }
7019
                } else {
7020
                    $this->debug('No encoding specified in XML declaration');
7021
                }
7022
            } else {
7023
                $this->debug('No XML declaration');
7024
            }
7025
            $this->debug('Entering nusoap_parser(), length=' . strlen($xml) . ', encoding=' . $encoding);
7026
            // Create an XML parser - why not xml_parser_create_ns?
7027
            $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...
7028
            // Set the options for parsing the XML data.
7029
            //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...
7030
            xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
7031
            xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, $this->xml_encoding);
7032
            // Set the object for the parser.
7033
            xml_set_object($this->parser, $this);
7034
            // Set the element handlers for the parser.
7035
            xml_set_element_handler($this->parser, 'start_element', 'end_element');
7036
            xml_set_character_data_handler($this->parser, 'character_data');
7037
7038
            // Parse the XML file.
7039
            if (!xml_parse($this->parser, $xml, true)) {
7040
                // Display an error message.
7041
                $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)));
7042
                $this->debug($err);
7043
                $this->debug("XML payload:\n" . $xml);
7044
                $this->setError($err);
7045
            } else {
7046
                $this->debug('in nusoap_parser ctor, message:');
7047
                $this->appendDebug($this->varDump($this->message));
7048
                $this->debug('parsed successfully, found root struct: ' . $this->root_struct . ' of name ' . $this->root_struct_name);
7049
                // get final value
7050
                $this->soapresponse = $this->message[$this->root_struct]['result'];
7051
                // get header value
7052
                if ($this->root_header != '' && isset($this->message[$this->root_header]['result'])) {
7053
                    $this->soapheader = $this->message[$this->root_header]['result'];
7054
                }
7055
                // resolve hrefs/ids
7056
                if (count($this->multirefs) > 0) {
7057
                    foreach ($this->multirefs as $id => $hrefs) {
7058
                        $this->debug('resolving multirefs for id: ' . $id);
7059
                        $idVal = $this->buildVal($this->ids[$id]);
7060
                        if (is_array($idVal) && isset($idVal['!id'])) {
7061
                            unset($idVal['!id']);
7062
                        }
7063
                        foreach ($hrefs as $refPos => $ref) {
7064
                            $this->debug('resolving href at pos ' . $refPos);
7065
                            $this->multirefs[$id][$refPos] = $idVal;
7066
                        }
7067
                    }
7068
                }
7069
            }
7070
            xml_parser_free($this->parser);
7071
        } else {
7072
            $this->debug('xml was empty, didn\'t parse!');
7073
            $this->setError('xml was empty, didn\'t parse!');
7074
        }
7075
    }
7076
7077
    /**
7078
     * start-element handler
7079
     *
7080
     * @param resource $parser XML parser object
7081
     * @param string   $name   element name
7082
     * @param array    $attrs  associative array of attributes
7083
     * @access   private
7084
     */
7085
    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...
7086
    {
7087
        // position in a total number of elements, starting from 0
7088
        // update class level pos
7089
        $pos = $this->position++;
7090
        // and set mine
7091
        $this->message[$pos] = array('pos' => $pos, 'children' => '', 'cdata' => '');
7092
        // depth = how many levels removed from root?
7093
        // set mine as current global depth and increment global depth value
7094
        $this->message[$pos]['depth'] = $this->depth++;
7095
7096
        // else add self as child to whoever the current parent is
7097
        if ($pos != 0) {
7098
            $this->message[$this->parent]['children'] .= '|' . $pos;
7099
        }
7100
        // set my parent
7101
        $this->message[$pos]['parent'] = $this->parent;
7102
        // set self as current parent
7103
        $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...
7104
        // set self as current value for this depth
7105
        $this->depth_array[$this->depth] = $pos;
7106
        // get element prefix
7107 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...
7108
            // get ns prefix
7109
            $prefix = substr($name, 0, strpos($name, ':'));
7110
            // get unqualified name
7111
            $name = substr(strstr($name, ':'), 1);
7112
        }
7113
        // set status
7114
        if ($name === 'Envelope' && $this->status == '') {
7115
            $this->status = 'envelope';
7116
        } elseif ($name === 'Header' && $this->status === 'envelope') {
7117
            $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...
7118
            $this->status      = 'header';
7119
        } elseif ($name === 'Body' && $this->status === 'envelope') {
7120
            $this->status        = 'body';
7121
            $this->body_position = $pos;
7122
            // set method
7123
        } elseif ($this->status === 'body' && $pos == ($this->body_position + 1)) {
7124
            $this->status                = 'method';
7125
            $this->root_struct_name      = $name;
7126
            $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...
7127
            $this->message[$pos]['type'] = 'struct';
7128
            $this->debug("found root struct $this->root_struct_name, pos $this->root_struct");
7129
        }
7130
        // set my status
7131
        $this->message[$pos]['status'] = $this->status;
7132
        // set name
7133
        $this->message[$pos]['name'] = htmlspecialchars($name);
7134
        // set attrs
7135
        $this->message[$pos]['attrs'] = $attrs;
7136
7137
        // loop through atts, logging ns and type declarations
7138
        $attstr = '';
7139
        foreach ($attrs as $key => $value) {
7140
            $key_prefix    = $this->getPrefix($key);
7141
            $key_localpart = $this->getLocalPart($key);
7142
            // if ns declarations, add to class level array of valid namespaces
7143
            if ($key_prefix === 'xmlns') {
7144
                if (preg_match('/^http:\/\/www.w3.org\/[0-9]{4}\/XMLSchema$/', $value)) {
7145
                    $this->XMLSchemaVersion  = $value;
7146
                    $this->namespaces['xsd'] = $this->XMLSchemaVersion;
7147
                    $this->namespaces['xsi'] = $this->XMLSchemaVersion . '-instance';
7148
                }
7149
                $this->namespaces[$key_localpart] = $value;
7150
                // set method namespace
7151
                if ($name == $this->root_struct_name) {
7152
                    $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...
7153
                }
7154
                // if it's a type declaration, set type
7155
            } elseif ($key_localpart === 'type') {
7156
                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...
7157
                    // do nothing: already processed arrayType
7158
                } else {
7159
                    $value_prefix                      = $this->getPrefix($value);
7160
                    $value_localpart                   = $this->getLocalPart($value);
7161
                    $this->message[$pos]['type']       = $value_localpart;
7162
                    $this->message[$pos]['typePrefix'] = $value_prefix;
7163
                    if (isset($this->namespaces[$value_prefix])) {
7164
                        $this->message[$pos]['type_namespace'] = $this->namespaces[$value_prefix];
7165
                    } elseif (isset($attrs['xmlns:' . $value_prefix])) {
7166
                        $this->message[$pos]['type_namespace'] = $attrs['xmlns:' . $value_prefix];
7167
                    }
7168
                    // should do something here with the namespace of specified type?
7169
                }
7170
            } elseif ($key_localpart === 'arrayType') {
7171
                $this->message[$pos]['type'] = 'array';
7172
                /* do arrayType ereg here
7173
                [1]    arrayTypeValue    ::=    atype asize
7174
                [2]    atype    ::=    QName rank*
7175
                [3]    rank    ::=    '[' (',')* ']'
7176
                [4]    asize    ::=    '[' length~ ']'
7177
                [5]    length    ::=    nextDimension* Digit+
7178
                [6]    nextDimension    ::=    Digit+ ','
7179
                */
7180
                $expr = '/([A-Za-z0-9_]+):([A-Za-z]+[A-Za-z0-9_]+)\[([0-9]+),?([0-9]*)\]/';
7181
                if (preg_match($expr, $value, $regs)) {
7182
                    $this->message[$pos]['typePrefix']      = $regs[1];
7183
                    $this->message[$pos]['arrayTypePrefix'] = $regs[1];
7184
                    if (isset($this->namespaces[$regs[1]])) {
7185
                        $this->message[$pos]['arrayTypeNamespace'] = $this->namespaces[$regs[1]];
7186
                    } elseif (isset($attrs['xmlns:' . $regs[1]])) {
7187
                        $this->message[$pos]['arrayTypeNamespace'] = $attrs['xmlns:' . $regs[1]];
7188
                    }
7189
                    $this->message[$pos]['arrayType'] = $regs[2];
7190
                    $this->message[$pos]['arraySize'] = $regs[3];
7191
                    $this->message[$pos]['arrayCols'] = $regs[4];
7192
                }
7193
                // specifies nil value (or not)
7194
            } elseif ($key_localpart === 'nil') {
7195
                $this->message[$pos]['nil'] = ($value === 'true' || $value == '1');
7196
                // some other attribute
7197
            } elseif ($key !== 'href' && $key !== 'xmlns' && $key_localpart !== 'encodingStyle'
7198
                      && $key_localpart !== 'root'
7199
            ) {
7200
                $this->message[$pos]['xattrs']['!' . $key] = $value;
7201
            }
7202
7203
            if ($key === 'xmlns') {
7204
                $this->default_namespace = $value;
7205
            }
7206
            // log id
7207
            if ($key === 'id') {
7208
                $this->ids[$value] = $pos;
7209
            }
7210
            // root
7211
            if ($key_localpart === 'root' && $value == 1) {
7212
                $this->status           = 'method';
7213
                $this->root_struct_name = $name;
7214
                $this->root_struct      = $pos;
7215
                $this->debug("found root struct $this->root_struct_name, pos $pos");
7216
            }
7217
            // for doclit
7218
            $attstr .= " $key=\"$value\"";
7219
        }
7220
        // get namespace - must be done after namespace atts are processed
7221
        if (isset($prefix)) {
7222
            $this->message[$pos]['namespace'] = $this->namespaces[$prefix];
7223
            $this->default_namespace          = $this->namespaces[$prefix];
7224
        } else {
7225
            $this->message[$pos]['namespace'] = $this->default_namespace;
7226
        }
7227 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...
7228
            if ($this->root_header != $pos) {
7229
                $this->responseHeaders .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
7230
            }
7231
        } elseif ($this->root_struct_name != '') {
7232
            $this->document .= '<' . (isset($prefix) ? $prefix . ':' : '') . "$name$attstr>";
7233
        }
7234
    }
7235
7236
    /**
7237
     * end-element handler
7238
     *
7239
     * @param resource $parser XML parser object
7240
     * @param string   $name   element name
7241
     * @access   private
7242
     */
7243
    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...
7244
    {
7245
        // position of current element is equal to the last value left in depth_array for my depth
7246
        $pos = $this->depth_array[$this->depth--];
7247
7248
        // get element prefix
7249 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...
7250
            // get ns prefix
7251
            $prefix = substr($name, 0, strpos($name, ':'));
7252
            // get unqualified name
7253
            $name = substr(strstr($name, ':'), 1);
7254
        }
7255
7256
        // build to native type
7257
        if (isset($this->body_position) && $pos > $this->body_position) {
7258
            // deal w/ multirefs
7259
            if (isset($this->message[$pos]['attrs']['href'])) {
7260
                // get id
7261
                $id = substr($this->message[$pos]['attrs']['href'], 1);
7262
                // add placeholder to href array
7263
                $this->multirefs[$id][$pos] = 'placeholder';
7264
                // add set a reference to it as the result value
7265
                $this->message[$pos]['result'] = $this->multirefs[$id][$pos];
7266
                // build complexType values
7267
            } elseif ($this->message[$pos]['children'] != '') {
7268
                // if result has already been generated (struct/array)
7269
                if (!isset($this->message[$pos]['result'])) {
7270
                    $this->message[$pos]['result'] = $this->buildVal($pos);
7271
                }
7272
                // build complexType values of attributes and possibly simpleContent
7273
            } elseif (isset($this->message[$pos]['xattrs'])) {
7274
                if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7275
                    $this->message[$pos]['xattrs']['!'] = null;
7276
                } elseif (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7277
                    if (isset($this->message[$pos]['type'])) {
7278
                        $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'] : '');
7279 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...
7280
                        $parent = $this->message[$pos]['parent'];
7281
                        if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7282
                            && isset($this->message[$parent]['arrayType'])
7283
                        ) {
7284
                            $this->message[$pos]['xattrs']['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'],
7285
                                                                                      isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7286
                        } else {
7287
                            $this->message[$pos]['xattrs']['!'] = $this->message[$pos]['cdata'];
7288
                        }
7289
                    }
7290
                }
7291
                $this->message[$pos]['result'] = $this->message[$pos]['xattrs'];
7292
                // set value of simpleType (or nil complexType)
7293
            } else {
7294
                //$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...
7295
                if (isset($this->message[$pos]['nil']) && $this->message[$pos]['nil']) {
7296
                    $this->message[$pos]['xattrs']['!'] = null;
7297
                } elseif (isset($this->message[$pos]['type'])) {
7298
                    $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'] : '');
7299 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...
7300
                    $parent = $this->message[$pos]['parent'];
7301
                    if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7302
                        && isset($this->message[$parent]['arrayType'])
7303
                    ) {
7304
                        $this->message[$pos]['result'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'],
7305
                                                                             isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7306
                    } else {
7307
                        $this->message[$pos]['result'] = $this->message[$pos]['cdata'];
7308
                    }
7309
                }
7310
7311
                /* add value to parent's result, if parent is struct/array
7312
                $parent = $this->message[$pos]['parent'];
7313
                if ($this->message[$parent]['type'] != 'map') {
7314
                    if (strtolower($this->message[$parent]['type']) == 'array') {
7315
                        $this->message[$parent]['result'][] = $this->message[$pos]['result'];
7316
                    } else {
7317
                        $this->message[$parent]['result'][$this->message[$pos]['name']] = $this->message[$pos]['result'];
7318
                    }
7319
                }
7320
                */
7321
            }
7322
        }
7323
7324
        // for doclit
7325 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...
7326
            if ($this->root_header != $pos) {
7327
                $this->responseHeaders .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7328
            }
7329
        } elseif ($pos >= $this->root_struct) {
7330
            $this->document .= '</' . (isset($prefix) ? $prefix . ':' : '') . "$name>";
7331
        }
7332
        // switch status
7333
        if ($pos == $this->root_struct) {
7334
            $this->status                = 'body';
7335
            $this->root_struct_namespace = $this->message[$pos]['namespace'];
7336
        } elseif ($pos == $this->root_header) {
7337
            $this->status = 'envelope';
7338
        } elseif ($name === 'Body' && $this->status === 'body') {
7339
            $this->status = 'envelope';
7340
        } elseif ($name === 'Header' && $this->status === 'header') { // will never happen
7341
            $this->status = 'envelope';
7342
        } elseif ($name === 'Envelope' && $this->status === 'envelope') {
7343
            $this->status = '';
7344
        }
7345
        // set parent back to my parent
7346
        $this->parent = $this->message[$pos]['parent'];
7347
    }
7348
7349
    /**
7350
     * element content handler
7351
     *
7352
     * @param resource $parser XML parser object
7353
     * @param string   $data   element content
7354
     * @access   private
7355
     */
7356
    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...
7357
    {
7358
        $pos = $this->depth_array[$this->depth];
7359
        if ($this->xml_encoding === 'UTF-8') {
7360
            // TODO: add an option to disable this for folks who want
7361
            // raw UTF-8 that, e.g., might not map to iso-8859-1
7362
            // TODO: this can also be handled with xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, "ISO-8859-1");
7363
            if ($this->decode_utf8) {
7364
                $data = utf8_decode($data);
7365
            }
7366
        }
7367
        $this->message[$pos]['cdata'] .= $data;
7368
        // for doclit
7369
        if ($this->status === 'header') {
7370
            $this->responseHeaders .= $data;
7371
        } else {
7372
            $this->document .= $data;
7373
        }
7374
    }
7375
7376
    /**
7377
     * get the parsed message (SOAP Body)
7378
     *
7379
     * @return mixed
7380
     * @access       public
7381
     * @deprecated   use get_soapbody instead
7382
     */
7383
    public function get_response()
7384
    {
7385
        return $this->soapresponse;
7386
    }
7387
7388
    /**
7389
     * get the parsed SOAP Body (NULL if there was none)
7390
     *
7391
     * @return mixed
7392
     * @access   public
7393
     */
7394
    public function get_soapbody()
7395
    {
7396
        return $this->soapresponse;
7397
    }
7398
7399
    /**
7400
     * get the parsed SOAP Header (NULL if there was none)
7401
     *
7402
     * @return mixed
7403
     * @access   public
7404
     */
7405
    public function get_soapheader()
7406
    {
7407
        return $this->soapheader;
7408
    }
7409
7410
    /**
7411
     * get the unparsed SOAP Header
7412
     *
7413
     * @return string XML or empty if no Header
7414
     * @access   public
7415
     */
7416
    public function getHeaders()
7417
    {
7418
        return $this->responseHeaders;
7419
    }
7420
7421
    /**
7422
     * decodes simple types into PHP variables
7423
     *
7424
     * @param  string $value  value to decode
7425
     * @param  string $type   XML type to decode
7426
     * @param  string $typens XML type namespace to decode
7427
     * @return mixed  PHP value
7428
     * @access   private
7429
     */
7430
    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...
7431
    {
7432
        // TODO: use the namespace!
7433
        if ((!isset($type)) || $type === 'string' || $type === 'long' || $type === 'unsignedLong') {
7434
            return (string)$value;
7435
        }
7436
        if ($type === 'int' || $type === 'integer' || $type === 'short' || $type === 'byte') {
7437
            return (int)$value;
7438
        }
7439
        if ($type === 'float' || $type === 'double' || $type === 'decimal') {
7440
            return (double)$value;
7441
        }
7442
        if ($type === 'boolean') {
7443
            if (strtolower($value) === 'false' || strtolower($value) === 'f') {
7444
                return false;
7445
            }
7446
7447
            return (boolean)$value;
7448
        }
7449
        if ($type === 'base64' || $type === 'base64Binary') {
7450
            $this->debug('Decode base64 value');
7451
7452
            return base64_decode($value);
7453
        }
7454
        // obscure numeric types
7455
        if ($type === 'nonPositiveInteger'
7456
            || $type === 'negativeInteger'
7457
            || $type === 'nonNegativeInteger'
7458
            || $type === 'positiveInteger'
7459
            || $type === 'unsignedInt'
7460
            || $type === 'unsignedShort'
7461
            || $type === 'unsignedByte'
7462
        ) {
7463
            return (int)$value;
7464
        }
7465
        // bogus: parser treats array with no elements as a simple type
7466
        if ($type === 'array') {
7467
            return array();
7468
        }
7469
7470
        // everything else
7471
        return (string)$value;
7472
    }
7473
7474
    /**
7475
     * builds response structures for compound values (arrays/structs)
7476
     * and scalars
7477
     *
7478
     * @param  integer $pos position in node tree
7479
     * @return mixed   PHP value
7480
     * @access   private
7481
     */
7482
    public function buildVal($pos)
7483
    {
7484 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...
7485
            $this->message[$pos]['type'] = '';
7486
        }
7487
        $this->debug('in buildVal() for ' . $this->message[$pos]['name'] . "(pos $pos) of type " . $this->message[$pos]['type']);
7488
        // if there are children...
7489
        if ($this->message[$pos]['children'] != '') {
7490
            $this->debug('in buildVal, there are children');
7491
            $children = explode('|', $this->message[$pos]['children']);
7492
            array_shift($children); // knock off empty
7493
            // md array
7494
            if (isset($this->message[$pos]['arrayCols']) && $this->message[$pos]['arrayCols'] != '') {
7495
                $r = 0; // rowcount
7496
                $c = 0; // colcount
7497
                foreach ($children as $child_pos) {
7498
                    $this->debug("in buildVal, got an MD array element: $r, $c");
7499
                    $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...
7500
                    ++$c;
7501
                    if ($c == $this->message[$pos]['arrayCols']) {
7502
                        $c = 0;
7503
                        ++$r;
7504
                    }
7505
                }
7506
                // array
7507
            } elseif ($this->message[$pos]['type'] === 'array' || $this->message[$pos]['type'] === 'Array') {
7508
                $this->debug('in buildVal, adding array ' . $this->message[$pos]['name']);
7509
                foreach ($children as $child_pos) {
7510
                    $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...
7511
                }
7512
                // apache Map type: java hashtable
7513
            } elseif ($this->message[$pos]['type'] === 'Map'
7514
                      && $this->message[$pos]['type_namespace'] === 'http://xml.apache.org/xml-soap'
7515
            ) {
7516
                $this->debug('in buildVal, Java Map ' . $this->message[$pos]['name']);
7517
                foreach ($children as $child_pos) {
7518
                    $kv                                       = explode('|', $this->message[$child_pos]['children']);
7519
                    $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...
7520
                }
7521
                // generic compound type
7522
                //} 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...
7523
            } else {
7524
                // Apache Vector type: treat as an array
7525
                $this->debug('in buildVal, adding Java Vector or generic compound type ' . $this->message[$pos]['name']);
7526
                if ($this->message[$pos]['type'] === 'Vector'
7527
                    && $this->message[$pos]['type_namespace'] === 'http://xml.apache.org/xml-soap'
7528
                ) {
7529
                    $notstruct = 1;
7530
                } else {
7531
                    $notstruct = 0;
7532
                }
7533
                //
7534
                foreach ($children as $child_pos) {
7535
                    if ($notstruct) {
7536
                        $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...
7537
                    } else {
7538
                        if (isset($params[$this->message[$child_pos]['name']])) {
7539
                            // de-serialize repeated element name into an array
7540
                            if ((!is_array($params[$this->message[$child_pos]['name']]))
7541
                                || (!isset($params[$this->message[$child_pos]['name']][0]))
7542
                            ) {
7543
                                $params[$this->message[$child_pos]['name']] = array($params[$this->message[$child_pos]['name']]);
7544
                            }
7545
                            $params[$this->message[$child_pos]['name']][] = $this->message[$child_pos]['result'];
7546
                        } else {
7547
                            $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...
7548
                        }
7549
                    }
7550
                }
7551
            }
7552
            if (isset($this->message[$pos]['xattrs'])) {
7553
                $this->debug('in buildVal, handling attributes');
7554
                foreach ($this->message[$pos]['xattrs'] as $n => $v) {
7555
                    $params[$n] = $v;
7556
                }
7557
            }
7558
            // handle simpleContent
7559
            if (isset($this->message[$pos]['cdata']) && trim($this->message[$pos]['cdata']) != '') {
7560
                $this->debug('in buildVal, handling simpleContent');
7561
                if (isset($this->message[$pos]['type'])) {
7562
                    $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7563
                } else {
7564
                    $parent = $this->message[$pos]['parent'];
7565
                    if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7566
                        && isset($this->message[$parent]['arrayType'])
7567
                    ) {
7568
                        $params['!'] = $this->decodeSimple($this->message[$pos]['cdata'], $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7569
                    } else {
7570
                        $params['!'] = $this->message[$pos]['cdata'];
7571
                    }
7572
                }
7573
            }
7574
            $ret = is_array($params) ? $params : array();
7575
            $this->debug('in buildVal, return:');
7576
            $this->appendDebug($this->varDump($ret));
7577
7578
            return $ret;
7579
        } else {
7580
            $this->debug('in buildVal, no children, building scalar');
7581
            $cdata = isset($this->message[$pos]['cdata']) ? $this->message[$pos]['cdata'] : '';
7582
            if (isset($this->message[$pos]['type'])) {
7583
                $ret = $this->decodeSimple($cdata, $this->message[$pos]['type'], isset($this->message[$pos]['type_namespace']) ? $this->message[$pos]['type_namespace'] : '');
7584
                $this->debug("in buildVal, return: $ret");
7585
7586
                return $ret;
7587
            }
7588
            $parent = $this->message[$pos]['parent'];
7589
            if (isset($this->message[$parent]['type']) && ($this->message[$parent]['type'] === 'array')
7590
                && isset($this->message[$parent]['arrayType'])
7591
            ) {
7592
                $ret = $this->decodeSimple($cdata, $this->message[$parent]['arrayType'], isset($this->message[$parent]['arrayTypeNamespace']) ? $this->message[$parent]['arrayTypeNamespace'] : '');
7593
                $this->debug("in buildVal, return: $ret");
7594
7595
                return $ret;
7596
            }
7597
            $ret = $this->message[$pos]['cdata'];
7598
            $this->debug("in buildVal, return: $ret");
7599
7600
            return $ret;
7601
        }
7602
    }
7603
}
7604
7605
/**
7606
 * Backward compatibility
7607
 */
7608
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...
7609
{
7610
}
7611
7612
?><?php
7613
7614
/**
7615
 *
7616
 * [nu]soapclient higher level class for easy usage.
7617
 *
7618
 * usage:
7619
 *
7620
 * // instantiate client with server info
7621
 * $soapclient = new nusoap_client( string path [ ,mixed wsdl] );
7622
 *
7623
 * // call method, get results
7624
 * echo $soapclient->call( string methodname [ ,array parameters] );
7625
 *
7626
 * // bye bye client
7627
 * unset($soapclient);
7628
 *
7629
 * @author   Dietrich Ayala <[email protected]>
7630
 * @author   Scott Nichol <[email protected]>
7631
 * @access   public
7632
 */
7633
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...
7634
{
7635
    public $username             = '';                // Username for HTTP authentication
7636
    public $password             = '';                // Password for HTTP authentication
7637
    public $authtype             = '';                // Type of HTTP authentication
7638
    public $certRequest          = array();        // Certificate for HTTP SSL authentication
7639
    public $requestHeaders       = false;    // SOAP headers in request (text)
7640
    public $responseHeaders      = '';        // SOAP headers from response (incomplete namespace resolution) (text)
7641
    public $responseHeader       = null;        // SOAP Header from response (parsed)
7642
    public $document             = '';                // SOAP body response portion (incomplete namespace resolution) (text)
7643
    public $endpoint;
7644
    public $forceEndpoint        = '';        // overrides WSDL endpoint
7645
    public $proxyhost            = '';
7646
    public $proxyport            = '';
7647
    public $proxyusername        = '';
7648
    public $proxypassword        = '';
7649
    public $portName             = '';                // port name to use in WSDL
7650
    public $xml_encoding         = '';            // character set encoding of incoming (response) messages
7651
    public $http_encoding        = false;
7652
    public $timeout              = 0;                // HTTP connection timeout
7653
    public $response_timeout     = 30;        // HTTP response timeout
7654
    public $endpointType         = '';            // soap|wsdl, empty for WSDL initialization error
7655
    public $persistentConnection = false;
7656
    public $defaultRpcParams     = false;    // This is no longer used
7657
    public $request              = '';                // HTTP request
7658
    public $response             = '';                // HTTP response
7659
    public $responseData         = '';            // SOAP payload of response
7660
    public $cookies              = array();            // Cookies from response or for request
7661
    public $decode_utf8          = true;        // toggles whether the parser decodes element content w/ utf8_decode()
7662
    public $operations           = array();        // WSDL operations, empty for WSDL initialization error
7663
    public $curl_options         = array();    // User-specified cURL options
7664
    public $bindingType          = '';            // WSDL operation binding type
7665
    public $use_curl             = false;            // whether to always try to use cURL
7666
7667
    /*
7668
     * fault related variables
7669
     */
7670
    /**
7671
     * @var fault
7672
     * @access   public
7673
     */
7674
    public $fault;
7675
    /**
7676
     * @var faultcode
7677
     * @access   public
7678
     */
7679
    public $faultcode;
7680
    /**
7681
     * @var faultstring
7682
     * @access   public
7683
     */
7684
    public $faultstring;
7685
    /**
7686
     * @var faultdetail
7687
     * @access   public
7688
     */
7689
    public $faultdetail;
7690
7691
    /**
7692
     * constructor
7693
     *
7694
     * @param mixed       $endpoint         SOAP server or WSDL URL (string) , or wsdl instance (object)
7695
     * @param mixed       $wsdl             optional, set to 'wsdl' or true if using WSDL
7696
     * @param bool|string $proxyhost        optional
7697
     * @param bool|string $proxyport        optional
7698
     * @param bool|string $proxyusername    optional
7699
     * @param bool|string $proxypassword    optional
7700
     * @param integer     $timeout          set the connection timeout
7701
     * @param integer     $response_timeout set the response timeout
7702
     * @param string      $portName         optional portName in WSDL document
7703
     * @access   public
7704
     * @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...
7705
     */
7706
    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...
7707
        $endpoint,
7708
        $wsdl = false,
7709
        $proxyhost = false,
7710
        $proxyport = false,
7711
        $proxyusername = false,
7712
        $proxypassword = false,
7713
        $timeout = 0,
7714
        $response_timeout = 30,
7715
        $portName = ''
7716
    ) {
7717
        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...
7718
        $this->endpoint         = $endpoint;
7719
        $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...
7720
        $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...
7721
        $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...
7722
        $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...
7723
        $this->timeout          = $timeout;
7724
        $this->response_timeout = $response_timeout;
7725
        $this->portName         = $portName;
7726
7727
        $this->debug("ctor wsdl=$wsdl timeout=$timeout response_timeout=$response_timeout");
7728
        $this->appendDebug('endpoint=' . $this->varDump($endpoint));
7729
7730
        // make values
7731
        if ($wsdl) {
7732
            if (is_object($endpoint) && (get_class($endpoint) === 'wsdl')) {
7733
                $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...
7734
                $this->endpoint = $this->wsdl->wsdl;
7735
                $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...
7736
                $this->debug('existing wsdl instance created from ' . $this->endpoint);
7737
                $this->checkWSDL();
7738
            } else {
7739
                $this->wsdlFile = $this->endpoint;
7740
                $this->wsdl     = null;
7741
                $this->debug('will use lazy evaluation of wsdl from ' . $this->endpoint);
7742
            }
7743
            $this->endpointType = 'wsdl';
7744
        } else {
7745
            $this->debug("instantiate SOAP with endpoint at $endpoint");
7746
            $this->endpointType = 'soap';
7747
        }
7748
    }
7749
7750
    /**
7751
     * calls method, returns PHP native type
7752
     *
7753
     * @param  string  $operation  SOAP server URL or path
7754
     * @param  mixed   $params     An array, associative or simple, of the parameters
7755
     *                             for the method call, or a string that is the XML
7756
     *                             for the call.  For rpc style, this call will
7757
     *                             wrap the XML in a tag named after the method, as
7758
     *                             well as the SOAP Envelope and Body.  For document
7759
     *                             style, this will only wrap with the Envelope and Body.
7760
     *                             IMPORTANT: when using an array with document style,
7761
     *                             in which case there
7762
     *                             is really one parameter, the root of the fragment
7763
     *                             used in the call, which encloses what programmers
7764
     *                             normally think of parameters.  A parameter array
7765
     *                             *must* include the wrapper.
7766
     * @param  string  $namespace  optional method namespace (WSDL can override)
7767
     * @param  string  $soapAction optional SOAPAction value (WSDL can override)
7768
     * @param  mixed   $headers    optional string of XML with SOAP header content, or array of soapval objects for SOAP headers, or associative array
7769
     * @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...
7770
     * @param  string  $style      optional (rpc|document) the style to use when serializing parameters (WSDL can override)
7771
     * @param  string  $use        optional (encoded|literal) the use when serializing parameters (WSDL can override)
7772
     * @return mixed   response from SOAP call, normally an associative array mirroring the structure of the XML response, false for certain fatal errors
7773
     * @access   public
7774
     */
7775
    public function call(
7776
        $operation,
7777
        $params = array(),
7778
        $namespace = 'http://tempuri.org',
7779
        $soapAction = '',
7780
        $headers = false,
7781
        $rpcParams = null,
7782
        $style = 'rpc',
7783
        $use = 'encoded'
7784
    ) {
7785
        $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...
7786
        $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...
7787
        $this->setError('');
7788
        $this->request      = '';
7789
        $this->response     = '';
7790
        $this->responseData = '';
7791
        $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...
7792
        $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...
7793
        $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...
7794
7795
        $this->debug("call: operation=$operation, namespace=$namespace, soapAction=$soapAction, rpcParams=$rpcParams, style=$style, use=$use, endpointType=$this->endpointType");
7796
        $this->appendDebug('params=' . $this->varDump($params));
7797
        $this->appendDebug('headers=' . $this->varDump($headers));
7798
        if ($headers) {
7799
            $this->requestHeaders = $headers;
7800
        }
7801 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...
7802
            $this->loadWSDL();
7803
            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...
7804
                return false;
7805
            }
7806
        }
7807
        // serialize parameters
7808
        if ($this->endpointType === 'wsdl' && $opData = $this->getOperationData($operation)) {
7809
            // use WSDL for operation
7810
            $this->opData = $opData;
7811
            $this->debug('found operation');
7812
            $this->appendDebug('opData=' . $this->varDump($opData));
7813
            if (isset($opData['soapAction'])) {
7814
                $soapAction = $opData['soapAction'];
7815
            }
7816
            if (!$this->forceEndpoint) {
7817
                $this->endpoint = $opData['endpoint'];
7818
            } else {
7819
                $this->endpoint = $this->forceEndpoint;
7820
            }
7821
            $namespace = isset($opData['input']['namespace']) ? $opData['input']['namespace'] : $namespace;
7822
            $style     = $opData['style'];
7823
            $use       = $opData['input']['use'];
7824
            // add ns to ns array
7825
            if ($namespace != '' && !isset($this->wsdl->namespaces[$namespace])) {
7826
                $nsPrefix                          = 'ns' . mt_rand(1000, 9999);
7827
                $this->wsdl->namespaces[$nsPrefix] = $namespace;
7828
            }
7829
            $nsPrefix = $this->wsdl->getPrefixFromNamespace($namespace);
7830
            // serialize payload
7831
            if (is_string($params)) {
7832
                $this->debug("serializing param string for WSDL operation $operation");
7833
                $payload = $params;
7834
            } elseif (is_array($params)) {
7835
                $this->debug("serializing param array for WSDL operation $operation");
7836
                $payload = $this->wsdl->serializeRPCParameters($operation, 'input', $params, $this->bindingType);
7837
            } else {
7838
                $this->debug('params must be array or string');
7839
                $this->setError('params must be array or string');
7840
7841
                return false;
7842
            }
7843
            $usedNamespaces = $this->wsdl->usedNamespaces;
7844
            if (isset($opData['input']['encodingStyle'])) {
7845
                $encodingStyle = $opData['input']['encodingStyle'];
7846
            } else {
7847
                $encodingStyle = '';
7848
            }
7849
            $this->appendDebug($this->wsdl->getDebug());
7850
            $this->wsdl->clearDebug();
7851
            if ($errstr = $this->wsdl->getError()) {
7852
                $this->debug('got wsdl error: ' . $errstr);
7853
                $this->setError('wsdl error: ' . $errstr);
7854
7855
                return false;
7856
            }
7857
        } elseif ($this->endpointType === 'wsdl') {
7858
            // operation not in WSDL
7859
            $this->appendDebug($this->wsdl->getDebug());
7860
            $this->wsdl->clearDebug();
7861
            $this->setError('operation ' . $operation . ' not present in WSDL.');
7862
            $this->debug("operation '$operation' not present in WSDL.");
7863
7864
            return false;
7865
        } else {
7866
            // no WSDL
7867
            //$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...
7868
            $nsPrefix = 'ns' . mt_rand(1000, 9999);
7869
            // serialize
7870
            $payload = '';
7871
            if (is_string($params)) {
7872
                $this->debug("serializing param string for operation $operation");
7873
                $payload = $params;
7874
            } elseif (is_array($params)) {
7875
                $this->debug("serializing param array for operation $operation");
7876
                foreach ($params as $k => $v) {
7877
                    $payload .= $this->serialize_val($v, $k, false, false, false, false, $use);
7878
                }
7879
            } else {
7880
                $this->debug('params must be array or string');
7881
                $this->setError('params must be array or string');
7882
7883
                return false;
7884
            }
7885
            $usedNamespaces = array();
7886
            if ($use === 'encoded') {
7887
                $encodingStyle = 'http://schemas.xmlsoap.org/soap/encoding/';
7888
            } else {
7889
                $encodingStyle = '';
7890
            }
7891
        }
7892
        // wrap RPC calls with method element
7893
        if ($style === 'rpc') {
7894
            if ($use === 'literal') {
7895
                $this->debug('wrapping RPC request with literal method element');
7896 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...
7897
                    // 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
7898
                    $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . "</$nsPrefix:$operation>";
7899
                } else {
7900
                    $payload = "<$operation>" . $payload . "</$operation>";
7901
                }
7902 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...
7903
                $this->debug('wrapping RPC request with encoded method element');
7904
                if ($namespace) {
7905
                    $payload = "<$nsPrefix:$operation xmlns:$nsPrefix=\"$namespace\">" . $payload . "</$nsPrefix:$operation>";
7906
                } else {
7907
                    $payload = "<$operation>" . $payload . "</$operation>";
7908
                }
7909
            }
7910
        }
7911
        // serialize envelope
7912
        $soapmsg = $this->serializeEnvelope($payload, $this->requestHeaders, $usedNamespaces, $style, $use, $encodingStyle);
7913
        $this->debug("endpoint=$this->endpoint, soapAction=$soapAction, namespace=$namespace, style=$style, use=$use, encodingStyle=$encodingStyle");
7914
        $this->debug('SOAP message length=' . strlen($soapmsg) . ' contents (max 1000 bytes)=' . substr($soapmsg, 0, 1000));
7915
        // send
7916
        $return = $this->send($this->getHTTPBody($soapmsg), $soapAction, $this->timeout, $this->response_timeout);
7917
        if ($errstr = $this->getError()) {
7918
            $this->debug('Error: ' . $errstr);
7919
7920
            return false;
7921
        } else {
7922
            $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...
7923
            $this->debug('sent message successfully and got a(n) ' . gettype($return));
7924
            $this->appendDebug('return=' . $this->varDump($return));
7925
7926
            // fault?
7927
            if (is_array($return) && isset($return['faultcode'])) {
7928
                $this->debug('got fault');
7929
                $this->setError($return['faultcode'] . ': ' . $return['faultstring']);
7930
                $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...
7931
                foreach ($return as $k => $v) {
7932
                    $this->$k = $v;
7933
                    $this->debug("$k = $v<br>");
7934
                }
7935
7936
                return $return;
7937
            } elseif ($style === 'document') {
7938
                // NOTE: if the response is defined to have multiple parts (i.e. unwrapped),
7939
                // we are only going to return the first part here...sorry about that
7940
                return $return;
7941
            } else {
7942
                // array of return values
7943
                if (is_array($return)) {
7944
                    // multiple 'out' parameters, which we return wrapped up
7945
                    // in the array
7946
                    if (count($return) > 1) {
7947
                        return $return;
7948
                    }
7949
                    // single 'out' parameter (normally the return value)
7950
                    $return = array_shift($return);
7951
                    $this->debug('return shifted value: ');
7952
                    $this->appendDebug($this->varDump($return));
7953
7954
                    return $return;
7955
                    // nothing returned (ie, echoVoid)
7956
                } else {
7957
                    return '';
7958
                }
7959
            }
7960
        }
7961
    }
7962
7963
    /**
7964
     * check WSDL passed as an instance or pulled from an endpoint
7965
     *
7966
     * @access   private
7967
     */
7968
    public function checkWSDL()
7969
    {
7970
        $this->appendDebug($this->wsdl->getDebug());
7971
        $this->wsdl->clearDebug();
7972
        $this->debug('checkWSDL');
7973
        // catch errors
7974
        if ($errstr = $this->wsdl->getError()) {
7975
            $this->appendDebug($this->wsdl->getDebug());
7976
            $this->wsdl->clearDebug();
7977
            $this->debug('got wsdl error: ' . $errstr);
7978
            $this->setError('wsdl error: ' . $errstr);
7979
        } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap')) {
7980
            $this->appendDebug($this->wsdl->getDebug());
7981
            $this->wsdl->clearDebug();
7982
            $this->bindingType = 'soap';
7983
            $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7984
        } elseif ($this->operations = $this->wsdl->getOperations($this->portName, 'soap12')) {
7985
            $this->appendDebug($this->wsdl->getDebug());
7986
            $this->wsdl->clearDebug();
7987
            $this->bindingType = 'soap12';
7988
            $this->debug('got ' . count($this->operations) . ' operations from wsdl ' . $this->wsdlFile . ' for binding type ' . $this->bindingType);
7989
            $this->debug('**************** WARNING: SOAP 1.2 BINDING *****************');
7990
        } else {
7991
            $this->appendDebug($this->wsdl->getDebug());
7992
            $this->wsdl->clearDebug();
7993
            $this->debug('getOperations returned false');
7994
            $this->setError('no operations defined in the WSDL document!');
7995
        }
7996
    }
7997
7998
    /**
7999
     * instantiate wsdl object and parse wsdl file
8000
     *
8001
     * @access  public
8002
     */
8003
    public function loadWSDL()
8004
    {
8005
        $this->debug('instantiating wsdl class with doc: ' . $this->wsdlFile);
8006
        $this->wsdl = new wsdl('', $this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword, $this->timeout, $this->response_timeout, $this->curl_options, $this->use_curl);
8007
        $this->wsdl->setCredentials($this->username, $this->password, $this->authtype, $this->certRequest);
8008
        $this->wsdl->fetchWSDL($this->wsdlFile);
8009
        $this->checkWSDL();
8010
    }
8011
8012
    /**
8013
     * get available data pertaining to an operation
8014
     *
8015
     * @param  string $operation operation name
8016
     * @return array  array of data pertaining to the operation
8017
     * @access   public
8018
     */
8019
    public function getOperationData($operation)
8020
    {
8021 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...
8022
            $this->loadWSDL();
8023
            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...
8024
                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...
8025
            }
8026
        }
8027
        if (isset($this->operations[$operation])) {
8028
            return $this->operations[$operation];
8029
        }
8030
        $this->debug("No data for operation: $operation");
8031
    }
8032
8033
    /**
8034
     * send the SOAP message
8035
     *
8036
     * Note: if the operation has multiple return values
8037
     * the return value of this method will be an array
8038
     * of those values.
8039
     *
8040
     * @param  string  $msg              a SOAPx4 soapmsg object
8041
     * @param  string  $soapaction       SOAPAction value
8042
     * @param  integer $timeout          set connection timeout in seconds
8043
     * @param  integer $response_timeout set response timeout in seconds
8044
     * @return mixed   native PHP types.
8045
     * @access   private
8046
     */
8047
    public function send($msg, $soapaction = '', $timeout = 0, $response_timeout = 30)
8048
    {
8049
        $this->checkCookies();
8050
        // detect transport
8051
        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...
8052
            // http(s)
8053
            case preg_match('/^http/', $this->endpoint):
8054
                $this->debug('transporting via HTTP');
8055
                if ($this->persistentConnection === true && is_object($this->persistentConnection)) {
8056
                    $http = $this->persistentConnection;
8057
                } else {
8058
                    $http = new soap_transport_http($this->endpoint, $this->curl_options, $this->use_curl);
8059
                    if ($this->persistentConnection) {
8060
                        $http->usePersistentConnection();
8061
                    }
8062
                }
8063
                $http->setContentType($this->getHTTPContentType(), $this->getHTTPContentTypeCharset());
8064
                $http->setSOAPAction($soapaction);
8065 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...
8066
                    $http->setProxy($this->proxyhost, $this->proxyport, $this->proxyusername, $this->proxypassword);
8067
                }
8068
                if ($this->authtype !== '') {
8069
                    $http->setCredentials($this->username, $this->password, $this->authtype, array(), $this->certRequest);
8070
                }
8071
                if ($this->http_encoding !== '') {
8072
                    $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...
8073
                }
8074
                $this->debug('sending message, length=' . strlen($msg));
8075
                if (preg_match('/^http:/', $this->endpoint)) {
8076
                    //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...
8077
                    $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...
8078
                } elseif (preg_match('/^https/', $this->endpoint)) {
8079
                    //} 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...
8080
                    //if (phpversion() == '4.3.0-dev') {
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...
8081
                    //$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...
8082
                    //$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...
8083
                    //$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...
8084
                    //} else
8085
                    $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...
8086
                } else {
8087
                    $this->setError('no http/s in endpoint url');
8088
                }
8089
                $this->request  = $http->outgoing_payload;
8090
                $this->response = $http->incoming_payload;
8091
                $this->appendDebug($http->getDebug());
8092
                $this->UpdateCookies($http->incoming_cookies);
8093
8094
                // save transport object if using persistent connections
8095
                if ($this->persistentConnection) {
8096
                    $http->clearDebug();
8097
                    if (!is_object($this->persistentConnection)) {
8098
                        $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...
8099
                    }
8100
                }
8101
8102
                if ($err = $http->getError()) {
8103
                    $this->setError('HTTP Error: ' . $err);
8104
8105
                    return false;
8106
                } 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...
8107
                    return false;
8108
                } else {
8109
                    $this->debug('got response, length=' . strlen($this->responseData) . ' type=' . $http->incoming_headers['content-type']);
8110
8111
                    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...
8112
                }
8113
                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...
8114
            default:
8115
                $this->setError('no transport found, or selected transport is not yet supported!');
8116
8117
                return false;
8118
                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...
8119
        }
8120
    }
8121
8122
    /**
8123
     * processes SOAP message returned from server
8124
     *
8125
     * @param  array  $headers The HTTP headers
8126
     * @param  string $data    unprocessed response data from server
8127
     * @return mixed  value of the message, decoded into a PHP type
8128
     * @access   private
8129
     */
8130
    public function parseResponse($headers, $data)
8131
    {
8132
        $this->debug('Entering parseResponse() for data of length ' . strlen($data) . ' headers:');
8133
        $this->appendDebug($this->varDump($headers));
8134
        if (!isset($headers['content-type'])) {
8135
            $this->setError('Response not of type text/xml (no content-type header)');
8136
8137
            return false;
8138
        }
8139 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...
8140
            $this->setError('Response not of type text/xml: ' . $headers['content-type']);
8141
8142
            return false;
8143
        }
8144 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...
8145
            $enc = str_replace('"', '', substr(strstr($headers['content-type'], '='), 1));
8146
            $this->debug('Got response encoding: ' . $enc);
8147
            if (preg_match('/^(ISO-8859-1|US-ASCII|UTF-8)$/i', $enc)) {
8148
                $this->xml_encoding = strtoupper($enc);
8149
            } else {
8150
                $this->xml_encoding = 'US-ASCII';
8151
            }
8152
        } else {
8153
            // should be US-ASCII for HTTP 1.0 or ISO-8859-1 for HTTP 1.1
8154
            $this->xml_encoding = 'ISO-8859-1';
8155
        }
8156
        $this->debug('Use encoding: ' . $this->xml_encoding . ' when creating nusoap_parser');
8157
        $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...
8158
        // add parser debug data to our debug
8159
        $this->appendDebug($parser->getDebug());
8160
        // if parse errors
8161
        if ($errstr = $parser->getError()) {
8162
            $this->setError($errstr);
8163
            // destroy the parser object
8164
            unset($parser);
8165
8166
            return false;
8167
        } else {
8168
            // get SOAP headers
8169
            $this->responseHeaders = $parser->getHeaders();
8170
            // get SOAP headers
8171
            $this->responseHeader = $parser->get_soapheader();
8172
            // get decoded message
8173
            $return = $parser->get_soapbody();
8174
            // add document for doclit support
8175
            $this->document = $parser->document;
8176
            // destroy the parser object
8177
            unset($parser);
8178
8179
            // return decode message
8180
            return $return;
8181
        }
8182
    }
8183
8184
    /**
8185
     * sets user-specified cURL options
8186
     *
8187
     * @param mixed $option The cURL option (always integer?)
8188
     * @param mixed $value  The cURL option value
8189
     * @access   public
8190
     */
8191
    public function setCurlOption($option, $value)
8192
    {
8193
        $this->debug("setCurlOption option=$option, value=");
8194
        $this->appendDebug($this->varDump($value));
8195
        $this->curl_options[$option] = $value;
8196
    }
8197
8198
    /**
8199
     * sets the SOAP endpoint, which can override WSDL
8200
     *
8201
     * @param string $endpoint The endpoint URL to use, or empty string or false to prevent override
8202
     * @access   public
8203
     */
8204
    public function setEndpoint($endpoint)
8205
    {
8206
        $this->debug("setEndpoint(\"$endpoint\")");
8207
        $this->forceEndpoint = $endpoint;
8208
    }
8209
8210
    /**
8211
     * set the SOAP headers
8212
     *
8213
     * @param mixed $headers String of XML with SOAP header content, or array of soapval objects for SOAP headers
8214
     * @access   public
8215
     */
8216
    public function setHeaders($headers)
8217
    {
8218
        $this->debug('setHeaders headers=');
8219
        $this->appendDebug($this->varDump($headers));
8220
        $this->requestHeaders = $headers;
8221
    }
8222
8223
    /**
8224
     * get the SOAP response headers (namespace resolution incomplete)
8225
     *
8226
     * @return string
8227
     * @access   public
8228
     */
8229
    public function getHeaders()
8230
    {
8231
        return $this->responseHeaders;
8232
    }
8233
8234
    /**
8235
     * get the SOAP response Header (parsed)
8236
     *
8237
     * @return mixed
8238
     * @access   public
8239
     */
8240
    public function getHeader()
8241
    {
8242
        return $this->responseHeader;
8243
    }
8244
8245
    /**
8246
     * set proxy info here
8247
     *
8248
     * @param string $proxyhost
8249
     * @param string $proxyport
8250
     * @param string $proxyusername
8251
     * @param string $proxypassword
8252
     * @access   public
8253
     */
8254
    public function setHTTPProxy($proxyhost, $proxyport, $proxyusername = '', $proxypassword = '')
8255
    {
8256
        $this->proxyhost     = $proxyhost;
8257
        $this->proxyport     = $proxyport;
8258
        $this->proxyusername = $proxyusername;
8259
        $this->proxypassword = $proxypassword;
8260
    }
8261
8262
    /**
8263
     * if authenticating, set user credentials here
8264
     *
8265
     * @param string $username
8266
     * @param string $password
8267
     * @param string $authtype    (basic|digest|certificate|ntlm)
8268
     * @param array  $certRequest (keys must be cainfofile (optional), sslcertfile, sslkeyfile, passphrase, verifypeer (optional), verifyhost (optional): see corresponding options in cURL docs)
8269
     * @access   public
8270
     */
8271 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...
8272
    {
8273
        $this->debug("setCredentials username=$username authtype=$authtype certRequest=");
8274
        $this->appendDebug($this->varDump($certRequest));
8275
        $this->username    = $username;
8276
        $this->password    = $password;
8277
        $this->authtype    = $authtype;
8278
        $this->certRequest = $certRequest;
8279
    }
8280
8281
    /**
8282
     * use HTTP encoding
8283
     *
8284
     * @param string $enc HTTP encoding
8285
     * @access   public
8286
     */
8287
    public function setHTTPEncoding($enc = 'gzip, deflate')
8288
    {
8289
        $this->debug("setHTTPEncoding(\"$enc\")");
8290
        $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...
8291
    }
8292
8293
    /**
8294
     * Set whether to try to use cURL connections if possible
8295
     *
8296
     * @param boolean $use Whether to try to use cURL
8297
     * @access   public
8298
     */
8299
    public function setUseCURL($use)
8300
    {
8301
        $this->debug("setUseCURL($use)");
8302
        $this->use_curl = $use;
8303
    }
8304
8305
    /**
8306
     * use HTTP persistent connections if possible
8307
     *
8308
     * @access   public
8309
     */
8310
    public function useHTTPPersistentConnection()
8311
    {
8312
        $this->debug('useHTTPPersistentConnection');
8313
        $this->persistentConnection = true;
8314
    }
8315
8316
    /**
8317
     * gets the default RPC parameter setting.
8318
     * If true, default is that call params are like RPC even for document style.
8319
     * Each call() can override this value.
8320
     *
8321
     * This is no longer used.
8322
     *
8323
     * @return boolean
8324
     * @access public
8325
     * @deprecated
8326
     */
8327
    public function getDefaultRpcParams()
8328
    {
8329
        return $this->defaultRpcParams;
8330
    }
8331
8332
    /**
8333
     * sets 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
     * @param boolean $rpcParams
8340
     * @access public
8341
     * @deprecated
8342
     */
8343
    public function setDefaultRpcParams($rpcParams)
8344
    {
8345
        $this->defaultRpcParams = $rpcParams;
8346
    }
8347
8348
    /**
8349
     * dynamically creates an instance of a proxy class,
8350
     * allowing user to directly call methods from wsdl
8351
     *
8352
     * @return object soap_proxy object
8353
     * @access   public
8354
     */
8355
    public function getProxy()
8356
    {
8357
        $r       = mt_rand();
8358
        $evalStr = $this->_getProxyClassCode($r);
8359
        //$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...
8360
        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...
8361
            $this->debug('Error from _getProxyClassCode, so return NULL');
8362
8363
            return null;
8364
        }
8365
        // eval the class
8366
        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...
8367
        // instantiate proxy object
8368
        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...
8369
        // transfer current wsdl data to the proxy thereby avoiding parsing the wsdl twice
8370
        $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...
8371
        $proxy->wsdlFile         = $this->wsdlFile;
8372
        $proxy->wsdl             = $this->wsdl;
8373
        $proxy->operations       = $this->operations;
8374
        $proxy->defaultRpcParams = $this->defaultRpcParams;
8375
        // transfer other state
8376
        $proxy->soap_defencoding     = $this->soap_defencoding;
8377
        $proxy->username             = $this->username;
8378
        $proxy->password             = $this->password;
8379
        $proxy->authtype             = $this->authtype;
8380
        $proxy->certRequest          = $this->certRequest;
8381
        $proxy->requestHeaders       = $this->requestHeaders;
8382
        $proxy->endpoint             = $this->endpoint;
8383
        $proxy->forceEndpoint        = $this->forceEndpoint;
8384
        $proxy->proxyhost            = $this->proxyhost;
8385
        $proxy->proxyport            = $this->proxyport;
8386
        $proxy->proxyusername        = $this->proxyusername;
8387
        $proxy->proxypassword        = $this->proxypassword;
8388
        $proxy->http_encoding        = $this->http_encoding;
8389
        $proxy->timeout              = $this->timeout;
8390
        $proxy->response_timeout     = $this->response_timeout;
8391
        $proxy->persistentConnection = $this->persistentConnection;
8392
        $proxy->decode_utf8          = $this->decode_utf8;
8393
        $proxy->curl_options         = $this->curl_options;
8394
        $proxy->bindingType          = $this->bindingType;
8395
        $proxy->use_curl             = $this->use_curl;
8396
8397
        return $proxy;
8398
    }
8399
8400
    /**
8401
     * dynamically creates proxy class code
8402
     *
8403
     * @param $r
8404
     * @return string PHP/NuSOAP code for the proxy class
8405
     * @access   private
8406
     */
8407
    public function _getProxyClassCode($r)
8408
    {
8409
        $this->debug("in getProxy endpointType=$this->endpointType");
8410
        $this->appendDebug('wsdl=' . $this->varDump($this->wsdl));
8411
        if ($this->endpointType !== 'wsdl') {
8412
            $evalStr = 'A proxy can only be created for a WSDL client';
8413
            $this->setError($evalStr);
8414
            $evalStr = "echo \"$evalStr\";";
8415
8416
            return $evalStr;
8417
        }
8418
        if ($this->endpointType === 'wsdl' && null === $this->wsdl) {
8419
            $this->loadWSDL();
8420
            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...
8421
                return "echo \"" . $this->getError() . "\";";
8422
            }
8423
        }
8424
        $evalStr = '';
8425
        foreach ($this->operations as $operation => $opData) {
8426
            if ($operation != '') {
8427
                // create param string and param comment string
8428
                if (count($opData['input']['parts']) > 0) {
8429
                    $paramStr        = '';
8430
                    $paramArrayStr   = '';
8431
                    $paramCommentStr = '';
8432
                    foreach ($opData['input']['parts'] as $name => $type) {
8433
                        $paramStr .= "\$$name, ";
8434
                        $paramArrayStr .= "'$name' => \$$name, ";
8435
                        $paramCommentStr .= "$type \$$name, ";
8436
                    }
8437
                    $paramStr        = substr($paramStr, 0, strlen($paramStr) - 2);
8438
                    $paramArrayStr   = substr($paramArrayStr, 0, strlen($paramArrayStr) - 2);
8439
                    $paramCommentStr = substr($paramCommentStr, 0, strlen($paramCommentStr) - 2);
8440
                } else {
8441
                    $paramStr        = '';
8442
                    $paramArrayStr   = '';
8443
                    $paramCommentStr = 'void';
8444
                }
8445
                $opData['namespace'] = !isset($opData['namespace']) ? 'http://testuri.com' : $opData['namespace'];
8446
                $evalStr .= "// $paramCommentStr
8447
    function " . str_replace('.', '__', $operation) . "($paramStr) {
8448
        \$params = array($paramArrayStr);
8449
8450
        return \$this->call('$operation', \$params, '" . $opData['namespace'] . "', '" . (isset($opData['soapAction']) ? $opData['soapAction'] : '') . "');
8451
    }
8452
    ";
8453
                unset($paramStr, $paramCommentStr);
8454
            }
8455
        }
8456
        $evalStr = 'class nusoap_proxy_' . $r . ' extends Nusoap_client {
8457
    ' . $evalStr . '
8458
}';
8459
8460
        return $evalStr;
8461
    }
8462
8463
    /**
8464
     * dynamically creates proxy class code
8465
     *
8466
     * @return string PHP/NuSOAP code for the proxy class
8467
     * @access   public
8468
     */
8469
    public function getProxyClassCode()
8470
    {
8471
        $r = mt_rand();
8472
8473
        return $this->_getProxyClassCode($r);
8474
    }
8475
8476
    /**
8477
     * gets the HTTP body for the current request.
8478
     *
8479
     * @param  string $soapmsg The SOAP payload
8480
     * @return string The HTTP body, which includes the SOAP payload
8481
     * @access private
8482
     */
8483
    public function getHTTPBody($soapmsg)
8484
    {
8485
        return $soapmsg;
8486
    }
8487
8488
    /**
8489
     * gets the HTTP content type for the current request.
8490
     *
8491
     * Note: getHTTPBody must be called before this.
8492
     *
8493
     * @return string the HTTP content type for the current request.
8494
     * @access private
8495
     */
8496
    public function getHTTPContentType()
8497
    {
8498
        return 'text/xml';
8499
    }
8500
8501
    /**
8502
     * gets the HTTP content type charset for the current request.
8503
     * returns false for non-text content types.
8504
     *
8505
     * Note: getHTTPBody must be called before this.
8506
     *
8507
     * @return string the HTTP content type charset for the current request.
8508
     * @access private
8509
     */
8510
    public function getHTTPContentTypeCharset()
8511
    {
8512
        return $this->soap_defencoding;
8513
    }
8514
8515
    /*
8516
    * whether or not parser should decode utf8 element content
8517
    *
8518
    * @return   always returns true
8519
    * @access   public
8520
    */
8521
    /**
8522
     * @param $bool
8523
     * @return bool
8524
     */
8525
    public function decodeUTF8($bool)
8526
    {
8527
        $this->decode_utf8 = $bool;
8528
8529
        return true;
8530
    }
8531
8532
    /**
8533
     * adds a new Cookie into $this->cookies array
8534
     *
8535
     * @param  string $name  Cookie Name
8536
     * @param  string $value Cookie Value
8537
     * @return boolean if cookie-set was successful returns true, else false
8538
     * @access  public
8539
     */
8540
    public function setCookie($name, $value)
8541
    {
8542
        if ('' === $name) {
8543
            return false;
8544
        }
8545
        $this->cookies[] = array('name' => $name, 'value' => $value);
8546
8547
        return true;
8548
    }
8549
8550
    /**
8551
     * gets all Cookies
8552
     *
8553
     * @return array with all internal cookies
8554
     * @access   public
8555
     */
8556
    public function getCookies()
8557
    {
8558
        return $this->cookies;
8559
    }
8560
8561
    /**
8562
     * checks all Cookies and delete those which are expired
8563
     *
8564
     * @return boolean always return true
8565
     * @access   private
8566
     */
8567
    public function checkCookies()
8568
    {
8569
        if (count($this->cookies) == 0) {
8570
            return true;
8571
        }
8572
        $this->debug('checkCookie: check ' . count($this->cookies) . ' cookies');
8573
        $curr_cookies  = $this->cookies;
8574
        $this->cookies = array();
8575
        foreach ($curr_cookies as $cookie) {
8576
            if (!is_array($cookie)) {
8577
                $this->debug('Remove cookie that is not an array');
8578
                continue;
8579
            }
8580
            if (isset($cookie['expires']) && (!empty($cookie['expires']))) {
8581
                if (strtotime($cookie['expires']) > time()) {
8582
                    $this->cookies[] = $cookie;
8583
                } else {
8584
                    $this->debug('Remove expired cookie ' . $cookie['name']);
8585
                }
8586
            } else {
8587
                $this->cookies[] = $cookie;
8588
            }
8589
        }
8590
        $this->debug('checkCookie: ' . count($this->cookies) . ' cookies left in array');
8591
8592
        return true;
8593
    }
8594
8595
    /**
8596
     * updates the current cookies with a new set
8597
     *
8598
     * @param  array $cookies new cookies with which to update current ones
8599
     * @return boolean always return true
8600
     * @access  private
8601
     */
8602
    public function UpdateCookies($cookies)
8603
    {
8604
        if (count($this->cookies) == 0) {
8605
            // no existing cookies: take whatever is new
8606
            if (count($cookies) > 0) {
8607
                $this->debug('Setting new cookie(s)');
8608
                $this->cookies = $cookies;
8609
            }
8610
8611
            return true;
8612
        }
8613
        if (count($cookies) == 0) {
8614
            // no new cookies: keep what we've got
8615
            return true;
8616
        }
8617
        // merge
8618
        foreach ($cookies as $newCookie) {
8619
            if (!is_array($newCookie)) {
8620
                continue;
8621
            }
8622
            if ((!isset($newCookie['name'])) || (!isset($newCookie['value']))) {
8623
                continue;
8624
            }
8625
            $newName = $newCookie['name'];
8626
8627
            $found = false;
8628
            for ($i = 0, $iMax = count($this->cookies); $i < $iMax; ++$i) {
8629
                $cookie = $this->cookies[$i];
8630
                if (!is_array($cookie)) {
8631
                    continue;
8632
                }
8633
                if (!isset($cookie['name'])) {
8634
                    continue;
8635
                }
8636
                if ($newName != $cookie['name']) {
8637
                    continue;
8638
                }
8639
                $newDomain = isset($newCookie['domain']) ? $newCookie['domain'] : 'NODOMAIN';
8640
                $domain    = isset($cookie['domain']) ? $cookie['domain'] : 'NODOMAIN';
8641
                if ($newDomain != $domain) {
8642
                    continue;
8643
                }
8644
                $newPath = isset($newCookie['path']) ? $newCookie['path'] : 'NOPATH';
8645
                $path    = isset($cookie['path']) ? $cookie['path'] : 'NOPATH';
8646
                if ($newPath != $path) {
8647
                    continue;
8648
                }
8649
                $this->cookies[$i] = $newCookie;
8650
                $found             = true;
8651
                $this->debug('Update cookie ' . $newName . '=' . $newCookie['value']);
8652
                break;
8653
            }
8654
            if (!$found) {
8655
                $this->debug('Add cookie ' . $newName . '=' . $newCookie['value']);
8656
                $this->cookies[] = $newCookie;
8657
            }
8658
        }
8659
8660
        return true;
8661
    }
8662
}
8663
8664
if (!extension_loaded('soap')) {
8665
    /**
8666
     *  For backwards compatiblity, define soapclient unless the PHP SOAP extension is loaded.
8667
     */
8668
    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...
8669
    {
8670
    }
8671
}
8672
?>
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...
8673