Issues (1751)

Security Analysis    not enabled

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

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

lib/modules/mod_json.php (4 issues)

Upgrade to new PHP Analysis Engine

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

1
<?php
2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3
4
/**
5
 * Converts to and from JSON format.
6
 *
7
 * JSON (JavaScript Object Notation) is a lightweight data-interchange
8
 * format. It is easy for humans to read and write. It is easy for machines
9
 * to parse and generate. It is based on a subset of the JavaScript
10
 * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
11
 * This feature can also be found in  Python. JSON is a text format that is
12
 * completely language independent but uses conventions that are familiar
13
 * to programmers of the C-family of languages, including C, C++, C#, Java,
14
 * JavaScript, Perl, TCL, and many others. These properties make JSON an
15
 * ideal data-interchange language.
16
 *
17
 * This package provides a simple encoder and decoder for JSON notation. It
18
 * is intended for use with client-side Javascript applications that make
19
 * use of HTTPRequest to perform server communication functions - data can
20
 * be encoded into JSON notation for use in a client-side javascript, or
21
 * decoded from incoming Javascript requests. JSON format is native to
22
 * Javascript, and can be directly eval()'ed with no further parsing
23
 * overhead
24
 *
25
 * All strings should be in ASCII or UTF-8 format!
26
 *
27
 * LICENSE: Redistribution and use in source and binary forms, with or
28
 * without modification, are permitted provided that the following
29
 * conditions are met: Redistributions of source code must retain the
30
 * above copyright notice, this list of conditions and the following
31
 * disclaimer. Redistributions in binary form must reproduce the above
32
 * copyright notice, this list of conditions and the following disclaimer
33
 * in the documentation and/or other materials provided with the
34
 * distribution.
35
 *
36
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
37
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
38
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
39
 * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
40
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
41
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
42
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
44
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
45
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46
 * DAMAGE.
47
 *
48
 * @category
49
 * @package     Services_JSON
50
 * @author      Michal Migurski <[email protected]>
51
 * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
52
 * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
53
 * @copyright   2005 Michal Migurski
54
 * @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
55
 * @license     http://www.opensource.org/licenses/bsd-license.php
56
 * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
57
 */
58
59
/**
60
 * Marker constant for Services_JSON::decode(), used to flag stack state
61
 */
62
define('SERVICES_JSON_SLICE',   1);
63
64
/**
65
 * Marker constant for Services_JSON::decode(), used to flag stack state
66
 */
67
define('SERVICES_JSON_IN_STR',  2);
68
69
/**
70
 * Marker constant for Services_JSON::decode(), used to flag stack state
71
 */
72
define('SERVICES_JSON_IN_ARR',  3);
73
74
/**
75
 * Marker constant for Services_JSON::decode(), used to flag stack state
76
 */
77
define('SERVICES_JSON_IN_OBJ',  4);
78
79
/**
80
 * Marker constant for Services_JSON::decode(), used to flag stack state
81
 */
82
define('SERVICES_JSON_IN_CMT', 5);
83
84
/**
85
 * Behavior switch for Services_JSON::decode()
86
 */
87
define('SERVICES_JSON_LOOSE_TYPE', 16);
88
89
/**
90
 * Behavior switch for Services_JSON::decode()
91
 */
92
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
93
94
/**
95
 * Converts to and from JSON format.
96
 *
97
 * Brief example of use:
98
 *
99
 * <code>
100
 * // create a new instance of Services_JSON
101
 * $json = new Services_JSON();
102
 *
103
 * // convert a complexe value to JSON notation, and send it to the browser
104
 * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
105
 * $output = $json->encode($value);
106
 *
107
 * print($output);
108
 * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
109
 *
110
 * // accept incoming POST data, assumed to be in JSON notation
111
 * $input = file_get_contents('php://input', 1000000);
112
 * $value = $json->decode($input);
113
 * </code>
114
 */
