GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

FirePHP   F
last analyzed

Complexity

Total Complexity 252

Size/Duplication

Total Lines 1472
Duplicated Lines 2.79 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 0
Metric Value
dl 41
loc 1472
rs 0.8
c 0
b 0
f 0
wmc 252
lcom 2
cbo 0

41 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 2 1
A __sleep() 0 3 1
A getInstance() 0 6 3
A init() 0 3 1
A setEnabled() 0 3 1
A getEnabled() 0 3 1
A setObjectFilter() 0 3 1
A setOptions() 0 3 1
A getOptions() 0 3 1
A registerErrorHandler() 0 11 1
A errorHandler() 0 17 4
A registerExceptionHandler() 0 4 1
A exceptionHandler() 0 10 1
A registerAssertionHandler() 0 11 3
A assertionHandler() 0 19 3
A setProcessorUrl() 0 4 1
A setRendererUrl() 0 4 1
A group() 0 17 6
A groupEnd() 0 3 1
A log() 0 3 1
A info() 0 3 1
A warn() 0 3 1
A error() 0 3 1
A dump() 0 3 1
A trace() 0 3 1
A table() 0 3 1
A detectClientExtension() 0 8 3
F fb() 6 262 96
A _standardizePath() 0 3 1
A _escapeTrace() 0 12 5
A _escapeTraceFile() 0 11 2
A setHeader() 0 3 1
A getUserAgent() 0 4 2
A newException() 0 3 1
A jsonEncode() 0 14 4
A encodeTable() 0 20 5
F encodeObject() 5 132 32
C is_utf8() 0 25 13
A json_utf82utf16() 0 32 5
F json_encode() 25 205 37
A json_name_value() 5 20 5

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FirePHP often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FirePHP, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * *** BEGIN LICENSE BLOCK *****
4
 *  
