Completed
Push — prado-3.3 ( e90646...0b76d5 )
by Fabio
23:37 queued 03:01
created

FirePHP::groupEnd()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 3
rs 10
c 0
b 0
f 0
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[$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)
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);
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);
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) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
689
          case E_NOTICE: $severity = 'E_NOTICE'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
690
          case E_USER_ERROR: $severity = 'E_USER_ERROR'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
691
          case E_USER_WARNING: $severity = 'E_USER_WARNING'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
692
          case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
693
          case E_STRICT: $severity = 'E_STRICT'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
694
          case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
695
          case E_DEPRECATED: $severity = 'E_DEPRECATED'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
696
          case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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'])
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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'])
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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'])
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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'])
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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'])
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

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

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

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

could be turned into

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

This is much more concise to read.

Loading history...
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');
818
  	$this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION);
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');
824
    } else {
825
    	$this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
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'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
837
        $msg_meta['File'] = $meta['file'];
838
      }
839 View Code Duplication
      if(isset($meta['line']) && !isset($msg_meta['Line'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
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):'')
856
                               . '|' . $part . '|'
857
                               . (($i<count($parts)-2)?'\\':''));
858
            } else {
859
              $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex,
860
                               strlen($part) . '|' . $part . '|');
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);
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() {
0 ignored issues
show
Coding Style introduced by
getUserAgent uses the super-global variable $_SERVER which is generally not recommended.

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

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

// Better
class Router
{
    private $host;

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

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

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

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
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 Object $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
1035
        $reflectionClass = new ReflectionClass($class);  
1036
        $properties = array();
1037
        foreach( $reflectionClass->getProperties() as $property) {
1038
          $properties[$property->getName()] = $property;
1039
        }
1040
            
1041
        $members = (array)$Object;
1042
            
1043
        foreach( $properties as $raw_name => $property ) {
1044
          
1045
          $name = $raw_name;
1046
          if($property->isStatic()) {
1047
            $name = 'static:'.$name;
1048
          }
1049
          if($property->isPublic()) {
1050
            $name = 'public:'.$name;
1051
          } else
1052
          if($property->isPrivate()) {
1053
            $name = 'private:'.$name;
1054
            $raw_name = "\0".$class."\0".$raw_name;
1055
          } else
1056
          if($property->isProtected()) {
1057
            $name = 'protected:'.$name;
1058
            $raw_name = "\0".'*'."\0".$raw_name;
1059
          }
1060
          
1061
          if(!(isset($this->objectFilters[$class])
1062
               && is_array($this->objectFilters[$class])
1063
               && in_array($raw_name,$this->objectFilters[$class]))) {
1064
1065
            if(array_key_exists($raw_name,$members)
1066
               && !$property->isStatic()) {
1067
              
1068
              $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1);      
1069
            
1070
            } else {
1071
              if(method_exists($property,'setAccessible')) {
1072
                $property->setAccessible(true);
1073
                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
1074
              } else
1075
              if($property->isPublic()) {
1076
                $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1);
1077
              } else {
1078
                $return[$name] = '** Need PHP 5.3 to get value **';
1079
              }
1080
            }
1081
          } else {
1082
            $return[$name] = '** Excluded by Filter **';
1083
          }
1084
        }
1085
        
1086
        // Include all members that are not defined in the class
1087
        // but exist in the object
1088
        foreach( $members as $raw_name => $value ) {
1089
          
1090
          $name = $raw_name;
1091
          
1092
          if ($name{0} == "\0") {
1093
            $parts = explode("\0", $name);
1094
            $name = $parts[2];
1095
          }
1096
          
1097
          if(!isset($properties[$name])) {
1098
            $name = 'undeclared:'.$name;
1099
              
1100
            if(!(isset($this->objectFilters[$class])
1101
                 && is_array($this->objectFilters[$class])
1102
                 && in_array($raw_name,$this->objectFilters[$class]))) {
1103
              
1104
              $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1);
1105
            } else {
1106
              $return[$name] = '** Excluded by Filter **';
1107
            }
1108
          }