115
116
class pinp_JSON {
117
	public static function _encode($var, $use=0) {
118
		return JSON::encode($var, $use);
119
	}
120
	public static function _decode($str, $use=0) {
121
		return JSON::decode($str, $use);
122
	}
123
	public static function _indent($str, $newLine="\n", $indentStr="\t") {
124
		return JSON::indent($str, $newLine, $indentStr);
125
	}
126
}
127
128
class JSON {
129
	public static function getInstance($use) {
130
		return new Services_JSON($use);
131
	}
132
133
	public static function encode($var, $use=0) {
134
		$json = JSON::getInstance($use);
135
		return $json->encode($var);
136
	}
137
138
	public static function decode($str, $use=0) {
139
		$json = JSON::getInstance($use);
140
		return $json->decode($str);
141
	}
142
143
	public static function indent($json, $newLine="\n", $indentStr="\t") {
144
	/**
145
	 * Indents a flat JSON string to make it more human-readable
146
	 *
147
	 * @param string $json The original JSON string to process
148
	 * @return string Indented version of the original JSON string
149
	 */
150
	    $result    = '';
151
	    $pos       = 0;
152
	    $strLen    = strlen($json);
153
154
	    for($i = 0; $i <= $strLen; $i++) {
155
156
	        // Grab the next character in the string
157
	        $char = substr($json, $i, 1);
158
159
	        // If this character is the end of an element,
160
	        // output a new line and indent the next line
161
	        if($char == '}' || $char == ']') {
162
	            $result .= $newLine;
163
	            $pos --;
164
	            for ($j=0; $j<$pos; $j++) {
165
	                $result .= $indentStr;
166
	            }
167
	        }
168
169
	        // Add the character to the result string
170
	        $result .= $char;
171
172
	        // If the last character was the beginning of an element,
173
	        // output a new line and indent the next line
174
	        if ($char == ',' || $char == '{' || $char == '[') {
175
	            $result .= $newLine;
176
	            if ($char == '{' || $char == '[') {
177
	                $pos ++;
178
	            }
179
	            for ($j = 0; $j < $pos; $j++) {
180
	                $result .= $indentStr;
181
	            }
182
	        }
183
	    }
184
	    return $result;
185
	}
186
}
187
188
class Services_JSON
189
{
190
   /**
191
    * constructs a new JSON instance
192
    *
193
    * @param    int     $use    object behavior flags; combine with boolean-OR
194
    *
195
    *                           possible values:
196
    *                           - SERVICES_JSON_LOOSE_TYPE:  loose typing.
197
    *                                   "{...}" syntax creates associative arrays
198
    *                                   instead of objects in decode().
199
    *                           - SERVICES_JSON_SUPPRESS_ERRORS:  error suppression.
200
    *                                   Values which can't be encoded (e.g. resources)
201
    *                                   appear as NULL instead of throwing errors.
202
    *                                   By default, a deeply-nested resource will
203
    *                                   bubble up with an error, so all return values
204
    *                                   from encode() should be checked with isError()
205
    */
206
    public function __construct($use = 0)
207
    {
208
        $this->use = $use;
0 ignored issues
show
The property use 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...
209
    }
210
211
   /**
212
    * convert a string from one UTF-16 char to one UTF-8 char
213
    *
214
    * Normally should be handled by mb_convert_encoding, but
215
    * provides a slower PHP-only method for installations
216
    * that lack the multibye string extension.
217
    *
218
    * @param    string  $utf16  UTF-16 character
219
    * @return   string  UTF-8 character
220
    * @access   private
221
    */
222
    protected function utf162utf8($utf16)
223
    {
224
        // oh please oh please oh please oh please oh please
225
        if(function_exists('mb_convert_encoding')) {
226
            return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
227
        }
228
229
        $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
230
231
        switch(true) {
232
            case ((0x7F & $bytes) == $bytes):
233
                // this case should never be reached, because we are in ASCII range
234
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
235
                return chr(0x7F & $bytes);
236
237
            case (0x07FF & $bytes) == $bytes:
238
                // return a 2-byte UTF-8 character
239
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
240
                return chr(0xC0 | (($bytes >> 6) & 0x1F))
241
                     . chr(0x80 | ($bytes & 0x3F));
242
243
            case (0xFFFF & $bytes) == $bytes:
244
                // return a 3-byte UTF-8 character
245
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
246
                return chr(0xE0 | (($bytes >> 12) & 0x0F))
247
                     . chr(0x80 | (($bytes >> 6) & 0x3F))
248
                     . chr(0x80 | ($bytes & 0x3F));
249
        }
250
251
        // ignoring UTF-32 for now, sorry
252
        return '';
253
    }
254
255
   /**
256
    * convert a string from one UTF-8 char to one UTF-16 char
257
    *
258
    * Normally should be handled by mb_convert_encoding, but
259
    * provides a slower PHP-only method for installations
260
    * that lack the multibye string extension.
261
    *
262
    * @param    string  $utf8   UTF-8 character
263
    * @return   string  UTF-16 character
264
    * @access   private
265
    */
266
    protected function utf82utf16($utf8)
267
    {
268
        // oh please oh please oh please oh please oh please
269
        if(function_exists('mb_convert_encoding')) {
270
            return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
271
        }
272
273
        switch(strlen($utf8)) {
274
            case 1:
275
                // this case should never be reached, because we are in ASCII range
276
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
277
                return $utf8;
278
279
            case 2:
280
                // return a UTF-16 character from a 2-byte UTF-8 char
281
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
282
                return chr(0x07 & (ord($utf8{0}) >> 2))
283
                     . chr((0xC0 & (ord($utf8{0}) << 6))
284
                         | (0x3F & ord($utf8{1})));
285
286
            case 3:
287
                // return a UTF-16 character from a 3-byte UTF-8 char
288
                // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
289
                return chr((0xF0 & (ord($utf8{0}) << 4))
290
                         | (0x0F & (ord($utf8{1}) >> 2)))
291
                     . chr((0xC0 & (ord($utf8{1}) << 6))
292
                         | (0x7F & ord($utf8{2})));
293
        }
294
295
        // ignoring UTF-32 for now, sorry
296
        return '';
297
    }
298
299
   /**
300
    * encodes an arbitrary variable into JSON format
301
    *
302
    * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
303
    *                           see argument 1 to Services_JSON() above for array-parsing behavior.
304
    *                           if var is a strng, note that encode() always expects it
305
    *                           to be in ASCII or UTF-8 format!
306
    *
307
    * @return   mixed   JSON string representation of input var or an error if a problem occurs
308
    * @access   public
309
    */
310
    public function encode($var)
311
    {
312
        switch (gettype($var)) {
313
            case 'boolean':
314
                return $var ? 'true' : 'false';
315
316
            case 'NULL':
317
                return 'null';
318
319
            case 'integer':
320
                return (int) $var;
321
322
            case 'double':
323
            case 'float':
324
                return (float) $var;
325
326
            case 'string':
327
                // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
328
                $ascii = '';
329
                $strlen_var = strlen($var);
330
331
               /*
332
                * Iterate over every character in the string,
333
                * escaping with a slash or encoding to UTF-8 where necessary
334
                */
335
                for ($c = 0; $c < $strlen_var; ++$c) {
336
337
                    $ord_var_c = ord($var{$c});
338
339
                    switch (true) {
340
                        case $ord_var_c == 0x08:
341
                            $ascii .= '\b';
342
                            break;
343
                        case $ord_var_c == 0x09:
344
                            $ascii .= '\t';
345
                            break;
346
                        case $ord_var_c == 0x0A:
347
                            $ascii .= '\n';
348
                            break;
349
                        case $ord_var_c == 0x0C:
350
                            $ascii .= '\f';
351
                            break;
352
                        case $ord_var_c == 0x0D:
353
                            $ascii .= '\r';
354
                            break;
355
356
                        case $ord_var_c == 0x22:
357
                        case $ord_var_c == 0x2F:
358
                        case $ord_var_c == 0x5C:
359
                            // double quote, slash, slosh
360
                            $ascii .= '\\'.$var{$c};
361
                            break;
362
363
                        case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
364
                            // characters U-00000000 - U-0000007F (same as ASCII)
365
                            $ascii .= $var{$c};
366
                            break;
367
368
                        case (($ord_var_c & 0xE0) == 0xC0):
369
                            // characters U-00000080 - U-000007FF, mask 110XXXXX
370
                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
371
                            $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
372
                            $c += 1;
373
                            $utf16 = $this->utf82utf16($char);
374
                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
375
                            break;
376
377
                        case (($ord_var_c & 0xF0) == 0xE0):
378
                            // characters U-00000800 - U-0000FFFF, mask 1110XXXX
379
                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
380
                            $char = pack('C*', $ord_var_c,
381
                                         ord($var{$c + 1}),
382
                                         ord($var{$c + 2}));
383
                            $c += 2;
384
                            $utf16 = $this->utf82utf16($char);
385
                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
386
                            break;
387
388
                        case (($ord_var_c & 0xF8) == 0xF0):
389
                            // characters U-00010000 - U-001FFFFF, mask 11110XXX
390
                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
391
                            $char = pack('C*', $ord_var_c,
392
                                         ord($var{$c + 1}),
393
                                         ord($var{$c + 2}),
394
                                         ord($var{$c + 3}));
395
                            $c += 3;
396
                            $utf16 = $this->utf82utf16($char);
397
                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
398
                            break;
399
400 View Code Duplication
                        case (($ord_var_c & 0xFC) == 0xF8):
401
                            // characters U-00200000 - U-03FFFFFF, mask 111110XX
402
                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
403
                            $char = pack('C*', $ord_var_c,
404
                                         ord($var{$c + 1}),
405
                                         ord($var{$c + 2}),
406
                                         ord($var{$c + 3}),
407
                                         ord($var{$c + 4}));
408
                            $c += 4;
409
                            $utf16 = $this->utf82utf16($char);
410
                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
411
                            break;
412
413 View Code Duplication
                        case (($ord_var_c & 0xFE) == 0xFC):
414
                            // characters U-04000000 - U-7FFFFFFF, mask 1111110X
415
                            // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
416
                            $char = pack('C*', $ord_var_c,
417
                                         ord($var{$c + 1}),
418
                                         ord($var{$c + 2}),
419
                                         ord($var{$c + 3}),
420
                                         ord($var{$c + 4}),
421
                                         ord($var{$c + 5}));
422
                            $c += 5;
423
                            $utf16 = $this->utf82utf16($char);
424
                            $ascii .= sprintf('\u%04s', bin2hex($utf16));
425
                            break;
426
                    }
427
                }
428
429
                return '"'.$ascii.'"';
430
431
            case 'array':
432
               /*
433
                * As per JSON spec if any array key is not an integer
434
                * we must treat the the whole array as an object. We
435
                * also try to catch a sparsely populated associative
436
                * array with numeric keys here because some JS engines
437
                * will create an array with empty indexes up to
438
                * max_index which can cause memory issues and because
439
                * the keys, which may be relevant, will be remapped
440
                * otherwise.
441
                *
442
                * As per the ECMA and JSON specification an object may
443
                * have any string as a property. Unfortunately due to
444
                * a hole in the ECMA specification if the key is a
445
                * ECMA reserved word or starts with a digit the
446
                * parameter is only accessible using ECMAScript's
447
                * bracket notation.
448
                */
449
450
                // treat as a JSON object
451
                if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
452
                    $properties = array_map(array($this, 'name_value'),
453
                                            array_keys($var),
454
                                            array_values($var));
455
456
                    foreach($properties as $property) {
457
                        if(Services_JSON::isError($property)) {
458
                            return $property;
459
                        }
460
                    }
461
462
                    return '{' . join(',', $properties) . '}';
463
                }
464
465
                // treat it like a regular array
466
                $elements = array_map(array($this, 'encode'), $var);
467
468
                foreach($elements as $element) {
469
                    if(Services_JSON::isError($element)) {
470
                        return $element;
471
                    }
472
                }
473
474
                return '[' . join(',', $elements) . ']';
475
476
            case 'object':
477
                $vars = get_object_vars($var);
478
479
                $properties = array_map(array($this, 'name_value'),
480
                                        array_keys($vars),
481
                                        array_values($vars));
482
483
                foreach($properties as $property) {
484
                    if(Services_JSON::isError($property)) {
485
                        return $property;
486
                    }
487
                }
488
489
                return '{' . join(',', $properties) . '}';
490
491
            default:
492
                return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
493
                    ? 'null'
494
                    : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
495
        }
496
    }