5
 * This file is part of FirePHP (http://www.firephp.org/).
6
 * 
7
 * Software License Agreement (New BSD License)
8
 * 
9
 * Copyright (c) 2006-2009, Christoph Dorn
10
 * All rights reserved.
11
 * 
12
 * Redistribution and use in source and binary forms, with or without modification,
13
 * are permitted provided that the following conditions are met:
14
 * 
15
 *     * Redistributions of source code must retain the above copyright notice,
16
 *       this list of conditions and the following disclaimer.
17
 * 
18
 *     * Redistributions in binary form must reproduce the above copyright notice,
19
 *       this list of conditions and the following disclaimer in the documentation
20
 *       and/or other materials provided with the distribution.
21
 * 
22
 *     * Neither the name of Christoph Dorn nor the names of its
23
 *       contributors may be used to endorse or promote products derived from this
24
 *       software without specific prior written permission.
25
 * 
26
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
30
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
33
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
 * 
37
 * ***** END LICENSE BLOCK *****
38
 * 
39
 * @copyright   Copyright (C) 2007-2009 Christoph Dorn
40
 * @author      Christoph Dorn <[email protected]>
41
 * @license     http://www.opensource.org/licenses/bsd-license.php
42
 * @package     FirePHP
43
 */
44
 
45
 
46
/**
47
 * Sends the given data to the FirePHP Firefox Extension.
48
 * The data can be displayed in the Firebug Console or in the
49
 * "Server" request tab.
50
 * 
51
 * For more information see: http://www.firephp.org/
52
 * 
53
 * @copyright   Copyright (C) 2007-2009 Christoph Dorn
54
 * @author      Christoph Dorn <[email protected]>
55
 * @license     http://www.opensource.org/licenses/bsd-license.php
56
 * @package     FirePHP
57
 */
58
class FirePHP {
59
  
60
  /**
61
   * FirePHP version
62
   *
63
   * @var string
64
   */
65
  const VERSION = '0.3';
66
  
67
  /**
68
   * Firebug LOG level
69
   *
70
   * Logs a message to firebug console.
71
   * 
72
   * @var string
73
   */
74
  const LOG = 'LOG';
75
  
76
  /**
77
   * Firebug INFO level
78
   *
79
   * Logs a message to firebug console and displays an info icon before the message.
80
   * 
81
   * @var string
82
   */
83
  const INFO = 'INFO';
84
  
85
  /**
86
   * Firebug WARN level
87
   *
88
   * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
89
   * 
90
   * @var string
91
   */
92
  const WARN = 'WARN';
93
  
94
  /**
95
   * Firebug ERROR level
96
   *
97
   * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
98
   * 
99
   * @var string
100
   */
101
  const ERROR = 'ERROR';
102
  
103
  /**
104
   * Dumps a variable to firebug's server panel
105
   *
106
   * @var string
107
   */
108
  const DUMP = 'DUMP';
109
  
110
  /**
111
   * Displays a stack trace in firebug console
112
   *
113
   * @var string
114
   */
115
  const TRACE = 'TRACE';
116
  
117
  /**
118
   * Displays an exception in firebug console
119
   * 
120
   * Increments the firebug error count.
121
   *
122
   * @var string
123
   */
124
  const EXCEPTION = 'EXCEPTION';
125
  
126
  /**
127
   * Displays an table in firebug console
128
   *
129
   * @var string
130
   */
131
  const TABLE = 'TABLE';
132
  
133
  /**
134
   * Starts a group in firebug console
135
   * 
136
   * @var string
137
   */
138
  const GROUP_START = 'GROUP_START';
139
  
140
  /**
141
   * Ends a group in firebug console
142
   * 
143
   * @var string
144
   */
145
  const GROUP_END = 'GROUP_END';
146
  
147
  /**
148
   * Singleton instance of FirePHP
149
   *
150
   * @var FirePHP
151
   */
152
  protected static $instance = null;
153
  
154
  /**
155
   * Flag whether we are logging from within the exception handler
156
   * 
157
   * @var boolean
158
   */
159
  protected $inExceptionHandler = false;
160
  
161
  /**
162
   * Flag whether to throw PHP errors that have been converted to ErrorExceptions
163
   * 
164
   * @var boolean
165
   */
166
  protected $throwErrorExceptions = true;
167
  
168
  /**
169
   * Flag whether to convert PHP assertion errors to Exceptions
170
   * 
171
   * @var boolean
172
   */
173
  protected $convertAssertionErrorsToExceptions = true;
174
  
175
  /**
176
   * Flag whether to throw PHP assertion errors that have been converted to Exceptions
177
   * 
178
   * @var boolean
179
   */
180
  protected $throwAssertionExceptions = false;
181
  
182
  /**
183
   * Wildfire protocol message index
184
   *
185
   * @var int
186
   */
187
  protected $messageIndex = 1;
188
    
189
  /**
190
   * Options for the library
191
   * 
192
   * @var array
193
   */
194
  protected $options = array('maxObjectDepth' => 10,
195
                             'maxArrayDepth' => 20,
196
                             'useNativeJsonEncode' => true,
197
                             'includeLineNumbers' => true);
198
199
  /**
200
   * Filters used to exclude object members when encoding
201
   * 
202
   * @var array
203
   */
204
  protected $objectFilters = array();
205
  
206
  /**
207
   * A stack of objects used to detect recursion during object encoding
208
   * 
209
   * @var object
210
   */
211
  protected $objectStack = array();
212
  
213
  /**
214
   * Flag to enable/disable logging
215
   * 
216
   * @var boolean
217
   */
218
  protected $enabled = true;
219
220
  /**
221
   * The object constructor
222
   */
223
  function __construct() {
224
  }
225
226
  /**
227
   * When the object gets serialized only include specific object members.
228
   * 
229
   * @return array
230
   */  
231
  public function __sleep() {
232
    return array('options','objectFilters','enabled');
233
  }
234
    
235
  /**
236
   * Gets singleton instance of FirePHP
237
   *
238
   * @param boolean $AutoCreate
239
   * @return FirePHP
240
   */
241
  public static function getInstance($AutoCreate=false) {
242
    if($AutoCreate===true && !self::$instance) {
243
      self::init();
244
    }
245
    return self::$instance;
246
  }
247
   
248
  /**
249
   * Creates FirePHP object and stores it for singleton access
250
   *
251
   * @return FirePHP
252
   */
253
  public static function init() {
254
    return self::$instance = new self();
255
  }
256
  
257
  /**
258
   * Enable and disable logging to Firebug
259
   * 
260
   * @param boolean $Enabled TRUE to enable, FALSE to disable
261
   * @return void
262
   */
263
  public function setEnabled($Enabled) {
264
    $this->enabled = $Enabled;
265
  }
266
  
267
  /**
268
   * Check if logging is enabled
269
   * 
270
   * @return boolean TRUE if enabled
271
   */
272
  public function getEnabled() {
273
    return $this->enabled;
274
  }
275
  
276
  /**
277
   * Specify a filter to be used when encoding an object
278
   * 
279
   * Filters are used to exclude object members.
280
   * 
281
   * @param string $Class The class name of the object
282
   * @param array $Filter An array of members to exclude
283
   * @return void
284
   */
285
  public function setObjectFilter($Class, $Filter) {
286
    $this->objectFilters[strtolower($Class)] = $Filter;
287
  }
288
  
289
  /**
290
   * Set some options for the library
291
   * 
292
   * Options:
293
   *  - maxObjectDepth: The maximum depth to traverse objects (default: 10)
294
   *  - maxArrayDepth: The maximum depth to traverse arrays (default: 20)
295
   *  - useNativeJsonEncode: If true will use json_encode() (default: true)
296
   *  - includeLineNumbers: If true will include line numbers and filenames (default: true)
297
   * 
298
   * @param array $Options The options to be set
299
   * @return void
300
   */
301
  public function setOptions($Options) {
302
    $this->options = array_merge($this->options,$Options);
303
  }
304
  
305
  /**
306
   * Get options from the library
307
   *
308
   * @return array The currently set options
309
   */
310
  public function getOptions() {
311
    return $this->options;
312
  }
313
  
314
  /**
315
   * Register FirePHP as your error handler
316
   * 
317
   * Will throw exceptions for each php error.
318
   * 
319
   * @return mixed Returns a string containing the previously defined error handler (if any)
320
   */
321
  public function registerErrorHandler($throwErrorExceptions=true)
322
  {
323
    //NOTE: The following errors will not be caught by this error handler:
324
    //      E_ERROR, E_PARSE, E_CORE_ERROR,
325
    //      E_CORE_WARNING, E_COMPILE_ERROR,
326
    //      E_COMPILE_WARNING, E_STRICT
327
    
328
    $this->throwErrorExceptions = $throwErrorExceptions;
329
    
330
    return set_error_handler(array($this,'errorHandler'));     
331
  }
332
333
  /**
334
   * FirePHP's error handler
335
   * 
336
   * Throws exception for each php error that will occur.
337
   *
338
   * @param int $errno
339
   * @param string $errstr
340
   * @param string $errfile
341
   * @param int $errline
342
   * @param array $errcontext
343
   */
344
  public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
0 ignored issues
show
Unused Code introduced by
The parameter $errcontext 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...
345
  {
346
    // Don't throw exception if error reporting is switched off
347
    if (error_reporting() == 0) {
348
      return;
349
    }
350
    // Only throw exceptions for errors we are asking for
351
    if (error_reporting() & $errno) {
352
353
      $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
354
      if($this->throwErrorExceptions) {
355
        throw $exception;
356
      } else {
357
        $this->fb($exception);
358
      }
359
    }
360
  }
361
  
362
  /**
363
   * Register FirePHP as your exception handler
364
   * 
365
   * @return mixed Returns the name of the previously defined exception handler,
366
   *               or NULL on error.
367
   *               If no previous handler was defined, NULL is also returned.
368
   */
369
  public function registerExceptionHandler()
370
  {
371
    return set_exception_handler(array($this,'exceptionHandler'));     
372
  }
373
  
374
  /**
375
   * FirePHP's exception handler
376
   * 
377
   * Logs all exceptions to your firebug console and then stops the script.
378
   *
379
   * @param Exception $Exception
380
   * @throws Exception
381
   */
382
  function exceptionHandler($Exception) {
383
    
384
    $this->inExceptionHandler = true;
385
386
    header('HTTP/1.1 500 Internal Server Error');
387
388
    $this->fb($Exception);
389
    
390
    $this->inExceptionHandler = false;
391
  }
392
  
393
  /**
394
   * Register FirePHP driver as your assert callback
395
   * 
396
   * @param boolean $convertAssertionErrorsToExceptions
397
   * @param boolean $throwAssertionExceptions
398
   * @return mixed Returns the original setting or FALSE on errors
399
   */
400
  public function registerAssertionHandler($convertAssertionErrorsToExceptions=true, $throwAssertionExceptions=false)
401
  {
402
    $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions;
403
    $this->throwAssertionExceptions = $throwAssertionExceptions;
404
    
405
    if($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) {
406
      throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!');
407
    }
408
    
409
    return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
410
  }
411
  
412
  /**
413
   * FirePHP's assertion handler
414
   *
415
   * Logs all assertions to your firebug console and then stops the script.
416
   *
417
   * @param string $file File source of assertion
418
   * @param int    $line Line source of assertion
419
   * @param mixed  $code Assertion code
420
   */
421
  public function assertionHandler($file, $line, $code)
422
  {
423
424
    if($this->convertAssertionErrorsToExceptions) {
425
      
426
      $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line);
427
428
      if($this->throwAssertionExceptions) {
429
        throw $exception;
430
      } else {
431
        $this->fb($exception);
432
      }
433
    
434
    } else {
435
    
436
      $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line));
437
    
438
    }
