PageRenderTime 62ms CodeModel.GetById 4ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 0ms

/min/lib/FirePHP.php

http://github.com/mrclay/minify
PHP | 1843 lines | 1081 code | 195 blank | 567 comment | 267 complexity | a361f087aac4862ba9a5cf9f6b0ec08d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2// Authors:
   3// - cadorn, Christoph Dorn <christoph@christophdorn.com>, Copyright 2007, New BSD License
   4// - qbbr, Sokolov Innokenty <sokolov.innokenty@gmail.com>, Copyright 2011, New BSD License
   5// - cadorn, Christoph Dorn <christoph@christophdorn.com>, Copyright 2011, MIT License
   6
   7/**
   8 * *** BEGIN LICENSE BLOCK *****
   9 * 
  10 * [MIT License](http://www.opensource.org/licenses/mit-license.php)
  11 * 
  12 * Copyright (c) 2007+ [Christoph Dorn](http://www.christophdorn.com/)
  13 * 
  14 * Permission is hereby granted, free of charge, to any person obtaining a copy
  15 * of this software and associated documentation files (the "Software"), to deal
  16 * in the Software without restriction, including without limitation the rights
  17 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  18 * copies of the Software, and to permit persons to whom the Software is
  19 * furnished to do so, subject to the following conditions:
  20 *
  21 * The above copyright notice and this permission notice shall be included in
  22 * all copies or substantial portions of the Software.
  23 *
  24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  30 * THE SOFTWARE.
  31 * 
  32 * ***** END LICENSE BLOCK *****
  33 * 
  34 * @copyright       Copyright (C) 2007+ Christoph Dorn
  35 * @author          Christoph Dorn <christoph@christophdorn.com>
  36 * @license         [MIT License](http://www.opensource.org/licenses/mit-license.php)
  37 * @package         FirePHPCore
  38 */
  39
  40/**
  41 * @see http://code.google.com/p/firephp/issues/detail?id=112
  42 */
  43if (!defined('E_STRICT')) {
  44    define('E_STRICT', 2048);
  45}
  46if (!defined('E_RECOVERABLE_ERROR')) {
  47    define('E_RECOVERABLE_ERROR', 4096);
  48}
  49if (!defined('E_DEPRECATED')) {
  50    define('E_DEPRECATED', 8192);
  51}
  52if (!defined('E_USER_DEPRECATED')) {
  53    define('E_USER_DEPRECATED', 16384);
  54} 
  55 
  56/**
  57 * Sends the given data to the FirePHP Firefox Extension.
  58 * The data can be displayed in the Firebug Console or in the
  59 * "Server" request tab.
  60 * 
  61 * For more information see: http://www.firephp.org/
  62 * 
  63 * @copyright       Copyright (C) 2007+ Christoph Dorn
  64 * @author          Christoph Dorn <christoph@christophdorn.com>
  65 * @license         [MIT License](http://www.opensource.org/licenses/mit-license.php)
  66 * @package         FirePHPCore
  67 *
  68 * @deprecated 2.3 This will be removed in Minify 3.0
  69 */
  70class FirePHP {
  71
  72    /**
  73     * FirePHP version
  74     *
  75     * @var string
  76     */
  77    const VERSION = '0.3';    // @pinf replace '0.3' with '%%VERSION%%'
  78
  79    /**
  80     * Firebug LOG level
  81     *
  82     * Logs a message to firebug console.
  83     * 
  84     * @var string
  85     */
  86    const LOG = 'LOG';
  87  
  88    /**
  89     * Firebug INFO level
  90     *
  91     * Logs a message to firebug console and displays an info icon before the message.
  92     * 
  93     * @var string
  94     */
  95    const INFO = 'INFO';
  96    
  97    /**
  98     * Firebug WARN level
  99     *
 100     * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
 101     * 
 102     * @var string
 103     */
 104    const WARN = 'WARN';
 105    
 106    /**
 107     * Firebug ERROR level
 108     *
 109     * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
 110     * 
 111     * @var string
 112     */
 113    const ERROR = 'ERROR';
 114    
 115    /**
 116     * Dumps a variable to firebug's server panel
 117     *
 118     * @var string
 119     */
 120    const DUMP = 'DUMP';
 121    
 122    /**
 123     * Displays a stack trace in firebug console
 124     *
 125     * @var string
 126     */
 127    const TRACE = 'TRACE';
 128    
 129    /**
 130     * Displays an exception in firebug console
 131     * 
 132     * Increments the firebug error count.
 133     *
 134     * @var string
 135     */
 136    const EXCEPTION = 'EXCEPTION';
 137    
 138    /**
 139     * Displays an table in firebug console
 140     *
 141     * @var string
 142     */
 143    const TABLE = 'TABLE';
 144    
 145    /**
 146     * Starts a group in firebug console
 147     * 
 148     * @var string
 149     */
 150    const GROUP_START = 'GROUP_START';
 151    
 152    /**
 153     * Ends a group in firebug console
 154     * 
 155     * @var string
 156     */
 157    const GROUP_END = 'GROUP_END';
 158    
 159    /**
 160     * Singleton instance of FirePHP
 161     *
 162     * @var FirePHP
 163     */
 164    protected static $instance = null;
 165    
 166    /**
 167     * Flag whether we are logging from within the exception handler
 168     * 
 169     * @var boolean
 170     */
 171    protected $inExceptionHandler = false;
 172    
 173    /**
 174     * Flag whether to throw PHP errors that have been converted to ErrorExceptions
 175     * 
 176     * @var boolean
 177     */
 178    protected $throwErrorExceptions = true;
 179    
 180    /**
 181     * Flag whether to convert PHP assertion errors to Exceptions
 182     * 
 183     * @var boolean
 184     */
 185    protected $convertAssertionErrorsToExceptions = true;
 186    
 187    /**
 188     * Flag whether to throw PHP assertion errors that have been converted to Exceptions
 189     * 
 190     * @var boolean
 191     */
 192    protected $throwAssertionExceptions = false;
 193
 194    /**
 195     * Wildfire protocol message index
 196     *
 197     * @var integer
 198     */
 199    protected $messageIndex = 1;
 200    
 201    /**
 202     * Options for the library
 203     * 
 204     * @var array
 205     */
 206    protected $options = array('maxDepth' => 10,
 207                               'maxObjectDepth' => 5,
 208                               'maxArrayDepth' => 5,
 209                               'useNativeJsonEncode' => true,
 210                               'includeLineNumbers' => true);
 211
 212    /**
 213     * Filters used to exclude object members when encoding
 214     * 
 215     * @var array
 216     */
 217    protected $objectFilters = array(
 218        'firephp' => array('objectStack', 'instance', 'json_objectStack'),
 219        'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack')
 220    );
 221
 222    /**
 223     * A stack of objects used to detect recursion during object encoding
 224     * 
 225     * @var object
 226     */
 227    protected $objectStack = array();
 228
 229    /**
 230     * Flag to enable/disable logging
 231     * 
 232     * @var boolean
 233     */
 234    protected $enabled = true;
 235
 236    /**
 237     * The insight console to log to if applicable
 238     * 
 239     * @var object
 240     */
 241    protected $logToInsightConsole = null;
 242
 243    /**
 244     * When the object gets serialized only include specific object members.
 245     * 
 246     * @return array
 247     */  
 248    public function __sleep()
 249    {
 250        return array('options', 'objectFilters', 'enabled');
 251    }
 252    
 253    /**
 254     * Gets singleton instance of FirePHP
 255     *
 256     * @param boolean $autoCreate
 257     * @return FirePHP
 258     */
 259    public static function getInstance($autoCreate = false)
 260    {
 261        if ($autoCreate === true && !self::$instance) {
 262            self::init();
 263        }
 264        return self::$instance;
 265    }
 266    
 267    /**
 268     * Creates FirePHP object and stores it for singleton access
 269     *
 270     * @return FirePHP
 271     */
 272    public static function init()
 273    {
 274        return self::setInstance(new self());
 275    }
 276
 277    /**
 278     * Set the instance of the FirePHP singleton
 279     * 
 280     * @param FirePHP $instance The FirePHP object instance
 281     * @return FirePHP
 282     */
 283    public static function setInstance($instance)
 284    {
 285        return self::$instance = $instance;
 286    }
 287
 288    /**
 289     * Set an Insight console to direct all logging calls to
 290     * 
 291     * @param object $console The console object to log to
 292     * @return void
 293     */
 294    public function setLogToInsightConsole($console)
 295    {
 296        if (is_string($console)) {
 297            if (get_class($this) != 'FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) {
 298                throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!');
 299            }
 300            $this->logToInsightConsole = $this->to('request')->console($console);
 301        } else {
 302            $this->logToInsightConsole = $console;
 303        }
 304    }
 305
 306    /**
 307     * Enable and disable logging to Firebug
 308     * 
 309     * @param boolean $enabled TRUE to enable, FALSE to disable
 310     * @return void
 311     */
 312    public function setEnabled($enabled)
 313    {
 314       $this->enabled = $enabled;
 315    }
 316    
 317    /**
 318     * Check if logging is enabled
 319     * 
 320     * @return boolean TRUE if enabled
 321     */
 322    public function getEnabled()
 323    {
 324        return $this->enabled;
 325    }
 326    
 327    /**
 328     * Specify a filter to be used when encoding an object
 329     * 
 330     * Filters are used to exclude object members.
 331     * 
 332     * @param string $class The class name of the object
 333     * @param array $filter An array of members to exclude
 334     * @return void
 335     */
 336    public function setObjectFilter($class, $filter)
 337    {
 338        $this->objectFilters[strtolower($class)] = $filter;
 339    }
 340  
 341    /**
 342     * Set some options for the library
 343     * 
 344     * Options:
 345     *  - maxDepth: The maximum depth to traverse (default: 10)
 346     *  - maxObjectDepth: The maximum depth to traverse objects (default: 5)
 347     *  - maxArrayDepth: The maximum depth to traverse arrays (default: 5)
 348     *  - useNativeJsonEncode: If true will use json_encode() (default: true)
 349     *  - includeLineNumbers: If true will include line numbers and filenames (default: true)
 350     * 
 351     * @param array $options The options to be set
 352     * @return void
 353     */
 354    public function setOptions($options)
 355    {
 356        $this->options = array_merge($this->options, $options);
 357    }
 358
 359    /**
 360     * Get options from the library
 361     *
 362     * @return array The currently set options
 363     */
 364    public function getOptions()
 365    {
 366        return $this->options;
 367    }
 368
 369    /**
 370     * Set an option for the library
 371     * 
 372     * @param string $name
 373     * @param mixed $value
 374     * @return void
 375     * @throws Exception
 376     */  
 377    public function setOption($name, $value)
 378    {
 379        if (!isset($this->options[$name])) {
 380            throw $this->newException('Unknown option: ' . $name);
 381        }
 382        $this->options[$name] = $value;
 383    }
 384
 385    /**
 386     * Get an option from the library
 387     *
 388     * @param string $name
 389     * @return mixed
 390     * @throws Exception
 391     */
 392    public function getOption($name)
 393    {
 394        if (!isset($this->options[$name])) {
 395            throw $this->newException('Unknown option: ' . $name);
 396        }
 397        return $this->options[$name];
 398    }
 399
 400    /**
 401     * Register FirePHP as your error handler
 402     * 
 403     * Will throw exceptions for each php error.
 404     * 
 405     * @return mixed Returns a string containing the previously defined error handler (if any)
 406     */
 407    public function registerErrorHandler($throwErrorExceptions = false)
 408    {
 409        //NOTE: The following errors will not be caught by this error handler:
 410        //      E_ERROR, E_PARSE, E_CORE_ERROR,
 411        //      E_CORE_WARNING, E_COMPILE_ERROR,
 412        //      E_COMPILE_WARNING, E_STRICT
 413    
 414        $this->throwErrorExceptions = $throwErrorExceptions;
 415    
 416        return set_error_handler(array($this, 'errorHandler'));
 417    }
 418
 419    /**
 420     * FirePHP's error handler
 421     * 
 422     * Throws exception for each php error that will occur.
 423     *
 424     * @param integer $errno
 425     * @param string $errstr
 426     * @param string $errfile
 427     * @param integer $errline
 428     * @param array $errcontext
 429     */
 430    public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
 431    {
 432        // Don't throw exception if error reporting is switched off
 433        if (error_reporting() == 0) {
 434            return;
 435        }
 436        // Only throw exceptions for errors we are asking for
 437        if (error_reporting() & $errno) {
 438
 439            $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
 440            if ($this->throwErrorExceptions) {
 441                throw $exception;
 442            } else {
 443                $this->fb($exception);
 444            }
 445        }
 446    }
 447  
 448    /**
 449     * Register FirePHP as your exception handler
 450     * 
 451     * @return mixed Returns the name of the previously defined exception handler,
 452     *               or NULL on error.
 453     *               If no previous handler was defined, NULL is also returned.
 454     */
 455    public function registerExceptionHandler()
 456    {
 457        return set_exception_handler(array($this, 'exceptionHandler'));
 458    }
 459  
 460    /**
 461     * FirePHP's exception handler
 462     * 
 463     * Logs all exceptions to your firebug console and then stops the script.
 464     *
 465     * @param Exception $exception
 466     * @throws Exception
 467     */
 468    function exceptionHandler($exception)
 469    {
 470        $this->inExceptionHandler = true;
 471    
 472        header('HTTP/1.1 500 Internal Server Error');
 473    
 474        try {
 475            $this->fb($exception);
 476        } catch (Exception $e) {
 477            echo 'We had an exception: ' . $e;
 478        }
 479        
 480        $this->inExceptionHandler = false;
 481    }
 482  
 483    /**
 484     * Register FirePHP driver as your assert callback
 485     * 
 486     * @param boolean $convertAssertionErrorsToExceptions
 487     * @param boolean $throwAssertionExceptions
 488     * @return mixed Returns the original setting or FALSE on errors
 489     */
 490    public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false)
 491    {
 492        $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions;
 493        $this->throwAssertionExceptions = $throwAssertionExceptions;
 494        
 495        if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) {
 496            throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!');
 497        }
 498        
 499        return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
 500    }
 501  
 502    /**
 503     * FirePHP's assertion handler
 504     *
 505     * Logs all assertions to your firebug console and then stops the script.
 506     *
 507     * @param string $file File source of assertion
 508     * @param integer $line Line source of assertion
 509     * @param mixed $code Assertion code
 510     */
 511    public function assertionHandler($file, $line, $code)
 512    {
 513        if ($this->convertAssertionErrorsToExceptions) {
 514          
 515          $exception = new ErrorException('Assertion Failed - Code[ ' . $code . ' ]', 0, null, $file, $line);
 516    
 517          if ($this->throwAssertionExceptions) {
 518              throw $exception;
 519          } else {
 520              $this->fb($exception);
 521          }
 522        
 523        } else {
 524            $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File' => $file, 'Line' => $line));
 525        }
 526    }
 527  
 528    /**
 529     * Start a group for following messages.
 530     * 
 531     * Options:
 532     *   Collapsed: [true|false]
 533     *   Color:     [#RRGGBB|ColorName]
 534     *
 535     * @param string $name
 536     * @param array $options OPTIONAL Instructions on how to log the group
 537     * @return true
 538     * @throws Exception
 539     */
 540    public function group($name, $options = null)
 541    {
 542    
 543        if ( !isset($name) ) {
 544            throw $this->newException('You must specify a label for the group!');
 545        }
 546
 547        if ($options) {
 548            if (!is_array($options)) {
 549                throw $this->newException('Options must be defined as an array!');
 550            }
 551            if (array_key_exists('Collapsed', $options)) {
 552                $options['Collapsed'] = ($options['Collapsed']) ? 'true' : 'false';
 553            }
 554        }
 555
 556        return $this->fb(null, $name, FirePHP::GROUP_START, $options);
 557    }
 558  
 559    /**
 560     * Ends a group you have started before
 561     *
 562     * @return true
 563     * @throws Exception
 564     */
 565    public function groupEnd()
 566    {
 567        return $this->fb(null, null, FirePHP::GROUP_END);
 568    }
 569
 570    /**
 571     * Log object with label to firebug console
 572     *
 573     * @see FirePHP::LOG
 574     * @param mixes $object
 575     * @param string $label
 576     * @return true
 577     * @throws Exception
 578     */
 579    public function log($object, $label = null, $options = array())
 580    {
 581        return $this->fb($object, $label, FirePHP::LOG, $options);
 582    } 
 583
 584    /**
 585     * Log object with label to firebug console
 586     *
 587     * @see FirePHP::INFO
 588     * @param mixes $object
 589     * @param string $label
 590     * @return true
 591     * @throws Exception
 592     */
 593    public function info($object, $label = null, $options = array())
 594    {
 595        return $this->fb($object, $label, FirePHP::INFO, $options);
 596    } 
 597
 598    /**
 599     * Log object with label to firebug console
 600     *
 601     * @see FirePHP::WARN
 602     * @param mixes $object
 603     * @param string $label
 604     * @return true
 605     * @throws Exception
 606     */
 607    public function warn($object, $label = null, $options = array())
 608    {
 609        return $this->fb($object, $label, FirePHP::WARN, $options);
 610    } 
 611
 612    /**
 613     * Log object with label to firebug console
 614     *
 615     * @see FirePHP::ERROR
 616     * @param mixes $object
 617     * @param string $label
 618     * @return true
 619     * @throws Exception
 620     */
 621    public function error($object, $label = null, $options = array())
 622    {
 623        return $this->fb($object, $label, FirePHP::ERROR, $options);
 624    } 
 625
 626    /**
 627     * Dumps key and variable to firebug server panel
 628     *
 629     * @see FirePHP::DUMP
 630     * @param string $key
 631     * @param mixed $variable
 632     * @return true
 633     * @throws Exception
 634     */
 635    public function dump($key, $variable, $options = array())
 636    {
 637        if (!is_string($key)) {
 638            throw $this->newException('Key passed to dump() is not a string');
 639        }
 640        if (strlen($key) > 100) {
 641            throw $this->newException('Key passed to dump() is longer than 100 characters');
 642        }
 643        if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $key, $m)) {
 644            throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]');
 645        }
 646        return $this->fb($variable, $key, FirePHP::DUMP, $options);
 647    }
 648  
 649    /**
 650     * Log a trace in the firebug console
 651     *
 652     * @see FirePHP::TRACE
 653     * @param string $label
 654     * @return true
 655     * @throws Exception
 656     */
 657    public function trace($label)
 658    {
 659        return $this->fb($label, FirePHP::TRACE);
 660    } 
 661
 662    /**
 663     * Log a table in the firebug console
 664     *
 665     * @see FirePHP::TABLE
 666     * @param string $label
 667     * @param string $table
 668     * @return true
 669     * @throws Exception
 670     */
 671    public function table($label, $table, $options = array())
 672    {
 673        return $this->fb($table, $label, FirePHP::TABLE, $options);
 674    }
 675
 676    /**
 677     * Insight API wrapper
 678     * 
 679     * @see Insight_Helper::to()
 680     */
 681    public static function to()
 682    {
 683        $instance = self::getInstance();
 684        if (!method_exists($instance, '_to')) {
 685            throw new Exception('FirePHP::to() implementation not loaded');
 686        }
 687        $args = func_get_args();
 688        return call_user_func_array(array($instance, '_to'), $args);
 689    }
 690
 691    /**
 692     * Insight API wrapper
 693     * 
 694     * @see Insight_Helper::plugin()
 695     */
 696    public static function plugin()
 697    {
 698        $instance = self::getInstance();
 699        if (!method_exists($instance, '_plugin')) {
 700            throw new Exception('FirePHP::plugin() implementation not loaded');
 701        }
 702        $args = func_get_args();
 703        return call_user_func_array(array($instance, '_plugin'), $args);
 704    }
 705
 706    /**
 707     * Check if FirePHP is installed on client
 708     *
 709     * @return boolean
 710     */
 711    public function detectClientExtension()
 712    {
 713        // Check if FirePHP is installed on client via User-Agent header
 714        if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si', $this->getUserAgent(), $m) &&
 715           version_compare($m[1][0], '0.0.6', '>=')) {
 716            return true;
 717        } else
 718        // Check if FirePHP is installed on client via X-FirePHP-Version header
 719        if (@preg_match_all('/^([\.\d]*)$/si', $this->getRequestHeader('X-FirePHP-Version'), $m) &&
 720           version_compare($m[1][0], '0.0.6', '>=')) {
 721            return true;
 722        }
 723        return false;
 724    }
 725 
 726    /**
 727     * Log varible to Firebug
 728     * 
 729     * @see http://www.firephp.org/Wiki/Reference/Fb
 730     * @param mixed $object The variable to be logged
 731     * @return boolean Return TRUE if message was added to headers, FALSE otherwise
 732     * @throws Exception
 733     */
 734    public function fb($object)
 735    {
 736        if ($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) {
 737            if (!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message
 738                $this->_logUpgradeClientMessage();
 739            }
 740        }
 741
 742        static $insightGroupStack = array();
 743
 744        if (!$this->getEnabled()) {
 745            return false;
 746        }
 747
 748        if ($this->headersSent($filename, $linenum)) {
 749            // If we are logging from within the exception handler we cannot throw another exception
 750            if ($this->inExceptionHandler) {
 751                // Simply echo the error out to the page
 752                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>';
 753            } else {
 754                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.');
 755            }
 756        }
 757      
 758        $type = null;
 759        $label = null;
 760        $options = array();
 761      
 762        if (func_num_args() == 1) {
 763        } else if (func_num_args() == 2) {
 764            switch (func_get_arg(1)) {
 765                case self::LOG:
 766                case self::INFO:
 767                case self::WARN:
 768                case self::ERROR:
 769                case self::DUMP:
 770                case self::TRACE:
 771                case self::EXCEPTION:
 772                case self::TABLE:
 773                case self::GROUP_START:
 774                case self::GROUP_END:
 775                    $type = func_get_arg(1);
 776                    break;
 777                default:
 778                    $label = func_get_arg(1);
 779                    break;
 780            }
 781        } else if (func_num_args() == 3) {
 782            $type = func_get_arg(2);
 783            $label = func_get_arg(1);
 784        } else if (func_num_args() == 4) {
 785            $type = func_get_arg(2);
 786            $label = func_get_arg(1);
 787            $options = func_get_arg(3);
 788        } else {
 789            throw $this->newException('Wrong number of arguments to fb() function!');
 790        }
 791
 792        // Get folder name where firephp is located.
 793        $parentFolder = basename(dirname(__FILE__));
 794        $parentFolderLength = strlen( $parentFolder );
 795        $fbLength = 7 + $parentFolderLength;
 796        $fireClassLength = 18 + $parentFolderLength;
 797
 798        if ($this->logToInsightConsole !== null && (get_class($this) == 'FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) {
 799            $trace = debug_backtrace();
 800            if (!$trace) return false;
 801            for ($i = 0; $i < sizeof($trace); $i++) {
 802                if (isset($trace[$i]['class'])) {
 803                    if ($trace[$i]['class'] == 'FirePHP' || $trace[$i]['class'] == 'FB') {
 804                        continue;
 805                    }
 806                }
 807                if (isset($trace[$i]['file'])) {
 808                    $path = $this->_standardizePath($trace[$i]['file']);
 809                    if (substr($path, -1*$fbLength, $fbLength) == $parentFolder.'/fb.php' || substr($path, -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php') {
 810                        continue;
 811                    }
 812                }
 813                if (isset($trace[$i]['function']) && $trace[$i]['function'] == 'fb' &&
 814                        isset($trace[$i - 1]['file']) && substr($this->_standardizePath($trace[$i - 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') {
 815                    continue;
 816                }
 817                if (isset($trace[$i]['class']) && $trace[$i]['class'] == 'FB' &&
 818                        isset($trace[$i - 1]['file']) && substr($this->_standardizePath($trace[$i - 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') {
 819                    continue;
 820                }
 821                break;
 822            }
 823            // adjust trace offset
 824            $msg = $this->logToInsightConsole->option('encoder.trace.offsetAdjustment', $i);
 825
 826            if ($object instanceof Exception) {
 827                $type = self::EXCEPTION;
 828            }
 829            if ($label && $type != self::TABLE && $type != self::GROUP_START) {
 830                $msg = $msg->label($label);
 831            }
 832            switch ($type) {
 833                case self::DUMP:
 834                case self::LOG:
 835                    return $msg->log($object);
 836                case self::INFO:
 837                    return $msg->info($object);
 838                case self::WARN:
 839                    return $msg->warn($object);
 840                case self::ERROR:
 841                    return $msg->error($object);
 842                case self::TRACE:
 843                    return $msg->trace($object);
 844                case self::EXCEPTION:
 845                    return $this->plugin('error')->handleException($object, $msg);
 846                case self::TABLE:
 847                    if (isset($object[0]) && !is_string($object[0]) && $label) {
 848                        $object = array($label, $object);
 849                    }
 850                    return $msg->table($object[0], array_slice($object[1], 1), $object[1][0]);
 851                case self::GROUP_START:
 852                    $insightGroupStack[] = $msg->group(md5($label))->open();
 853                    return $msg->log($label);
 854                case self::GROUP_END:
 855                    if (count($insightGroupStack) == 0) {
 856                        throw new Error('Too many groupEnd() as opposed to group() calls!');
 857                    }
 858                    $group = array_pop($insightGroupStack);
 859                    return $group->close();
 860                default:
 861                    return $msg->log($object);
 862            }
 863        }
 864
 865        if (!$this->detectClientExtension()) {
 866            return false;
 867        }
 868
 869        $meta = array();
 870        $skipFinalObjectEncode = false;
 871      
 872        if ($object instanceof Exception) {
 873    
 874            $meta['file'] = $this->_escapeTraceFile($object->getFile());
 875            $meta['line'] = $object->getLine();
 876          
 877            $trace = $object->getTrace();
 878            if ($object instanceof ErrorException
 879               && isset($trace[0]['function'])
 880               && $trace[0]['function'] == 'errorHandler'
 881               && isset($trace[0]['class'])
 882               && $trace[0]['class'] == 'FirePHP') {
 883               
 884                $severity = false;
 885                switch ($object->getSeverity()) {
 886                    case E_WARNING:
 887                        $severity = 'E_WARNING';
 888                        break;
 889
 890                    case E_NOTICE:
 891                        $severity = 'E_NOTICE';
 892                        break;
 893
 894                    case E_USER_ERROR:
 895                        $severity = 'E_USER_ERROR';
 896                        break;
 897
 898                    case E_USER_WARNING:
 899                        $severity = 'E_USER_WARNING';
 900                        break;
 901
 902                    case E_USER_NOTICE:
 903                        $severity = 'E_USER_NOTICE';
 904                        break;
 905
 906                    case E_STRICT:
 907                        $severity = 'E_STRICT';
 908                        break;
 909
 910                    case E_RECOVERABLE_ERROR:
 911                        $severity = 'E_RECOVERABLE_ERROR';
 912                        break;
 913
 914                    case E_DEPRECATED:
 915                        $severity = 'E_DEPRECATED';
 916                        break;
 917
 918                    case E_USER_DEPRECATED:
 919                        $severity = 'E_USER_DEPRECATED';
 920                        break;
 921                }
 922                   
 923                $object = array('Class' => get_class($object),
 924                                'Message' => $severity . ': ' . $object->getMessage(),
 925                                'File' => $this->_escapeTraceFile($object->getFile()),
 926                                'Line' => $object->getLine(),
 927                                'Type' => 'trigger',
 928                                'Trace' => $this->_escapeTrace(array_splice($trace, 2)));
 929                $skipFinalObjectEncode = true;
 930            } else {
 931                $object = array('Class' => get_class($object),
 932                                'Message' => $object->getMessage(),
 933                                'File' => $this->_escapeTraceFile($object->getFile()),
 934                                'Line' => $object->getLine(),
 935                                'Type' => 'throw',
 936                                'Trace' => $this->_escapeTrace($trace));
 937                $skipFinalObjectEncode = true;
 938            }
 939            $type = self::EXCEPTION;
 940          
 941        } else if ($type == self::TRACE) {
 942          
 943            $trace = debug_backtrace();
 944            if (!$trace) return false;
 945            for ($i = 0; $i < sizeof($trace); $i++) {
 946    
 947                if (isset($trace[$i]['class'])
 948                   && isset($trace[$i]['file'])
 949                   && ($trace[$i]['class'] == 'FirePHP'
 950                       || $trace[$i]['class'] == 'FB')
 951                   && (substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php'
 952                       || substr($this->_standardizePath($trace[$i]['file']), -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php')) {
 953                    /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
 954                } else
 955                if (isset($trace[$i]['class'])
 956                   && isset($trace[$i+1]['file'])
 957                   && $trace[$i]['class'] == 'FirePHP'
 958                   && substr($this->_standardizePath($trace[$i + 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') {
 959                    /* Skip fb() */
 960                } else
 961                if ($trace[$i]['function'] == 'fb'
 962                   || $trace[$i]['function'] == 'trace'
 963                   || $trace[$i]['function'] == 'send') {
 964
 965                    $object = array('Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '',
 966                                    'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '',
 967                                    'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '',
 968                                    'Message' => $trace[$i]['args'][0],
 969                                    'File' => isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : '',
 970                                    'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '',
 971                                    'Args' => isset($trace[$i]['args']) ? $this->encodeObject($trace[$i]['args']) : '',
 972                                    'Trace' => $this->_escapeTrace(array_splice($trace, $i + 1)));
 973        
 974                    $skipFinalObjectEncode = true;
 975                    $meta['file'] = isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : '';
 976                    $meta['line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : '';
 977                    break;
 978                }
 979            }
 980    
 981        } else
 982        if ($type == self::TABLE) {
 983          
 984            if (isset($object[0]) && is_string($object[0])) {
 985                $object[1] = $this->encodeTable($object[1]);
 986            } else {
 987                $object = $this->encodeTable($object);
 988            }
 989    
 990            $skipFinalObjectEncode = true;
 991          
 992        } else if ($type == self::GROUP_START) {
 993          
 994            if (!$label) {
 995                throw $this->newException('You must specify a label for the group!');
 996            }
 997          
 998        } else {
 999            if ($type === null) {
1000                $type = self::LOG;
1001            }
1002        }
1003        
1004        if ($this->options['includeLineNumbers']) {
1005            if (!isset($meta['file']) || !isset($meta['line'])) {
1006    
1007                $trace = debug_backtrace();
1008                for ($i = 0; $trace && $i < sizeof($trace); $i++) {
1009          
1010                    if (isset($trace[$i]['class'])
1011                       && isset($trace[$i]['file'])
1012                       && ($trace[$i]['class'] == 'FirePHP'
1013                           || $trace[$i]['class'] == 'FB')
1014                       && (substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php'
1015                           || substr($this->_standardizePath($trace[$i]['file']), -1*$fireClassLength, $fireClassLength) == $parentFolder.'/FirePHP.class.php')) {
1016                        /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */
1017                    } else
1018                    if (isset($trace[$i]['class'])
1019                       && isset($trace[$i + 1]['file'])
1020                       && $trace[$i]['class'] == 'FirePHP'
1021                       && substr($this->_standardizePath($trace[$i + 1]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') {
1022                        /* Skip fb() */
1023                    } else
1024                    if (isset($trace[$i]['file'])
1025                       && substr($this->_standardizePath($trace[$i]['file']), -1*$fbLength, $fbLength) == $parentFolder.'/fb.php') {
1026                        /* Skip FB::fb() */
1027                    } else {
1028                        $meta['file'] = isset($trace[$i]['file']) ? $this->_escapeTraceFile($trace[$i]['file']) : '';
1029                        $meta['line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : '';
1030                        break;
1031                    }
1032                }      
1033            }
1034        } else {
1035            unset($meta['file']);
1036            unset($meta['line']);
1037        }
1038
1039        $this->setHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
1040        $this->setHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/' . self::VERSION);
1041     
1042        $structureIndex = 1;
1043        if ($type == self::DUMP) {
1044            $structureIndex = 2;
1045            $this->setHeader('X-Wf-1-Structure-2', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
1046        } else {
1047            $this->setHeader('X-Wf-1-Structure-1', 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
1048        }
1049      
1050        if ($type == self::DUMP) {
1051            $msg = '{"' . $label . '":' . $this->jsonEncode($object, $skipFinalObjectEncode) . '}';
1052        } else {
1053            $msgMeta = $options;
1054            $msgMeta['Type'] = $type;
1055            if ($label !== null) {
1056                $msgMeta['Label'] = $label;
1057            }
1058            if (isset($meta['file']) && !isset($msgMeta['File'])) {
1059                $msgMeta['File'] = $meta['file'];
1060            }
1061            if (isset($meta['line']) && !isset($msgMeta['Line'])) {
1062                $msgMeta['Line'] = $meta['line'];
1063            }
1064            $msg = '[' . $this->jsonEncode($msgMeta) . ',' . $this->jsonEncode($object, $skipFinalObjectEncode) . ']';
1065        }
1066        
1067        $parts = explode("\n", chunk_split($msg, 5000, "\n"));
1068
1069        for ($i = 0; $i < count($parts); $i++) {
1070            
1071            $part = $parts[$i];
1072            if ($part) {
1073                
1074                if (count($parts) > 2) {
1075                    // Message needs to be split into multiple parts
1076                    $this->setHeader('X-Wf-1-' . $structureIndex . '-' . '1-' . $this->messageIndex,
1077                                     (($i == 0) ? strlen($msg) : '')
1078                                     . '|' . $part . '|'
1079                                     . (($i < count($parts) - 2) ? '\\' : ''));
1080                } else {
1081                    $this->setHeader('X-Wf-1-' . $structureIndex . '-' . '1-' . $this->messageIndex,
1082                                     strlen($part) . '|' . $part . '|');
1083                }
1084                
1085                $this->messageIndex++;
1086                
1087                if ($this->messageIndex > 99999) {
1088                    throw $this->newException('Maximum number (99,999) of messages reached!');             
1089                }
1090            }
1091        }
1092    
1093        $this->setHeader('X-Wf-1-Index', $this->messageIndex - 1);
1094    
1095        return true;
1096    }
1097  
1098    /**
1099     * Standardizes path for windows systems.
1100     *
1101     * @param string $path
1102     * @return string
1103     */
1104    protected function _standardizePath($path)
1105    {
1106        return preg_replace('/\\\\+/', '/', $path);
1107    }
1108  
1109    /**
1110     * Escape trace path for windows systems
1111     *
1112     * @param array $trace
1113     * @return array
1114     */
1115    protected function _escapeTrace($trace)
1116    {
1117        if (!$trace) return $trace;
1118        for ($i = 0; $i < sizeof($trace); $i++) {
1119            if (isset($trace[$i]['file'])) {
1120                $trace[$i]['file'] = $this->_escapeTraceFile($trace[$i]['file']);
1121            }
1122            if (isset($trace[$i]['args'])) {
1123                $trace[$i]['args'] = $this->encodeObject($trace[$i]['args']);
1124            }
1125        }
1126        return $trace;    
1127    }
1128  
1129    /**
1130     * Escape file information of trace for windows systems
1131     *
1132     * @param string $file
1133     * @return string
1134     */
1135    protected function _escapeTraceFile($file)
1136    {
1137        /* Check if we have a windows filepath */
1138        if (strpos($file, '\\')) {
1139            /* First strip down to single \ */
1140
1141            $file = preg_replace('/\\\\+/', '\\', $file);
1142
1143            return $file;
1144        }
1145        return $file;
1146    }
1147
1148    /**
1149     * Check if headers have already been sent
1150     *
1151     * @param string $filename
1152     * @param integer $linenum
1153     */
1154    protected function headersSent(&$filename, &$linenum)
1155    {
1156        return headers_sent($filename, $linenum);
1157    }
1158
1159    /**
1160     * Send header
1161     *
1162     * @param string $name
1163     * @param string $value
1164     */
1165    protected function setHeader($name, $value)
1166    {
1167        return header($name . ': ' . $value);
1168    }
1169
1170    /**
1171     * Get user agent
1172     *
1173     * @return string|false
1174     */
1175    protected function getUserAgent()
1176    {
1177        if (!isset($_SERVER['HTTP_USER_AGENT'])) return false;
1178        return $_SERVER['HTTP_USER_AGENT'];
1179    }
1180
1181    /**
1182     * Get all request headers
1183     * 
1184     * @return array
1185     */
1186    public static function getAllRequestHeaders()
1187    {
1188        static $_cachedHeaders = false;
1189        if ($_cachedHeaders !== false) {
1190            return $_cachedHeaders;
1191        }
1192        $headers = array();
1193        if (function_exists('getallheaders')) {
1194            foreach (getallheaders() as $name => $value) {
1195                $headers[strtolower($name)] = $value;
1196            }
1197        } else {
1198            foreach ($_SERVER as $name => $value) {
1199                if (substr($name, 0, 5) == 'HTTP_') {
1200                    $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value;
1201                }
1202            }
1203        }
1204        return $_cachedHeaders = $headers;
1205    }
1206
1207    /**
1208     * Get a request header
1209     *
1210     * @return string|false
1211     */
1212    protected function getRequestHeader($name)
1213    {
1214        $headers = self::getAllRequestHeaders();
1215        if (isset($headers[strtolower($name)])) {
1216            return $headers[strtolower($name)];
1217        }
1218        return false;
1219    }
1220
1221    /**
1222     * Returns a new exception
1223     *
1224     * @param string $message
1225     * @return Exception
1226     */
1227    protected function newException($message)
1228    {
1229        return new Exception($message);
1230    }
1231  
1232    /**
1233     * Encode an object into a JSON string
1234     * 
1235     * Uses PHP's jeson_encode() if available
1236     * 
1237     * @param object $object The object to be encoded
1238     * @param boolean $skipObjectEncode
1239     * @return string The JSON string
1240     */
1241    public function jsonEncode($object, $skipObjectEncode = false)
1242    {
1243        if (!$skipObjectEncode) {
1244            $object = $this->encodeObject($object);
1245        }
1246        
1247        if (function_exists('json_encode')
1248           && $this->options['useNativeJsonEncode'] != false) {
1249    
1250            return json_encode($object);
1251        } else {
1252            return $this->json_encode($object);
1253        }
1254    }
1255
1256    /**
1257     * Encodes a table by encoding each row and column with encodeObject()
1258     * 
1259     * @param array $table The table to be encoded
1260     * @return array
1261     */  
1262    protected function encodeTable($table)
1263    {
1264        if (!$table) return $table;
1265        
1266        $newTable = array();
1267        foreach ($table as $row) {
1268
1269            if (is_array($row)) {
1270                $newRow = array();
1271
1272                foreach ($row as $item) {
1273                    $newRow[] = $this->encodeObject($item);
1274                }
1275
1276                $newTable[] = $newRow;
1277            }
1278        }
1279
1280        return $newTable;
1281    }
1282
1283    /**
1284     * Encodes an object including members with
1285     * protected and private visibility
1286     * 
1287     * @param object $object The object to be encoded
1288     * @param integer $Depth The current traversal depth
1289     * @return array All members of the object
1290     */
1291    protected function encodeObject($object, $objectDepth = 1, $arrayDepth = 1, $maxDepth = 1)
1292    {
1293        if ($maxDepth > $this->options['maxDepth']) {
1294            return '** Max Depth (' . $this->options['maxDepth'] . ') **';
1295        }
1296
1297        $return = array();
1298    
1299        //#2801 is_resource reports false for closed resources https://bugs.php.net/bug.php?id=28016
1300        if (is_resource($object) || gettype($object) === "unknown type") {
1301    
1302            return '** ' . (string) $object . ' **';
1303    
1304        } else if (is_object($object)) {
1305    
1306            if ($objectDepth > $this->options['maxObjectDepth']) {
1307                return '** Max Object Depth (' . $this->options['maxObjectDepth'] . ') **';
1308            }
1309            
1310            foreach ($this->objectStack as $refVal) {
1311                if ($refVal === $object) {
1312                    return '** Recursion (' . get_class($object) . ') **';
1313                }
1314            }
1315            array_push($this->objectStack, $object);
1316                    
1317            $return['__className'] = $class = get_class($object);
1318            $classLower = strtolower($class);
1319
1320            $reflectionClass = new ReflectionClass($class);
1321            $properties = array();
1322            foreach ($reflectionClass->getProperties() as $property) {
1323                $properties[$property->getName()] = $property;
1324            }
1325                
1326            $members = (array)$object;
1327    
1328            foreach ($properties as $plainName => $property) {
1329    
1330                $name = $rawName = $plainName;
1331                if ($property->isStatic()) {
1332                    $name = 'static:' . $name;
1333                }
1334                if ($property->isPublic()) {
1335                    $name = 'public:' . $name;
1336                } else if ($property->isPrivate()) {
1337                    $name = 'private:' . $name;
1338                    $rawName = "\0" . $class . "\0" . $rawName;
1339                } else if ($property->isProtected()) {
1340                    $name = 'protected:' . $name;
1341                    $rawName = "\0" . '*' . "\0" . $rawName;
1342                }
1343    
1344                if (!(isset($this->objectFilters[$classLower])
1345                     && is_array($this->objectFilters[$classLower])
1346                     && in_array($plainName, $this->objectFilters[$classLower]))) {
1347    
1348                    if (array_key_exists($rawName, $members) && !$property->isStatic()) {
1349                        $return[$name] = $this->encodeObject($members[$rawName], $objectDepth + 1, 1, $maxDepth + 1);
1350                    } else {
1351                        if (method_exists($property, 'setAccessible')) {
1352                            $property->setAccessible(true);
1353                            $return[$name] = $this->encodeObject($property->getValue($object), $objectDepth + 1, 1, $maxDepth + 1);
1354                        } else
1355                        if ($property->isPublic()) {
1356                            $return[$name] = $this->encodeObject($property->getValue($object), $objectDepth + 1, 1, $maxDepth + 1);
1357                        } else {
1358                            $return[$name] = '** Need PHP 5.3 to get value **';
1359                        }
1360                    }
1361                } else {
1362                    $return[$name] = '** Excluded by Filter **';
1363                }
1364            }
1365            
1366            // Include all members that are not defined in the class
1367            // but exist in the object
1368            foreach ($members as $rawName => $value) {
1369    
1370                $name = $rawName;
1371
1372                if ($name{0} == "\0") {
1373                    $parts = explode("\0", $name);
1374                    $name = $parts[2];
1375                }
1376
1377                $plainName = $name;
1378    
1379                if (!isset($properties[$name])) {
1380                    $name = 'undeclared:' . $name;
1381    
1382                    if (!(isset($this->objectFilters[$classLower])
1383                         && is_array($this->objectFilters[$classLower])
1384                         && in_array($plainName, $this->objectFilters[$classLower]))) {
1385    
1386                        $return[$name] = $this->encodeObject($value, $objectDepth + 1, 1, $maxDepth + 1);
1387                    } else {
1388                        $return[$name] = '** Excluded by Filter **';
1389                    }
1390                }
1391            }
1392            
1393            array_pop($this->objectStack);
1394            
1395        } elseif (is_array($object)) {
1396    
1397            if ($arrayDepth > $this->options['maxArrayDepth']) {
1398                return '** Max Array Depth (' . $this->options['maxArrayDepth'] . ') **';
1399            }
1400          
1401            foreach ($object as $key => $val) {                
1402
1403                // Encoding the $GLOBALS PHP array causes an infinite loop
1404                // if the recursion is not reset here as it contains
1405                // a reference to itself. This is the only way I have come up
1406                // with to stop infinite recursion in this case.
1407                if ($key == 'GLOBALS'
1408                   && is_array($val)
1409                   && array_key_exists('GLOBALS', $val)) {
1410                    $val['GLOBALS'] = '** Recursion (GLOBALS) **';
1411                }
1412
1413                if (!$this->is_utf8($key)) {
1414                    $key = utf8_encode($key);
1415                }
1416
1417                $return[$key] = $this->encodeObject($val, 1, $arrayDepth + 1, $maxDepth + 1);
1418            }
1419		} elseif ( is_bool($object) ) {
1420			return $object;
1421		} elseif ( is_null($object) ) {
1422			return $object;
1423		} elseif ( is_numeric($object) ) {
1424			return $object;
1425		} else {
1426            if ($this->is_utf8($object)) {
1427                return $object;
1428            } else {
1429                return utf8_encode($object);
1430            }
1431        }
1432        return $return;
1433    }
1434
1435    /**
1436     * Returns true if $string is valid UTF-8 and false otherwise.
1437     *
1438     * @param mixed $str String to be tested
1439     * @return boolean
1440     */
1441    protected function is_utf8($str)
1442    {
1443        if (function_exists('mb_detect_encoding')) {
1444            return (
1445                mb_detect_encoding($str, 'UTF-8', true) == 'UTF-8' &&
1446                ($str === null || $this->jsonEncode($str, true) !== 'null')
1447            );
1448        }
1449        $c = 0;
1450        $b = 0;
1451        $bits = 0;
1452        $len = strlen($str);
1453        for ($i = 0; $i < $len; $i++) {
1454            $c = ord($str[$i]);
1455            if ($c > 128) {
1456                if (($c >= 254)) return false;
1457                elseif ($c >= 252) $bits = 6;
1458                elseif ($c >= 248) $bits = 5;
1459                elseif ($c >= 240) $bits = 4;
1460                elseif ($c >= 224) $bits = 3;
1461                elseif ($c >= 192) $bits = 2;
1462                else return false;
1463                if (($i + $bits) > $len) return false;
1464                while($bits > 1) {
1465                    $i++;
1466                    $b = ord($str[$i]);
1467                    if ($b < 128 || $b > 191) return false;
1468                    $bits--;
1469                }
1470            }
1471        }
1472        return ($str === null || $this->jsonEncode($str, true) !== 'null');
1473    } 
1474
1475    /**
1476     * Converts to and from JSON format.
1477     *
1478     * JSON (JavaScript Object Notation) is a lightweight data-interchange
1479     * format. It is easy for humans to read and write. It is easy for machines
1480     * to parse and generate. It is based on a subset of the JavaScript
1481     * Programming Language, Standard ECMA-262 3rd Edition - December 1999.
1482     * This feature can also be found in  Python. JSON is a text format that is
1483     * completely language independent but uses conventions that are familiar
1484     * to programmers of the C-family of languages, including C, C++, C#, Java,
1485     * JavaScript, Perl, TCL, and many others. These properties make JSON an
1486     * ideal data-interchange language.
1487     *
1488     * This package provides a simple encoder and decoder for JSON notation. It
1489     * is intended for use with client-side Javascript applications that make
1490     * use of HTTPRequest to perform server communication functions - data can
1491     * be encoded into JSON notation for use in a…

Large files files are truncated, but you can click here to view the full file