497
498
   /**
499
    * array-walking function for use in generating JSON-formatted name-value pairs
500
    *
501
    * @param    string  $name   name of key to use
502
    * @param    mixed   $value  reference to an array element to be encoded
503
    *
504
    * @return   string  JSON-formatted name-value pair, like '"name":value'
505
    * @access   private
506
    */
507
    protected function name_value($name, $value)
508
    {
509
        $encoded_value = $this->encode($value);
510
511
        if(Services_JSON::isError($encoded_value)) {
512
            return $encoded_value;
513
        }
514
515
        return $this->encode(strval($name)) . ':' . $encoded_value;
516
    }
517
518
   /**
519
    * reduce a string by removing leading and trailing comments and whitespace
520
    *
521
    * @param    $str    string      string value to strip of comments and whitespace
522
    *
523
    * @return   string  string value stripped of comments and whitespace
524
    * @access   private
525
    */
526
    protected function reduce_string($str)
527
    {
528
        $str = preg_replace(array(
529
530
                // eliminate single line comments in '// ...' form
531
                '#^\s*//(.+)$#m',
532
533
                // eliminate multi-line comments in '/* ... */' form, at start of string
534
                '#^\s*/\*(.+)\*/#Us',
535
536
                // eliminate multi-line comments in '/* ... */' form, at end of string
537
                '#/\*(.+)\*/\s*$#Us'
538
539
            ), '', $str);
540
541
        // eliminate extraneous space
542
        return trim($str);
543
    }