439
  }  
440
  
441
  /**
442
   * Set custom processor url for FirePHP
443
   *
444
   * @param string $URL
445
   */    
446
  public function setProcessorUrl($URL)
447
  {
448
    $this->setHeader('X-FirePHP-ProcessorURL', $URL);
0 ignored issues
show
Documentation introduced by
$URL is of type string, but the function expects a object<string_type>.

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...
449
  }
450
451
  /**
452
   * Set custom renderer url for FirePHP
453
   *
454
   * @param string $URL
455
   */
456
  public function setRendererUrl($URL)
457
  {
458
    $this->setHeader('X-FirePHP-RendererURL', $URL);
0 ignored issues
show
Documentation introduced by
$URL is of type string, but the function expects a object<string_type>.

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...
459
  }
460
  
461
  /**
462
   * Start a group for following messages.
463
   * 
464
   * Options:
465
   *   Collapsed: [true|false]
466
   *   Color:     [#RRGGBB|ColorName]
467
   *
468
   * @param string $Name
469
   * @param array $Options OPTIONAL Instructions on how to log the group
470
   * @return true
471
   * @throws Exception
472
   */
473
  public function group($Name, $Options=null) {
474
    
475
    if(!$Name) {
476
      throw $this->newException('You must specify a label for the group!');
477
    }
478
    
479
    if($Options) {
480
      if(!is_array($Options)) {
481
        throw $this->newException('Options must be defined as an array!');
482
      }
483
      if(array_key_exists('Collapsed', $Options)) {
484
        $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false';
485
      }
486
    }
487
    
488
    return $this->fb(null, $Name, FirePHP::GROUP_START, $Options);
489
  }
490
  
491
  /**
492
   * Ends a group you have started before
493
   *
494
   * @return true
495
   * @throws Exception
496
   */
497
  public function groupEnd() {
498
    return $this->fb(null, null, FirePHP::GROUP_END);
499
  }
500
501
  /**
502
   * Log object with label to firebug console
503
   *
504
   * @see FirePHP::LOG
505
   * @param mixes $Object
506
   * @param string $Label
507
   * @return true
508
   * @throws Exception
509
   */
510
  public function log($Object, $Label=null) {
511
    return $this->fb($Object, $Label, FirePHP::LOG);
512
  } 
513
514
  /**
515
   * Log object with label to firebug console
516
   *
517
   * @see FirePHP::INFO
518
   * @param mixes $Object
519
   * @param string $Label
520
   * @return true
521
   * @throws Exception
522
   */
523
  public function info($Object, $Label=null) {
524
    return $this->fb($Object, $Label, FirePHP::INFO);
525
  } 
526
527
  /**
528
   * Log object with label to firebug console
529
   *
530
   * @see FirePHP::WARN
531
   * @param mixes $Object
532
   * @param string $Label
533
   * @return true
534
   * @throws Exception
535
   */
536
  public function warn($Object, $Label=null) {
537
    return $this->fb($Object, $Label, FirePHP::WARN);
538
  } 
539
540
  /**
541
   * Log object with label to firebug console
542
   *
543
   * @see FirePHP::ERROR
544
   * @param mixes $Object
545
   * @param string $Label
546
   * @return true
547
   * @throws Exception
548
   */
549
  public function error($Object, $Label=null) {
550
    return $this->fb($Object, $Label, FirePHP::ERROR);
551
  } 
552
553
  /**
554
   * Dumps key and variable to firebug server panel
555
   *
556
   * @see FirePHP::DUMP
557
   * @param string $Key
558
   * @param mixed $Variable
559
   * @return true
560
   * @throws Exception
561
   */
562
  public function dump($Key, $Variable) {
563
    return $this->fb($Variable, $Key, FirePHP::DUMP);
564
  }
565
  
566
  /**
567
   * Log a trace in the firebug console
568
   *
569
   * @see FirePHP::TRACE
570
   * @param string $Label
571
   * @return true
572
   * @throws Exception
573
   */
574
  public function trace($Label) {
575
    return $this->fb($Label, FirePHP::TRACE);
576
  } 
577
578
  /**
579
   * Log a table in the firebug console
580
   *
581
   * @see FirePHP::TABLE
582
   * @param string $Label
583
   * @param string $Table
584
   * @return true
585
   * @throws Exception
586
   */
587
  public function table($Label, $Table) {
588
    return $this->fb($Table, $Label, FirePHP::TABLE);
589
  }
590
  
591
  /**
592
   * Check if FirePHP is installed on client
593
   *
594
   * @return boolean
595
   */
596
  public function detectClientExtension() {
597
    /* Check if FirePHP is installed on client */
598
    if(!@preg_match_all('/\sFirePHP\/([\.|\d]*)\s?/si',$this->getUserAgent(),$m) ||
599
       !version_compare($m[1][0],'0.0.6','>=')) {
600
      return false;
601
    }
602
    return true;    
603
  }
604
 
605
  /**
606
   * Log varible to Firebug
607
   * 
608
   * @see http://www.firephp.org/Wiki/Reference/Fb
609
   * @param mixed $Object The variable to be logged
610
   * @return true Return TRUE if message was added to headers, FALSE otherwise
611
   * @throws Exception
612
   */