1109
        }
1110
        
1111
        array_pop($this->objectStack);
1112
        
1113
    } elseif (is_array($Object)) {
1114
1115
        if ($ArrayDepth > $this->options['maxArrayDepth']) {
1116
          return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **';
1117
        }
1118
      
1119
        foreach ($Object as $key => $val) {
1120
          
1121
          // Encoding the $GLOBALS PHP array causes an infinite loop
1122
          // if the recursion is not reset here as it contains
1123
          // a reference to itself. This is the only way I have come up
1124
          // with to stop infinite recursion in this case.
1125 View Code Duplication
          if($key=='GLOBALS'
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1126
             && is_array($val)
1127
             && array_key_exists('GLOBALS',$val)) {
1128
            $val['GLOBALS'] = '** Recursion (GLOBALS) **';
1129
          }
1130
          
1131
          $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1);
1132
        }
1133
    } else {
1134
      if(self::is_utf8($Object)) {
1135
        return $Object;
1136
      } else {
1137
        return utf8_encode($Object);
1138
      }
1139
    }
1140
    return $return;
1141
  }
1142
1143
  /**
1144
   * Returns true if $string is valid UTF-8 and false otherwise.
1145
   *
1146
   * @param mixed $str String to be tested
1147
   * @return boolean
1148
   */
1149
  protected static function is_utf8($str) {
1150
    $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...
1151
    $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...
1152
    $len=strlen($str);
1153
    for($i=0; $i<$len; $i++){
1154
        $c=ord($str[$i]);
1155
        if($c > 128){
1156
            if(($c >= 254)) return false;
1157
            elseif($c >= 252) $bits=6;
1158
            elseif($c >= 248) $bits=5;
1159
            elseif($c >= 240) $bits=4;
1160
            elseif($c >= 224) $bits=3;
1161
            elseif($c >= 192) $bits=2;
1162
            else return false;
1163
            if(($i+$bits) > $len) return false;
1164
            while($bits > 1){
1165
                $i++;
1166
                $b=ord($str[$i]);
1167
                if($b < 128 || $b > 191) return false;
1168
                $bits--;
1169
            }
1170
        }
1171
    }
1172
    return true;
1173
  } 
1174
1175
  /**
1176
   * Converts to and from JSON format.
1177
   *
1178
   * JSON (JavaScript Object Notation) is a lightweight data-interchange
1179
   * format. It is easy for humans to read and write. It is easy for machines
1180
   * to parse and generate. It is based on a subset of the JavaScript
1181
   * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
1182
   * This feature can also be found in  Python. JSON is a text format that is
1183
   * completely language independent but uses conventions that are familiar
1184
   * to programmers of the C-family of languages, including C, C++, C#, Java,
1185
   * JavaScript, Perl, TCL, and many others. These properties make JSON an
1186
   * ideal data-interchange language.
1187
   *
1188
   * This package provides a simple encoder and decoder for JSON notation. It
1189
   * is intended for use with client-side Javascript applications that make
1190
   * use of HTTPRequest to perform server communication functions - data can
1191
   * be encoded into JSON notation for use in a client-side javascript, or
1192
   * decoded from incoming Javascript requests. JSON format is native to
1193
   * Javascript, and can be directly eval()'ed with no further parsing
1194
   * overhead
1195
   *
1196
   * All strings should be in ASCII or UTF-8 format!
1197
   *
1198
   * LICENSE: Redistribution and use in source and binary forms, with or
1199
   * without modification, are permitted provided that the following
1200
   * conditions are met: Redistributions of source code must retain the
1201
   * above copyright notice, this list of conditions and the following
1202
   * disclaimer. Redistributions in binary form must reproduce the above
1203
   * copyright notice, this list of conditions and the following disclaimer
1204
   * in the documentation and/or other materials provided with the
1205
   * distribution.
1206
   *
1207
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1208
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1209
   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1210
   * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1211
   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1212
   * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
1213
   * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1214
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
1215
   * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
1216
   * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
1217
   * DAMAGE.
1218
   *
1219
   * @category
1220
   * @package     Services_JSON
1221
   * @author      Michal Migurski <[email protected]>
1222
   * @author      Matt Knapp <mdknapp[at]gmail[dot]com>
1223
   * @author      Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
1224
   * @author      Christoph Dorn <[email protected]>
1225
   * @copyright   2005 Michal Migurski
1226
   * @version     CVS: $Id: FirePHP.class.php 3187 2012-07-12 11:21:01Z ctrlaltca $
1227
   * @license     http://www.opensource.org/licenses/bsd-license.php
1228
   * @link        http://pear.php.net/pepr/pepr-proposal-show.php?id=198
1229
   */