544
545
   /**
546
    * decodes a JSON string into appropriate variable
547
    *
548
    * @param    string  $str    JSON-formatted string
549
    *
550
    * @return   mixed   number, boolean, string, array, or object
551
    *                   corresponding to given JSON input string.
552
    *                   See argument 1 to Services_JSON() above for object-output behavior.
553
    *                   Note that decode() always returns strings
554
    *                   in ASCII or UTF-8 format!
555
    * @access   public
556
    */
557
    public function decode($str)
558
    {
559
        $str = $this->reduce_string($str);
560
561
        switch (strtolower($str)) {
562
            case 'true':
563
                return true;
564
565
            case 'false':
566
                return false;
567
568
            case 'null':
569
                return null;
570
571
            default:
572
                $m = array();
573
574
                if (is_numeric($str)) {
575
                    // Lookie-loo, it's a number
576
577
                    // This would work on its own, but I'm trying to be
578
                    // good about returning integers where appropriate:
579
                    // return (float)$str;
580
581
                    // Return float or int, as appropriate
582
                    return ((float)$str == (integer)$str)
583
                        ? (integer)$str
584
                        : (float)$str;
585
586
                } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
587
                    // STRINGS RETURNED IN UTF-8 FORMAT
588
                    $delim = substr($str, 0, 1);
589
                    $chrs = substr($str, 1, -1);
590
                    $utf8 = '';
591
                    $strlen_chrs = strlen($chrs);
592
593
                    for ($c = 0; $c < $strlen_chrs; ++$c) {
594
595
                        $substr_chrs_c_2 = substr($chrs, $c, 2);
596
                        $ord_chrs_c = ord($chrs{$c});
597
598
                        switch (true) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing preg_match('/\\\\u[0-9A-..., substr($chrs, $c, 6)) 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...
599
                            case $substr_chrs_c_2 == '\b':
600
                                $utf8 .= chr(0x08);
601
                                ++$c;
602
                                break;
603
                            case $substr_chrs_c_2 == '\t':
604
                                $utf8 .= chr(0x09);
605
                                ++$c;
606
                                break;
607
                            case $substr_chrs_c_2 == '\n':
608
                                $utf8 .= chr(0x0A);
609
                                ++$c;
610
                                break;
611
                            case $substr_chrs_c_2 == '\f':
612
                                $utf8 .= chr(0x0C);
613
                                ++$c;
614
                                break;
615
                            case $substr_chrs_c_2 == '\r':
616
                                $utf8 .= chr(0x0D);
617
                                ++$c;
618
                                break;
619
620
                            case $substr_chrs_c_2 == '\\"':
621
                            case $substr_chrs_c_2 == '\\\'':
622
                            case $substr_chrs_c_2 == '\\\\':
623
                            case $substr_chrs_c_2 == '\\/':
624
                                if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
625
                                   ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
626
                                    $utf8 .= $chrs{++$c};
627
                                }
628
                                break;
629
630
                            case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
631
                                // single, escaped unicode character
632
                                $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
633
                                       . chr(hexdec(substr($chrs, ($c + 4), 2)));
634
                                $utf8 .= $this->utf162utf8($utf16);
635
                                $c += 5;
636
                                break;
637
638
                            case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
639
                                $utf8 .= $chrs{$c};
640
                                break;
641
642 View Code Duplication
                            case ($ord_chrs_c & 0xE0) == 0xC0:
643
                                // characters U-00000080 - U-000007FF, mask 110XXXXX
644
                                //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
645
                                $utf8 .= substr($chrs, $c, 2);
646
                                ++$c;
647
                                break;
648
649 View Code Duplication
                            case ($ord_chrs_c & 0xF0) == 0xE0:
650
                                // characters U-00000800 - U-0000FFFF, mask 1110XXXX
651
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
652
                                $utf8 .= substr($chrs, $c, 3);
653
                                $c += 2;
654
                                break;
655
656 View Code Duplication
                            case ($ord_chrs_c & 0xF8) == 0xF0:
657
                                // characters U-00010000 - U-001FFFFF, mask 11110XXX
658
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
659
                                $utf8 .= substr($chrs, $c, 4);
660
                                $c += 3;
661
                                break;
662
663 View Code Duplication
                            case ($ord_chrs_c & 0xFC) == 0xF8:
664
                                // characters U-00200000 - U-03FFFFFF, mask 111110XX
665
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
666
                                $utf8 .= substr($chrs, $c, 5);
667
                                $c += 4;
668
                                break;
669
670 View Code Duplication
                            case ($ord_chrs_c & 0xFE) == 0xFC:
671
                                // characters U-04000000 - U-7FFFFFFF, mask 1111110X
672
                                // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
673
                                $utf8 .= substr($chrs, $c, 6);
674
                                $c += 5;
675
                                break;
676
677
                        }
678
679
                    }
680
681
                    return $utf8;
682
683
                } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