613
  public function fb($Object) {
614
  
615
    if(!$this->enabled) {
616
      return false;
617
    }
618
  
619
    if (headers_sent($filename, $linenum)) {
620
      // If we are logging from within the exception handler we cannot throw another exception
621
      if($this->inExceptionHandler) {
622
        // Simply echo the error out to the page
623
        echo '<div style="border: 2px solid red; font-family: Arial; font-size: 12px; background-color: lightgray; padding: 5px;"><span style="color: red; font-weight: bold;">FirePHP ERROR:</span> Headers already sent in <b>'.$filename.'</b> on line <b>'.$linenum.'</b>. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.</div>';
624
      } else {
625
        throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.');
626
      }
627
    }
628
  
629
    $Type = null;
630
    $Label = null;
631
    $Options = array();
632
  
633
    if(func_num_args()==1) {
634
    } else
635
    if(func_num_args()==2) {
636
      switch(func_get_arg(1)) {
637
        case self::LOG:
638
        case self::INFO:
639
        case self::WARN:
640
        case self::ERROR:
641
        case self::DUMP:
642
        case self::TRACE:
643
        case self::EXCEPTION:
644
        case self::TABLE:
645
        case self::GROUP_START:
646
        case self::GROUP_END:
647
          $Type = func_get_arg(1);
648
          break;
649
        default:
650
          $Label = func_get_arg(1);
651
          break;
652
      }
653
    } else
654
    if(func_num_args()==3) {
655
      $Type = func_get_arg(2);
656
      $Label = func_get_arg(1);
657
    } else
658
    if(func_num_args()==4) {
659
      $Type = func_get_arg(2);
660
      $Label = func_get_arg(1);
661
      $Options = func_get_arg(3);
662
    } else {
663
      throw $this->newException('Wrong number of arguments to fb() function!');
664
    }
665
  
666
  
667
    if(!$this->detectClientExtension()) {
668
      return false;
669
    }
670
  
671
    $meta = array();
672
    $skipFinalObjectEncode = false;
673
  
674
    if($Object instanceof Exception) {
675
676
      $meta['file'] = $this->_escapeTraceFile($Object->getFile());
677
      $meta['line'] = $Object->getLine();
678
      
679
      $trace = $Object->getTrace();
680
      if($Object instanceof ErrorException
681
         && isset($trace[0]['function'])
682
         && $trace[0]['function']=='errorHandler'
683
         && isset($trace[0]['class'])
684
         && $trace[0]['class']=='FirePHP') {
685
           
686
        $severity = false;
687
        switch($Object->getSeverity()) {
688
          case E_WARNING: $severity = 'E_WARNING'; break;
689
          case E_NOTICE: $severity = 'E_NOTICE'; break;
690
          case E_USER_ERROR: $severity = 'E_USER_ERROR'; break;
691
          case E_USER_WARNING: $severity = 'E_USER_WARNING'; break;
692
          case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break;
693
          case E_STRICT: $severity = 'E_STRICT'; break;
694
          case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break;
695
          case E_DEPRECATED: $severity = 'E_DEPRECATED'; break;
696
          case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break;
697
        }
698
           
699
        $Object = array('Class'=>get_class($Object),
700
                        'Message'=>$severity.': '.$Object->getMessage(),
701
                        'File'=>$this->_escapeTraceFile($Object->getFile()),
702
                        'Line'=>$Object->getLine(),
703
                        'Type'=>'trigger',
704
                        'Trace'=>$this->_escapeTrace(array_splice($trace,2)));
705
        $skipFinalObjectEncode = true;
706
      } else {
707
        $Object = array('Class'=>get_class($Object),
708
                        'Message'=>$Object->getMessage(),
709
                        'File'=>$this->_escapeTraceFile($Object->getFile()),
710
                        'Line'=>$Object->getLine(),
711
                        'Type'=>'throw',
712
                        'Trace'=>$this->_escapeTrace($trace));
713
        $skipFinalObjectEncode = true;
714
      }
715
      $Type = self::EXCEPTION;
716
      
717
    } else
718
    if($Type==self::TRACE) {
719
      
720
      $trace = debug_backtrace();
721
      if(!$trace) return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression $trace 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...
722
      for( $i=0 ; $i<sizeof($trace) ; $i++ ) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() 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...
723
724
        if(isset($trace[$i]['class'])
725
           && isset($trace[$i]['file'])
726
           && ($trace[$i]['class']=='FirePHP'
727
               || $trace[$i]['class']=='FB')
728
           && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
729
               || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
730
          /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
731
        } else
732
        if(isset($trace[$i]['class'])
733
           && isset($trace[$i+1]['file'])
734
           && $trace[$i]['class']=='FirePHP'
735
           && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
736
          /* Skip fb() */
737
        } else
738
        if($trace[$i]['function']=='fb'
739
           || $trace[$i]['function']=='trace'
740
           || $trace[$i]['function']=='send') {
741
          $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'',
742
                          'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'',
743
                          'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'',
744
                          'Message'=>$trace[$i]['args'][0],
745
                          'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'',
746
                          'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'',
747
                          'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'',
748
                          'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1)));
749
750
          $skipFinalObjectEncode = true;
751
          $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
752
          $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
753
          break;
754
        }
755
      }
756
757
    } else
758
    if($Type==self::TABLE) {
759
      
760
      if(isset($Object[0]) && is_string($Object[0])) {
761
        $Object[1] = $this->encodeTable($Object[1]);
762
      } else {
763
        $Object = $this->encodeTable($Object);
764
      }
765
766
      $skipFinalObjectEncode = true;
767
      
768
    } else
769
    if($Type==self::GROUP_START) {
770
      
771
      if(!$Label) {
772
        throw $this->newException('You must specify a label for the group!');
773
      }
774
      
775
    } else {
776
      if($Type===null) {
777
        $Type = self::LOG;
778
      }
779
    }
780
    
781
    if($this->options['includeLineNumbers']) {
782
      if(!isset($meta['file']) || !isset($meta['line'])) {
783
784
        $trace = debug_backtrace();
785
        for( $i=0 ; $trace && $i<sizeof($trace) ; $i++ ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $trace 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...
786
  
787
          if(isset($trace[$i]['class'])
788
             && isset($trace[$i]['file'])
789
             && ($trace[$i]['class']=='FirePHP'
790
                 || $trace[$i]['class']=='FB')
791
             && (substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php'
792
                 || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) {
793
            /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
794
          } else
795
          if(isset($trace[$i]['class'])
796
             && isset($trace[$i+1]['file'])
797
             && $trace[$i]['class']=='FirePHP'
798
             && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') {
799
            /* Skip fb() */
800
          } else
801
          if(isset($trace[$i]['file'])
802
             && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') {
803
            /* Skip FB::fb() */
804
          } else {
805
            $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'';
806
            $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:'';
807
            break;
808
          }
809
        }      
810
      
811
      }
812
    } else {
813
      unset($meta['file']);
814
      unset($meta['line']);
815
    }
816
817
  	$this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
0 ignored issues
show
Documentation introduced by
'http://meta.wildfirehq....rotocol/JsonStream/0.2' is of type string, but the function expects a object<string_type>.

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...
818
  	$this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION);