1230
   
1231
     
1232
  /**
1233
   * Keep a list of objects as we descend into the array so we can detect recursion.
1234
   */
1235
  private $json_objectStack = array();
1236
1237
1238
 /**
1239
  * convert a string from one UTF-8 char to one UTF-16 char
1240
  *
1241
  * Normally should be handled by mb_convert_encoding, but
1242
  * provides a slower PHP-only method for installations
1243
  * that lack the multibye string extension.
1244
  *
1245
  * @param    string  $utf8   UTF-8 character
1246
  * @return   string  UTF-16 character
1247
  * @access   private
1248
  */
1249
  private function json_utf82utf16($utf8)
1250
  {
1251
      // oh please oh please oh please oh please oh please
1252
      if(function_exists('mb_convert_encoding')) {
1253
          return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
1254
      }
1255
1256
      switch(strlen($utf8)) {
1257
          case 1:
1258
              // this case should never be reached, because we are in ASCII range
1259
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1260
              return $utf8;
1261
1262
          case 2:
1263
              // return a UTF-16 character from a 2-byte UTF-8 char
1264
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1265
              return chr(0x07 & (ord($utf8{0}) >> 2))
1266
                   . chr((0xC0 & (ord($utf8{0}) << 6))
1267
                       | (0x3F & ord($utf8{1})));
1268
1269
          case 3:
1270
              // return a UTF-16 character from a 3-byte UTF-8 char
1271
              // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1272
              return chr((0xF0 & (ord($utf8{0}) << 4))
1273
                       | (0x0F & (ord($utf8{1}) >> 2)))
1274
                   . chr((0xC0 & (ord($utf8{1}) << 6))
1275
                       | (0x7F & ord($utf8{2})));
1276
      }
1277
1278
      // ignoring UTF-32 for now, sorry
1279
      return '';
1280
  }
1281
1282
 /**
1283
  * encodes an arbitrary variable into JSON format
1284
  *
1285
  * @param    mixed   $var    any number, boolean, string, array, or object to be encoded.
1286
  *                           see argument 1 to Services_JSON() above for array-parsing behavior.
1287
  *                           if var is a strng, note that encode() always expects it
1288
  *                           to be in ASCII or UTF-8 format!
1289
  *
1290
  * @return   mixed   JSON string representation of input var or an error if a problem occurs
1291
  * @access   public
1292
  */
1293
  private function json_encode($var)