684
                    // array, or object notation
685
686
                    if ($str{0} == '[') {
687
                        $stk = array(SERVICES_JSON_IN_ARR);
688
                        $arr = array();
689
                    } else {
690
                        if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
691
                            $stk = array(SERVICES_JSON_IN_OBJ);
692
                            $obj = array();
693
                        } else {
694
                            $stk = array(SERVICES_JSON_IN_OBJ);
695
                            $obj = new stdClass();
696
                        }
697
                    }
698
699
                    array_push($stk, array('what'  => SERVICES_JSON_SLICE,
700
                                           'where' => 0,
701
                                           'delim' => false));
702
703
                    $chrs = substr($str, 1, -1);
704
                    $chrs = $this->reduce_string($chrs);
705
706
                    if ($chrs == '') {
707
                        if (reset($stk) == SERVICES_JSON_IN_ARR) {
708
                            return $arr;
0 ignored issues
show
The variable $arr 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...
709
710
                        } else {
711
                            return $obj;
0 ignored issues
show
The variable $obj 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...
712
713
                        }
714
                    }
715
716
                    //print("\nparsing {$chrs}\n");
717
718
                    $strlen_chrs = strlen($chrs);
719
720
                    for ($c = 0; $c <= $strlen_chrs; ++$c) {
721
722
                        $top = end($stk);
723
                        $substr_chrs_c_2 = substr($chrs, $c, 2);
724
725
                        if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
726
                            // found a comma that is not inside a string, array, etc.,
727
                            // OR we've reached the end of the character list
728
                            $slice = substr($chrs, $top['where'], ($c - $top['where']));
729
                            array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
730
                            //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
731
732
                            if (reset($stk) == SERVICES_JSON_IN_ARR) {
733
                                // we are in an array, so just push an element onto the stack
734
                                array_push($arr, $this->decode($slice));
735
736
                            } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
737
                                // we are in an object, so figure
738
                                // out the property name and set an
739
                                // element in an associative array,
740
                                // for now
741
                                $parts = array();
742
743
                                if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
744
                                    // "name":value pair
745
                                    $key = $this->decode($parts[1]);
746
                                    $val = $this->decode($parts[2]);
747
748 View Code Duplication
                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
749
                                        $obj[$key] = $val;
750
                                    } else {
751
                                        $obj->$key = $val;
752
                                    }