0 ignored issues
show
Documentation introduced by
'http://meta.firephp.org...PCore/' . self::VERSION is of type string, but the function expects a object<string_type>.

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...
819
 
820
    $structure_index = 1;
821
    if($Type==self::DUMP) {
822
      $structure_index = 2;
823
    	$this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
0 ignored issues
show
Documentation introduced by
'http://meta.firephp.org...cture/FirePHP/Dump/0.1' is of type string, but the function expects a object<string_type>.

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...
824
    } else {
825
    	$this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
0 ignored issues
show
Documentation introduced by
'http://meta.firephp.org...PHP/FirebugConsole/0.1' is of type string, but the function expects a object<string_type>.

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...
826
    }
827
  
828
    if($Type==self::DUMP) {
829
    	$msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}';
830
    } else {
831
      $msg_meta = $Options;
832
      $msg_meta['Type'] = $Type;
833
      if($Label!==null) {
834
        $msg_meta['Label'] = $Label;
835
      }
836 View Code Duplication
      if(isset($meta['file']) && !isset($msg_meta['File'])) {
837
        $msg_meta['File'] = $meta['file'];
838
      }
839 View Code Duplication
      if(isset($meta['line']) && !isset($msg_meta['Line'])) {
840
        $msg_meta['Line'] = $meta['line'];
841
      }
842
    	$msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']';
843
    }
844
    
845
    $parts = explode("\n",chunk_split($msg, 5000, "\n"));
846
847
    for( $i=0 ; $i<count($parts) ; $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

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

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

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
848
        
849
        $part = $parts[$i];
850
        if ($part) {
851
            
852
            if(count($parts)>2) {
853
              // Message needs to be split into multiple parts
854
              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
855
                               (($i==0)?strlen($msg):'')
0 ignored issues
show
Documentation introduced by
($i == 0 ? strlen($msg) ...parts) - 2 ? '\\' : '') is of type string, but the function expects a object<string_type>.

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...
856
                               . '|' . $part . '|'
857
                               . (($i<count($parts)-2)?'\\':''));
858
            } else {
859
              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
860
                               strlen($part) . '|' . $part . '|');
0 ignored issues
show
Documentation introduced by
strlen($part) . '|' . $part . '|' is of type string, but the function expects a object<string_type>.

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...
861
            }
862
            
863
            $this->messageIndex++;
864
            
865
            if ($this->messageIndex > 99999) {
866
                throw $this->newException('Maximum number (99,999) of messages reached!');             
867
            }
868
        }
869
    }
870
871
  	$this->setHeader('X-Wf-1-Index',$this->messageIndex-1);
0 ignored issues
show
Documentation introduced by
$this->messageIndex - 1 is of type integer, but the function expects a object<string_type>.

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...
872
873
    return true;
874
  }
875
  
876
  /**
877
   * Standardizes path for windows systems.
878
   *
879
   * @param string $Path
880
   * @return string
881
   */
882
  protected function _standardizePath($Path) {
883
    return preg_replace('/\\\\+/','/',$Path);    
884
  }
885
  
886
  /**
887
   * Escape trace path for windows systems
888
   *
889
   * @param array $Trace
890
   * @return array
891
   */
892
  protected function _escapeTrace($Trace) {
893
    if(!$Trace) return $Trace;
0 ignored issues
show
Bug Best Practice introduced by
The expression $Trace 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...
894
    for( $i=0 ; $i<sizeof($Trace) ; $i++ ) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function sizeof() 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...
895
      if(isset($Trace[$i]['file'])) {
896
        $Trace[$i]['file'] = $this->_escapeTraceFile($Trace[$i]['file']);
897
      }
898
      if(isset($Trace[$i]['args'])) {
899
        $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']);
900
      }
901
    }
902
    return $Trace;    
903
  }
904
  
905
  /**
906
   * Escape file information of trace for windows systems
907
   *
908
   * @param string $File
909
   * @return string
910
   */
911
  protected function _escapeTraceFile($File) {
912
    /* Check if we have a windows filepath */
913
    if(strpos($File,'\\')) {
914
      /* First strip down to single \ */
915
      
916
      $file = preg_replace('/\\\\+/','\\',$File);
917
      
918
      return $file;
919
    }
920
    return $File;
921
  }
922
923
  /**
924
   * Send header
925
   *
926
   * @param string $Name
927
   * @param string_type $Value
928
   */
929
  protected function setHeader($Name, $Value) {
930
    return header($Name.': '.$Value);
931
  }
932
933
  /**
934
   * Get user agent
935
   *
936
   * @return string|false
937
   */
938
  protected function getUserAgent() {
939
    if(!isset($_SERVER['HTTP_USER_AGENT'])) return false;
940
    return $_SERVER['HTTP_USER_AGENT'];
941
  }
942
943
  /**
944
   * Returns a new exception
945
   *
946
   * @param string $Message
947
   * @return Exception
948
   */
949
  protected function newException($Message) {
950
    return new Exception($Message);
951
  }
952
  
953
  /**
954
   * Encode an object into a JSON string
955
   * 
956
   * Uses PHP's jeson_encode() if available
957
   * 
958
   * @param object $Object The object to be encoded
959
   * @return string The JSON string
960
   */
961
  public function jsonEncode($Object, $skipObjectEncode=false)
962
  {
963
    if(!$skipObjectEncode) {
964
      $Object = $this->encodeObject($Object);
965
    }
966
    
967
    if(function_exists('json_encode')
968
       && $this->options['useNativeJsonEncode']!=false) {
969
970
      return json_encode($Object);
971
    } else {
972
      return $this->json_encode($Object);
973
    }
974
  }
975
976
  /**
977
   * Encodes a table by encoding each row and column with encodeObject()
978
   * 
979
   * @param array $Table The table to be encoded
980
   * @return array
981
   */  