1294
  {
1295
    
1296
    if(is_object($var)) {
1297
      if(in_array($var,$this->json_objectStack)) {
1298
        return '"** Recursion **"';
1299
      }
1300
    }
1301
          
1302
      switch (gettype($var)) {
1303
          case 'boolean':
1304
              return $var ? 'true' : 'false';
1305
1306
          case 'NULL':
1307
              return 'null';
1308
1309
          case 'integer':
1310
              return (int) $var;
1311
1312
          case 'double':
1313
          case 'float':
1314
              return (float) $var;
1315
1316
          case 'string':
1317
              // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
1318
              $ascii = '';
1319
              $strlen_var = strlen($var);
1320
1321
             /*
1322
              * Iterate over every character in the string,
1323
              * escaping with a slash or encoding to UTF-8 where necessary
1324
              */
1325
              for ($c = 0; $c < $strlen_var; ++$c) {
1326
1327
                  $ord_var_c = ord($var{$c});
1328
1329
                  switch (true) {
1330
                      case $ord_var_c == 0x08:
1331
                          $ascii .= '\b';
1332
                          break;
1333
                      case $ord_var_c == 0x09:
1334
                          $ascii .= '\t';
1335
                          break;
1336
                      case $ord_var_c == 0x0A:
1337
                          $ascii .= '\n';
1338
                          break;
1339
                      case $ord_var_c == 0x0C:
1340
                          $ascii .= '\f';
1341
                          break;
1342
                      case $ord_var_c == 0x0D:
1343
                          $ascii .= '\r';
1344
                          break;
1345
1346
                      case $ord_var_c == 0x22:
1347
                      case $ord_var_c == 0x2F:
1348
                      case $ord_var_c == 0x5C:
1349
                          // double quote, slash, slosh
1350
                          $ascii .= '\\'.$var{$c};
1351
                          break;
1352
1353
                      case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
1354
                          // characters U-00000000 - U-0000007F (same as ASCII)
1355
                          $ascii .= $var{$c};
1356
                          break;
1357
1358
                      case (($ord_var_c & 0xE0) == 0xC0):
1359
                          // characters U-00000080 - U-000007FF, mask 110XXXXX
1360
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1361
                          $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
1362
                          $c += 1;
1363
                          $utf16 = $this->json_utf82utf16($char);
1364
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1365
                          break;
1366
1367
                      case (($ord_var_c & 0xF0) == 0xE0):
1368
                          // characters U-00000800 - U-0000FFFF, mask 1110XXXX
1369
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1370
                          $char = pack('C*', $ord_var_c,
1371
                                       ord($var{$c + 1}),
1372
                                       ord($var{$c + 2}));
1373
                          $c += 2;
1374
                          $utf16 = $this->json_utf82utf16($char);
1375
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1376
                          break;
1377
1378
                      case (($ord_var_c & 0xF8) == 0xF0):
1379
                          // characters U-00010000 - U-001FFFFF, mask 11110XXX
1380
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1381
                          $char = pack('C*', $ord_var_c,
1382
                                       ord($var{$c + 1}),
1383
                                       ord($var{$c + 2}),
1384
                                       ord($var{$c + 3}));
1385
                          $c += 3;
1386
                          $utf16 = $this->json_utf82utf16($char);
1387
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1388
                          break;
1389
1390 View Code Duplication
                      case (($ord_var_c & 0xFC) == 0xF8):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1391
                          // characters U-00200000 - U-03FFFFFF, mask 111110XX
1392
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1393
                          $char = pack('C*', $ord_var_c,
1394
                                       ord($var{$c + 1}),
1395
                                       ord($var{$c + 2}),
1396
                                       ord($var{$c + 3}),
1397
                                       ord($var{$c + 4}));
1398
                          $c += 4;
1399
                          $utf16 = $this->json_utf82utf16($char);
1400
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1401
                          break;
1402
1403 View Code Duplication
                      case (($ord_var_c & 0xFE) == 0xFC):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1404
                          // characters U-04000000 - U-7FFFFFFF, mask 1111110X
1405
                          // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
1406
                          $char = pack('C*', $ord_var_c,
1407
                                       ord($var{$c + 1}),
1408
                                       ord($var{$c + 2}),
1409
                                       ord($var{$c + 3}),
1410
                                       ord($var{$c + 4}),
1411
                                       ord($var{$c + 5}));
1412
                          $c += 5;
1413
                          $utf16 = $this->json_utf82utf16($char);
1414
                          $ascii .= sprintf('\u%04s', bin2hex($utf16));
1415
                          break;
1416
                  }
1417
              }
1418
1419
              return '"'.$ascii.'"';
1420
1421
          case 'array':
1422
             /*
1423
              * As per JSON spec if any array key is not an integer
1424
              * we must treat the the whole array as an object. We
1425
              * also try to catch a sparsely populated associative
1426
              * array with numeric keys here because some JS engines
1427
              * will create an array with empty indexes up to
1428
              * max_index which can cause memory issues and because
1429
              * the keys, which may be relevant, will be remapped
1430
              * otherwise.
1431
              *
1432
              * As per the ECMA and JSON specification an object may
1433
              * have any string as a property. Unfortunately due to
1434
              * a hole in the ECMA specification if the key is a
1435
              * ECMA reserved word or starts with a digit the
1436
              * parameter is only accessible using ECMAScript's
1437
              * bracket notation.
1438
              */
1439
1440
              // treat as a JSON object
1441
              if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
1442
                  
1443
                  $this->json_objectStack[] = $var;
1444
1445
                  $properties = array_map(array($this, 'json_name_value'),
1446
                                          array_keys($var),
1447
                                          array_values($var));
1448
1449
                  array_pop($this->json_objectStack);
1450
1451
                  foreach($properties as $property) {
1452
                      if($property instanceof Exception) {
1453
                          return $property;
1454
                      }
1455
                  }
1456
1457
                  return '{' . join(',', $properties) . '}';
1458
              }
1459
1460
              $this->json_objectStack[] = $var;
1461
1462
              // treat it like a regular array
1463
              $elements = array_map(array($this, 'json_encode'), $var);
1464
1465
              array_pop($this->json_objectStack);
1466
1467
              foreach($elements as $element) {
1468
                  if($element instanceof Exception) {
1469
                      return $element;
1470
                  }
1471
              }
1472
1473
              return '[' . join(',', $elements) . ']';
1474
1475
          case 'object':
1476
              $vars = self::encodeObject($var);
1477
1478
              $this->json_objectStack[] = $var;
1479
1480
              $properties = array_map(array($this, 'json_name_value'),
1481
                                      array_keys($vars),
1482
                                      array_values($vars));
1483
1484
              array_pop($this->json_objectStack);
1485
              
1486
              foreach($properties as $property) {
1487
                  if($property instanceof Exception) {
1488
                      return $property;
1489
                  }
1490
              }
1491
                     
1492
              return '{' . join(',', $properties) . '}';
1493
1494
          default:
1495
              return null;
1496
      }
1497
  }
1498
1499
 /**
1500
  * array-walking function for use in generating JSON-formatted name-value pairs
1501
  *
1502
  * @param    string  $name   name of key to use
1503
  * @param    mixed   $value  reference to an array element to be encoded
1504
  *
1505
  * @return   string  JSON-formatted name-value pair, like '"name":value'
1506
  * @access   private
1507
  */
1508
  private function json_name_value($name, $value)
1509
  {
1510
      // Encoding the $GLOBALS PHP array causes an infinite loop
1511
      // if the recursion is not reset here as it contains
1512
      // a reference to itself. This is the only way I have come up
1513
      // with to stop infinite recursion in this case.
1514 View Code Duplication
      if($name=='GLOBALS'
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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

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

Loading history...
1515
         && is_array($value)
1516
         && array_key_exists('GLOBALS',$value)) {
1517
        $value['GLOBALS'] = '** Recursion **';
1518
      }
1519
    
1520
      $encoded_value = $this->json_encode($value);
1521
1522
      if($encoded_value instanceof Exception) {
1523
          return $encoded_value;
1524
      }
1525
1526
      return $this->json_encode(strval($name)) . ':' . $encoded_value;
1527
  }
1528
}
1529