753
                                } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
754
                                    // name:value pair, where name is unquoted
755
                                    $key = $parts[1];
756
                                    $val = $this->decode($parts[2]);
757
758 View Code Duplication
                                    if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
759
                                        $obj[$key] = $val;
760
                                    } else {
761
                                        $obj->$key = $val;
762
                                    }
763
                                }
764
765
                            }
766
767
                        } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
768
                            // found a quote, and we are not inside a string
769
                            array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
770
                            //print("Found start of string at {$c}\n");
771
772
                        } elseif (($chrs{$c} == $top['delim']) &&
773
                                 ($top['what'] == SERVICES_JSON_IN_STR) &&
774
                                 ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
775
                            // found a quote, we're in a string, and it's not escaped
776
                            // we know that it's not escaped becase there is _not_ an
777
                            // odd number of backslashes at the end of the string so far
778
                            array_pop($stk);
779
                            //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
780
781 View Code Duplication
                        } elseif (($chrs{$c} == '[') &&
782
                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
783
                            // found a left-bracket, and we are in an array, object, or slice
784
                            array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
785
                            //print("Found start of array at {$c}\n");
786
787
                        } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
788
                            // found a right-bracket, and we're in an array
789
                            array_pop($stk);
790
                            //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
791
792 View Code Duplication
                        } elseif (($chrs{$c} == '{') &&
793
                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
794
                            // found a left-brace, and we are in an array, object, or slice
795
                            array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
796
                            //print("Found start of object at {$c}\n");
797
798
                        } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