982
  protected function encodeTable($Table) {
983
    
984
    if(!$Table) return $Table;
0 ignored issues
show
Bug Best Practice introduced by
The expression $Table 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...
985
    
986
    $new_table = array();
987
    foreach($Table as $row) {
988
  
989
      if(is_array($row)) {
990
        $new_row = array();
991
        
992
        foreach($row as $item) {
993
          $new_row[] = $this->encodeObject($item);
994
        }
995
        
996
        $new_table[] = $new_row;
997
      }
998
    }
999
    
1000
    return $new_table;
1001
  }
1002
1003
  /**
1004
   * Encodes an object including members with
1005
   * protected and private visibility
1006
   * 
1007
   * @param BaseObject $Object The object to be encoded
1008
   * @param int $Depth The current traversal depth
0 ignored issues
show
Bug introduced by
There is no parameter named $Depth. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
1009
   * @return array All members of the object
1010
   */
1011
  protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1)
1012
  {
1013
    $return = array();
1014
1015
    if (is_resource($Object)) {
1016
1017
      return '** '.(string)$Object.' **';
1018
1019
    } else    
1020
    if (is_object($Object)) {
1021
1022
        if ($ObjectDepth > $this->options['maxObjectDepth']) {
1023
          return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **';
1024
        }
1025
        
1026
        foreach ($this->objectStack as $refVal) {
1027
            if ($refVal === $Object) {
1028
                return '** Recursion ('.get_class($Object).') **';
1029
            }
1030
        }
1031
        array_push($this->objectStack, $Object);
1032
                
1033
        $return['__className'] = $class = get_class($Object);
1034
        $class_lower = strtolower($class);
1035
1036
        $reflectionClass = new ReflectionClass($class);  
1037
        $properties = array();
1038
        foreach( $reflectionClass->getProperties() as $property) {
1039
          $properties[$property->getName()] = $property;
1040
        }
1041
            
1042
        $members = (array)$Object;
1043
            
1044
        foreach( $properties as $raw_name => $property ) {
1045
          
1046
          $name = $raw_name;
1047
          if($property->isStatic()) {
1048
            $name = 'static:'.$name;
1049
          }
1050
          if($property->isPublic()) {
1051
            $name = 'public:'.$name;
1052
          } else
1053
          if($property->isPrivate()) {
1054
            $name = 'private:'.$name;
1055
            $raw_name = "\0".$class."\0".$raw_name;
1056
          } else
1057
          if($property->isProtected()) {
1058
            $name = 'protected:'.$name;
1059
            $raw_name = "\0".'*'."\0".$raw_name;
1060
          }
1061
          
1062
          if(!(isset($this->objectFilters[$class_lower])
1063
               && is_array($this->objectFilters[$class_lower])
1064
               && in_array($raw_name,$this->objectFilters[$class_lower]))) {
1065
1066
            if(array_key_exists($raw_name,$members)
1067
               && !$property->isStatic()) {
1068
              
1069
              $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1);      
1070
            
1071
            } else {
1072
              if(method_exists($property,'setAccessible')) {
1073
                $property->setAccessible(true);
1074
                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
1075
              } else
1076
              if($property->isPublic()) {
1077
                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
1078
              } else {
1079
                $return[$name] = '** Need PHP 5.3 to get value **';
1080
              }
1081
            }
1082
          } else {
1083
            $return[$name] = '** Excluded by Filter **';
1084
          }
1085
        }
1086
        
1087
        // Include all members that are not defined in the class
1088
        // but exist in the object
1089
        foreach( $members as $raw_name => $value ) {
1090
          
1091
          $name = $raw_name;
1092
          
1093
          if ($name{0} == "\0") {
1094
            $parts = explode("\0", $name);
1095
            $name = $parts[2];
1096
          }
1097
          
1098
          if(!isset($properties[$name])) {
1099
            $name = 'undeclared:'.$name;
1100
              
1101
            if(!(isset($this->objectFilters[$class_lower])
1102
                 && is_array($this->objectFilters[$class_lower])
1103
                 && in_array($raw_name,$this->objectFilters[$class_lower]))) {
1104
              
1105
              $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1);
1106
            } else {
1107
              $return[$name] = '** Excluded by Filter **';
1108
            }
1109
          }
1110
        }
1111
        
1112
        array_pop($this->objectStack);
1113
        
1114
    } elseif (is_array($Object)) {
1115
1116
        if ($ArrayDepth > $this->options['maxArrayDepth']) {
1117
          return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **';
1118
        }
1119
      
1120
        foreach ($Object as $key => $val) {
1121
          
1122
          // Encoding the $GLOBALS PHP array causes an infinite loop
1123
          // if the recursion is not reset here as it contains
1124
          // a reference to itself. This is the only way I have come up
1125
          // with to stop infinite recursion in this case.
1126 View Code Duplication
          if($key=='GLOBALS'
1127
             && is_array($val)
1128
             && array_key_exists('GLOBALS',$val)) {
1129
            $val['GLOBALS'] = '** Recursion (GLOBALS) **';
1130
          }
1131
          
1132
          $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1);
1133
        }
1134
    } else {
1135
      if(self::is_utf8($Object)) {
1136
        return $Object;
1137
      } else {
1138
        return utf8_encode($Object);
1139
      }
1140
    }
1141
    return $return;
1142
  }
1143
1144
  /**
1145
   * Returns true if $string is valid UTF-8 and false otherwise.
1146
   *
1147
   * @param mixed $str String to be tested
1148
   * @return boolean
1149
   */
1150
  protected static function is_utf8($str) {
1151
    $c=0; $b=0;
0 ignored issues
show
Unused Code introduced by
$c 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...
Unused Code introduced by
$b 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...
1152
    $bits=0;
0 ignored issues
show
Unused Code introduced by
$bits 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...
1153
    $len=strlen($str);
1154
    for($i=0; $i<$len; $i++){
1155
        $c=ord($str[$i]);
1156
        if($c > 128){
1157
            if(($c >= 254)) return false;
1158
            elseif($c >= 252) $bits=6;
1159
            elseif($c >= 248) $bits=5;
1160
            elseif($c >= 240) $bits=4;
1161
            elseif($c >= 224) $bits=3;
1162
            elseif($c >= 192) $bits=2;
1163
            else return false;
1164
            if(($i+$bits) > $len) return false;
1165
            while($bits > 1){
1166
                $i++;
1167
                $b=ord($str[$i]);
1168
                if($b < 128 || $b > 191) return false;
1169
                $bits--;
1170
            }
1171
        }
1172
    }
1173
    return true;
1174
  } 
1175
1176
  /**
1177
   * Converts to and from JSON format.
1178
   *
1179
   * JSON (JavaScript Object Notation) is a lightweight data-interchange
1180
   * format. It is easy for humans to read and write. It is easy for machines
1181
   * to parse and generate. It is based on a subset of the JavaScript
1182
   * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
1183
   * This feature can also be found in  Python. JSON is a text format that is
1184
   * completely language independent but uses conventions that are familiar
1185
   * to programmers of the C-family of languages, including C, C++, C#, Java,
1186
   * JavaScript, Perl, TCL, and many others. These properties make JSON an
1187
   * ideal data-interchange language.
1188
   *
1189
   * This package provides a simple encoder and decoder for JSON notation. It
1190
   * is intended for use with client-side Javascript applications that make
1191
   * use of HTTPRequest to perform server communication functions - data can
1192
   * be encoded into JSON notation for use in a client-side javascript, or
1193
   * decoded from incoming Javascript requests. JSON format is native to
1194
   * Javascript, and can be directly eval()'ed with no further parsing
1195
   * overhead
1196
   *
1197
   * All strings should be in ASCII or UTF-8 format!
1198
   *
1199
   * LICENSE: Redistribution and use in source and binary forms, with or
1200
   * without modification, are permitted provided that the following
1201
   * conditions are met: Redistributions of source code must retain the
1202
   * above copyright notice, this list of conditions and the following
1203
   * disclaimer. Redistributions in binary form must reproduce the above
1204
   * copyright notice, this list of conditions and the following disclaimer
1205
   * in the documentation and/or other materials provided with the
1206
   * distribution.
1207
   *
1208
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1209
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1210
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1211
   * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1212
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1213
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
1214
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1215
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
1216
   * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1217
   * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1218
   * DAMAGE.
1219
   *
1220
   * @category
1221
   * @package     Services_JSON
1222
   * @author      Michal Migurski <[email protected]>
1223
   * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
1224
   * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
1225
   * @author      Christoph Dorn <[email protected]>
1226
   * @copyright   2005 Michal Migurski
1227
   * @version     CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $
1228
   * @license     http://www.opensource.org/licenses/bsd-license.php
1229
   * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
1230
   */
1231
   
1232
     
1233
  /**
1234
   * Keep a list of objects as we descend into the array so we can detect recursion.
1235
   */
1236
  private $json_objectStack = array();
1237
1238
1239
 /**
1240
  * convert a string from one UTF-8 char to one UTF-16 char
1241
  *
1242
  * Normally should be handled by mb_convert_encoding, but
1243
  * provides a slower PHP-only method for installations
1244
  * that lack the multibye string extension.
1245
  *
1246
  * @param    string  $utf8   UTF-8 character
1247
  * @return   string  UTF-16 character
1248
  * @access   private
1249
  */
1250
  private function json_utf82utf16($utf8)
1251
  {
1252
      // oh please oh please oh please oh please oh please
1253
      if(function_exists('mb_convert_encoding')) {
1254
          return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
1255
      }
1256
1257
      switch(strlen($utf8)) {
1258
          case 1:
1259
              // this case should never be reached, because we are in ASCII range
1260
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1261
              return $utf8;
1262
1263
          case 2:
1264
              // return a UTF-16 character from a 2-byte UTF-8 char
1265
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1266
              return chr(0x07 & (ord($utf8{0}) >> 2))
1267
                   . chr((0xC0 & (ord($utf8{0}) << 6))
1268
                       | (0x3F & ord($utf8{1})));
1269
1270
          case 3:
1271
              // return a UTF-16 character from a 3-byte UTF-8 char
1272
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1273
              return chr((0xF0 & (ord($utf8{0}) << 4))
1274
                       | (0x0F & (ord($utf8{1}) >> 2)))
1275
                   . chr((0xC0 & (ord($utf8{1}) << 6))
1276
                       | (0x7F & ord($utf8{2})));
1277
      }
1278
1279
      // ignoring UTF-32 for now, sorry
1280
      return '';
1281
  }
1282
1283
 /**
1284
  * encodes an arbitrary variable into JSON format
1285
  *
1286
  * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
1287
  *                           see argument 1 to Services_JSON() above for array-parsing behavior.
1288
  *                           if var is a strng, note that encode() always expects it
1289
  *                           to be in ASCII or UTF-8 format!
1290
  *
1291
  * @return   mixed   JSON string representation of input var or an error if a problem occurs
1292
  * @access   public
1293
  */
1294
  private function json_encode($var)