799
                            // found a right-brace, and we're in an object
800
                            array_pop($stk);
801
                            //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
802
803 View Code Duplication
                        } elseif (($substr_chrs_c_2 == '/*') &&
804
                                 in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
805
                            // found a comment start, and we are in an array, object, or slice
806
                            array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
807
                            $c++;
808
                            //print("Found start of comment at {$c}\n");
809
810
                        } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
811
                            // found a comment end, and we're in one now
812
                            array_pop($stk);
813
                            $c++;
814
815
                            for ($i = $top['where']; $i <= $c; ++$i)
816
                                $chrs = substr_replace($chrs, ' ', $i, 1);
817
818
                            //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
819
820
                        }
821
822
                    }
823
824
                    if (reset($stk) == SERVICES_JSON_IN_ARR) {
825
                        return $arr;
826
827
                    } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
828
                        return $obj;
829
830
                    }
831
832
                }
833
        }
834
    }
835
836
    /**
837
     * @todo Ultimately, this should just call PEAR::isError()
838
     */
839
    public function isError($data, $code = null)
840
    {
841
        return PEAR::isError($data, $code);
842
    }
843
}
844
845
class Services_JSON_Error extends PEAR_Error
846
{
847
    function __construct($message = 'unknown error', $code = null,
848
                                 $mode = null, $options = null, $userinfo = null)
849
    {
850
        parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
851
    }
852
}
853