1295
  {
1296
    
1297
    if(is_object($var)) {
1298
      if(in_array($var,$this->json_objectStack)) {
1299
        return '"** Recursion **"';
1300
      }
1301
    }
1302
          
1303
      switch (gettype($var)) {
1304
          case 'boolean':
1305
              return $var ? 'true' : 'false';
1306
1307
          case 'NULL':
1308
              return 'null';
1309
1310
          case 'integer':
1311
              return (int) $var;
1312
1313
          case 'double':
1314
          case 'float':
1315
              return (float) $var;
1316
1317
          case 'string':
1318
              // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
1319
              $ascii = '';
1320
              $strlen_var = strlen($var);
1321
1322
             /*
1323
              * Iterate over every character in the string,
1324
              * escaping with a slash or encoding to UTF-8 where necessary
1325
              */
1326
              for ($c = 0; $c < $strlen_var; ++$c) {
1327
1328
                  $ord_var_c = ord($var{$c});
1329
1330
                  switch (true) {
1331
                      case $ord_var_c == 0x08:
1332
                          $ascii .= '\b';
1333
                          break;
1334
                      case $ord_var_c == 0x09:
1335
                          $ascii .= '\t';
1336
                          break;
1337
                      case $ord_var_c == 0x0A:
1338
                          $ascii .= '\n';
1339
                          break;
1340
                      case $ord_var_c == 0x0C:
1341
                          $ascii .= '\f';
1342
                          break;
1343
                      case $ord_var_c == 0x0D:
1344
                          $ascii .= '\r';
1345
                          break;
1346
1347
                      case $ord_var_c == 0x22:
1348
                      case $ord_var_c == 0x2F:
1349
                      case $ord_var_c == 0x5C:
1350
                          // double quote, slash, slosh
1351
                          $ascii .= '\\'.$var{$c};
1352
                          break;
1353
1354
                      case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
1355
                          // characters U-00000000 - U-0000007F (same as ASCII)
1356
                          $ascii .= $var{$c};
1357
                          break;
1358
1359
                      case (($ord_var_c & 0xE0) == 0xC0):
1360
                          // characters U-00000080 - U-000007FF, mask 110XXXXX
1361
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1362
                          $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
1363
                          $c += 1;
1364
                          $utf16 = $this->json_utf82utf16($char);
1365
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1366
                          break;
1367
1368
                      case (($ord_var_c & 0xF0) == 0xE0):
1369
                          // characters U-00000800 - U-0000FFFF, mask 1110XXXX
1370
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1371
                          $char = pack('C*', $ord_var_c,
1372
                                       ord($var{$c + 1}),
1373
                                       ord($var{$c + 2}));
1374
                          $c += 2;
1375
                          $utf16 = $this->json_utf82utf16($char);
1376
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1377
                          break;
1378
1379
                      case (($ord_var_c & 0xF8) == 0xF0):
1380
                          // characters U-00010000 - U-001FFFFF, mask 11110XXX
1381
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1382
                          $char = pack('C*', $ord_var_c,
1383
                                       ord($var{$c + 1}),
1384
                                       ord($var{$c + 2}),
1385
                                       ord($var{$c + 3}));
1386
                          $c += 3;
1387
                          $utf16 = $this->json_utf82utf16($char);
1388
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1389
                          break;
1390
1391 View Code Duplication
                      case (($ord_var_c & 0xFC) == 0xF8):
1392
                          // characters U-00200000 - U-03FFFFFF, mask 111110XX
1393
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1394
                          $char = pack('C*', $ord_var_c,
1395
                                       ord($var{$c + 1}),
1396
                                       ord($var{$c + 2}),
1397
                                       ord($var{$c + 3}),
1398
                                       ord($var{$c + 4}));
1399
                          $c += 4;
1400
                          $utf16 = $this->json_utf82utf16($char);
1401
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1402
                          break;
1403
1404 View Code Duplication
                      case (($ord_var_c & 0xFE) == 0xFC):
1405
                          // characters U-04000000 - U-7FFFFFFF, mask 1111110X
1406
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1407
                          $char = pack('C*', $ord_var_c,
1408
                                       ord($var{$c + 1}),
1409
                                       ord($var{$c + 2}),
1410
                                       ord($var{$c + 3}),
1411
                                       ord($var{$c + 4}),
1412
                                       ord($var{$c + 5}));
1413
                          $c += 5;
1414
                          $utf16 = $this->json_utf82utf16($char);
1415
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1416
                          break;
1417
                  }
1418
              }
1419
1420
              return '"'.$ascii.'"';
1421
1422
          case 'array':
1423
             /*
1424
              * As per JSON spec if any array key is not an integer
1425
              * we must treat the the whole array as an object. We
1426
              * also try to catch a sparsely populated associative
1427
              * array with numeric keys here because some JS engines
1428
              * will create an array with empty indexes up to
1429
              * max_index which can cause memory issues and because
1430
              * the keys, which may be relevant, will be remapped
1431
              * otherwise.
1432
              *
1433
              * As per the ECMA and JSON specification an object may
1434
              * have any string as a property. Unfortunately due to
1435
              * a hole in the ECMA specification if the key is a
1436
              * ECMA reserved word or starts with a digit the
1437
              * parameter is only accessible using ECMAScript's
1438
              * bracket notation.
1439
              */
1440
1441
              // treat as a JSON object
1442
              if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
1443
                  
1444
                  $this->json_objectStack[] = $var;
1445
1446
                  $properties = array_map(array($this, 'json_name_value'),
1447
                                          array_keys($var),
1448
                                          array_values($var));
1449
1450
                  array_pop($this->json_objectStack);
1451
1452
                  foreach($properties as $property) {
1453
                      if($property instanceof Exception) {
1454
                          return $property;
1455
                      }
1456
                  }
1457
1458
                  return '{' . join(',', $properties) . '}';
1459
              }
1460
1461
              $this->json_objectStack[] = $var;
1462
1463
              // treat it like a regular array
1464
              $elements = array_map(array($this, 'json_encode'), $var);
1465
1466
              array_pop($this->json_objectStack);
1467
1468
              foreach($elements as $element) {
1469
                  if($element instanceof Exception) {
1470
                      return $element;
1471
                  }
1472
              }
1473
1474
              return '[' . join(',', $elements) . ']';
1475
1476
          case 'object':
1477
              $vars = self::encodeObject($var);
1478
1479
              $this->json_objectStack[] = $var;
1480
1481
              $properties = array_map(array($this, 'json_name_value'),
1482
                                      array_keys($vars),
1483
                                      array_values($vars));
1484
1485
              array_pop($this->json_objectStack);
1486
              
1487
              foreach($properties as $property) {
1488
                  if($property instanceof Exception) {
1489
                      return $property;
1490
                  }
1491
              }
1492
                     
1493
              return '{' . join(',', $properties) . '}';
1494
1495
          default:
1496
              return null;
1497
      }
1498
  }
1499
1500
 /**
1501
  * array-walking function for use in generating JSON-formatted name-value pairs
1502
  *
1503
  * @param    string  $name   name of key to use
1504
  * @param    mixed   $value  reference to an array element to be encoded
1505
  *
1506
  * @return   string  JSON-formatted name-value pair, like '"name":value'
1507
  * @access   private
1508
  */
1509
  private function json_name_value($name, $value)
1510
  {
1511
      // Encoding the $GLOBALS PHP array causes an infinite loop
1512
      // if the recursion is not reset here as it contains
1513
      // a reference to itself. This is the only way I have come up
1514
      // with to stop infinite recursion in this case.
1515 View Code Duplication
      if($name=='GLOBALS'
1516
         && is_array($value)
1517
         && array_key_exists('GLOBALS',$value)) {
1518
        $value['GLOBALS'] = '** Recursion **';
1519
      }
1520
    
1521
      $encoded_value = $this->json_encode($value);
1522
1523
      if($encoded_value instanceof Exception) {
1524
          return $encoded_value;
1525
      }
1526
1527
      return $this->json_encode(strval($name)) . ':' . $encoded_value;
1528
  }
1529
}
1530