PageRenderTime 58ms CodeModel.GetById 2ms app.highlight 46ms RepoModel.GetById 1ms app.codeStats 0ms

/system/application/libraries/Firephp.php

https://bitbucket.org/zhemel/cloudengine
PHP | 1833 lines | 1068 code | 193 blank | 572 comment | 262 complexity | abc6c2aa84ec3e1570fc974eabed89a4 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/**
   6* *** BEGIN LICENSE BLOCK *****
   7*
   8* This file is part of FirePHP (http://www.firephp.org/).
   9*
  10* Software License Agreement (New BSD License)
  11*
  12* Copyright (c) 2006-2011, Christoph Dorn
  13* All rights reserved.
  14*
  15* Redistribution and use in source and binary forms, with or without modification,
  16* are permitted provided that the following conditions are met:
  17*
  18* * Redistributions of source code must retain the above copyright notice,
  19* this list of conditions and the following disclaimer.
  20*
  21* * Redistributions in binary form must reproduce the above copyright notice,
  22* this list of conditions and the following disclaimer in the documentation
  23* and/or other materials provided with the distribution.
  24*
  25* * Neither the name of Christoph Dorn nor the names of its
  26* contributors may be used to endorse or promote products derived from this
  27* software without specific prior written permission.
  28*
  29* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  30* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  31* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  32* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  33* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  34* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  35* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  36* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  37* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  38* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  39*
  40* ***** END LICENSE BLOCK *****
  41*
  42* @copyright Copyright (C) 2007-2011 Christoph Dorn
  43* @author Christoph Dorn <christoph@christophdorn.com>
  44* @license http://www.opensource.org/licenses/bsd-license.php
  45* @package FirePHPCore
  46*/
  47
  48/**
  49* @see http://code.google.com/p/firephp/issues/detail?id=112
  50*/
  51if (!defined('E_STRICT')) {
  52    define('E_STRICT', 2048);
  53}
  54if (!defined('E_RECOVERABLE_ERROR')) {
  55    define('E_RECOVERABLE_ERROR', 4096);
  56}
  57if (!defined('E_DEPRECATED')) {
  58    define('E_DEPRECATED', 8192);
  59}
  60if (!defined('E_USER_DEPRECATED')) {
  61    define('E_USER_DEPRECATED', 16384);
  62}
  63 
  64/**
  65* Sends the given data to the FirePHP Firefox Extension.
  66* The data can be displayed in the Firebug Console or in the
  67* "Server" request tab.
  68*
  69* For more information see: http://www.firephp.org/
  70*
  71* @copyright Copyright (C) 2007-2011 Christoph Dorn
  72* @author Christoph Dorn <christoph@christophdorn.com>
  73* @license http://www.opensource.org/licenses/bsd-license.php
  74* @package FirePHPCore
  75*/
  76class FirePHP {
  77
  78    /**
  79* FirePHP version
  80*
  81* @var string
  82*/
  83    const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%'
  84
  85    /**
  86* Firebug LOG level
  87*
  88* Logs a message to firebug console.
  89*
  90* @var string
  91*/
  92    const LOG = 'LOG';
  93  
  94    /**
  95* Firebug INFO level
  96*
  97* Logs a message to firebug console and displays an info icon before the message.
  98*
  99* @var string
 100*/
 101    const INFO = 'INFO';
 102    
 103    /**
 104* Firebug WARN level
 105*
 106* Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise.
 107*
 108* @var string
 109*/
 110    const WARN = 'WARN';
 111    
 112    /**
 113* Firebug ERROR level
 114*
 115* Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count.
 116*
 117* @var string
 118*/
 119    const ERROR = 'ERROR';
 120    
 121    /**
 122* Dumps a variable to firebug's server panel
 123*
 124* @var string
 125*/
 126    const DUMP = 'DUMP';
 127    
 128    /**
 129* Displays a stack trace in firebug console
 130*
 131* @var string
 132*/
 133    const TRACE = 'TRACE';
 134    
 135    /**
 136* Displays an exception in firebug console
 137*
 138* Increments the firebug error count.
 139*
 140* @var string
 141*/
 142    const EXCEPTION = 'EXCEPTION';
 143    
 144    /**
 145* Displays an table in firebug console
 146*
 147* @var string
 148*/
 149    const TABLE = 'TABLE';
 150    
 151    /**
 152* Starts a group in firebug console
 153*
 154* @var string
 155*/
 156    const GROUP_START = 'GROUP_START';
 157    
 158    /**
 159* Ends a group in firebug console
 160*
 161* @var string
 162*/
 163    const GROUP_END = 'GROUP_END';
 164    
 165    /**
 166* Singleton instance of FirePHP
 167*
 168* @var FirePHP
 169*/
 170    protected static $instance = null;
 171    
 172    /**
 173* Flag whether we are logging from within the exception handler
 174*
 175* @var boolean
 176*/
 177    protected $inExceptionHandler = false;
 178    
 179    /**
 180* Flag whether to throw PHP errors that have been converted to ErrorExceptions
 181*
 182* @var boolean
 183*/
 184    protected $throwErrorExceptions = true;
 185    
 186    /**
 187* Flag whether to convert PHP assertion errors to Exceptions
 188*
 189* @var boolean
 190*/
 191    protected $convertAssertionErrorsToExceptions = true;
 192    
 193    /**
 194* Flag whether to throw PHP assertion errors that have been converted to Exceptions
 195*
 196* @var boolean
 197*/
 198    protected $throwAssertionExceptions = false;
 199
 200    /**
 201* Wildfire protocol message index
 202*
 203* @var integer
 204*/
 205    protected $messageIndex = 1;
 206    
 207    /**
 208* Options for the library
 209*
 210* @var array
 211*/
 212    protected $options = array('maxDepth' => 10,
 213                               'maxObjectDepth' => 5,
 214                               'maxArrayDepth' => 5,
 215                               'useNativeJsonEncode' => true,
 216                               'includeLineNumbers' => true);
 217
 218    /**
 219* Filters used to exclude object members when encoding
 220*
 221* @var array
 222*/
 223    protected $objectFilters = array(
 224        'firephp' => array('objectStack', 'instance', 'json_objectStack'),
 225        'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack')
 226    );
 227
 228    /**
 229* A stack of objects used to detect recursion during object encoding
 230*
 231* @var object
 232*/
 233    protected $objectStack = array();
 234
 235    /**
 236* Flag to enable/disable logging
 237*
 238* @var boolean
 239*/
 240    protected $enabled = true;
 241
 242    /**
 243* The insight console to log to if applicable
 244*
 245* @var object
 246*/
 247    protected $logToInsightConsole = null;
 248
 249    /**
 250* When the object gets serialized only include specific object members.
 251*
 252* @return array
 253*/
 254    public function __sleep()
 255    {
 256        return array('options', 'objectFilters', 'enabled');
 257    }
 258    
 259    /**
 260* Gets singleton instance of FirePHP
 261*
 262* @param boolean $AutoCreate
 263* @return FirePHP
 264*/
 265    public static function getInstance($AutoCreate = false)
 266    {
 267        if ($AutoCreate===true && !self::$instance) {
 268            self::init();
 269        }
 270        return self::$instance;
 271    }
 272    
 273    /**
 274* Creates FirePHP object and stores it for singleton access
 275*
 276* @return FirePHP
 277*/
 278    public static function init()
 279    {
 280        return self::setInstance(new self());
 281    }
 282
 283    /**
 284* Set the instance of the FirePHP singleton
 285*
 286* @param FirePHP $instance The FirePHP object instance
 287* @return FirePHP
 288*/
 289    public static function setInstance($instance)
 290    {
 291        return self::$instance = $instance;
 292    }
 293
 294    /**
 295* Set an Insight console to direct all logging calls to
 296*
 297* @param object $console The console object to log to
 298* @return void
 299*/
 300    public function setLogToInsightConsole($console)
 301    {
 302        if (is_string($console)) {
 303            if (get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) {
 304                throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!');
 305            }
 306            $this->logToInsightConsole = $this->to('request')->console($console);
 307        } else {
 308            $this->logToInsightConsole = $console;
 309        }
 310    }
 311
 312    /**
 313* Enable and disable logging to Firebug
 314*
 315* @param boolean $Enabled TRUE to enable, FALSE to disable
 316* @return void
 317*/
 318    public function setEnabled($Enabled)
 319    {
 320       $this->enabled = $Enabled;
 321    }
 322    
 323    /**
 324* Check if logging is enabled
 325*
 326* @return boolean TRUE if enabled
 327*/
 328    public function getEnabled()
 329    {
 330        return $this->enabled;
 331    }
 332    
 333    /**
 334* Specify a filter to be used when encoding an object
 335*
 336* Filters are used to exclude object members.
 337*
 338* @param string $Class The class name of the object
 339* @param array $Filter An array of members to exclude
 340* @return void
 341*/
 342    public function setObjectFilter($Class, $Filter)
 343    {
 344        $this->objectFilters[strtolower($Class)] = $Filter;
 345    }
 346  
 347    /**
 348* Set some options for the library
 349*
 350* Options:
 351* - maxDepth: The maximum depth to traverse (default: 10)
 352* - maxObjectDepth: The maximum depth to traverse objects (default: 5)
 353* - maxArrayDepth: The maximum depth to traverse arrays (default: 5)
 354* - useNativeJsonEncode: If true will use json_encode() (default: true)
 355* - includeLineNumbers: If true will include line numbers and filenames (default: true)
 356*
 357* @param array $Options The options to be set
 358* @return void
 359*/
 360    public function setOptions($Options)
 361    {
 362        $this->options = array_merge($this->options,$Options);
 363    }
 364
 365    /**
 366* Get options from the library
 367*
 368* @return array The currently set options
 369*/
 370    public function getOptions()
 371    {
 372        return $this->options;
 373    }
 374
 375    /**
 376* Set an option for the library
 377*
 378* @param string $Name
 379* @param mixed $Value
 380* @throws Exception
 381* @return void
 382*/
 383    public function setOption($Name, $Value)
 384    {
 385        if (!isset($this->options[$Name])) {
 386            throw $this->newException('Unknown option: ' . $Name);
 387        }
 388        $this->options[$Name] = $Value;
 389    }
 390
 391    /**
 392* Get an option from the library
 393*
 394* @param string $Name
 395* @throws Exception
 396* @return mixed
 397*/
 398    public function getOption($Name)
 399    {
 400        if (!isset($this->options[$Name])) {
 401            throw $this->newException('Unknown option: ' . $Name);
 402        }
 403        return $this->options[$Name];
 404    }
 405
 406    /**
 407* Register FirePHP as your error handler
 408*
 409* Will throw exceptions for each php error.
 410*
 411* @return mixed Returns a string containing the previously defined error handler (if any)
 412*/
 413    public function registerErrorHandler($throwErrorExceptions = false)
 414    {
 415        //NOTE: The following errors will not be caught by this error handler:
 416        // E_ERROR, E_PARSE, E_CORE_ERROR,
 417        // E_CORE_WARNING, E_COMPILE_ERROR,
 418        // E_COMPILE_WARNING, E_STRICT
 419    
 420        $this->throwErrorExceptions = $throwErrorExceptions;
 421    
 422        return set_error_handler(array($this, 'errorHandler'));
 423    }
 424
 425    /**
 426* FirePHP's error handler
 427*
 428* Throws exception for each php error that will occur.
 429*
 430* @param integer $errno
 431* @param string $errstr
 432* @param string $errfile
 433* @param integer $errline
 434* @param array $errcontext
 435*/
 436    public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext)
 437    {
 438        // Don't throw exception if error reporting is switched off
 439        if (error_reporting() == 0) {
 440            return;
 441        }
 442        // Only throw exceptions for errors we are asking for
 443        if (error_reporting() & $errno) {
 444
 445            $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline);
 446            if ($this->throwErrorExceptions) {
 447                throw $exception;
 448            } else {
 449                $this->fb($exception);
 450            }
 451        }
 452    }
 453  
 454    /**
 455* Register FirePHP as your exception handler
 456*
 457* @return mixed Returns the name of the previously defined exception handler,
 458* or NULL on error.
 459* If no previous handler was defined, NULL is also returned.
 460*/
 461    public function registerExceptionHandler()
 462    {
 463        return set_exception_handler(array($this, 'exceptionHandler'));
 464    }
 465  
 466    /**
 467* FirePHP's exception handler
 468*
 469* Logs all exceptions to your firebug console and then stops the script.
 470*
 471* @param Exception $Exception
 472* @throws Exception
 473*/
 474    function exceptionHandler($Exception)
 475    {
 476        $this->inExceptionHandler = true;
 477    
 478        header('HTTP/1.1 500 Internal Server Error');
 479    
 480        try {
 481            $this->fb($Exception);
 482        } catch (Exception $e) {
 483            echo 'We had an exception: ' . $e;
 484        }
 485        
 486        $this->inExceptionHandler = false;
 487    }
 488  
 489    /**
 490* Register FirePHP driver as your assert callback
 491*
 492* @param boolean $convertAssertionErrorsToExceptions
 493* @param boolean $throwAssertionExceptions
 494* @return mixed Returns the original setting or FALSE on errors
 495*/
 496    public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false)
 497    {
 498        $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions;
 499        $this->throwAssertionExceptions = $throwAssertionExceptions;
 500        
 501        if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) {
 502            throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!');
 503        }
 504        
 505        return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler'));
 506    }
 507  
 508    /**
 509* FirePHP's assertion handler
 510*
 511* Logs all assertions to your firebug console and then stops the script.
 512*
 513* @param string $file File source of assertion
 514* @param integer $line Line source of assertion
 515* @param mixed $code Assertion code
 516*/
 517    public function assertionHandler($file, $line, $code)
 518    {
 519        if ($this->convertAssertionErrorsToExceptions) {
 520          
 521          $exception = new ErrorException('Assertion Failed - Code[ ' . $code . ' ]', 0, null, $file, $line);
 522    
 523          if ($this->throwAssertionExceptions) {
 524              throw $exception;
 525          } else {
 526              $this->fb($exception);
 527          }
 528        
 529        } else {
 530            $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File' => $file, 'Line' => $line));
 531        }
 532    }
 533  
 534    /**
 535* Start a group for following messages.
 536*
 537* Options:
 538* Collapsed: [true|false]
 539* Color: [#RRGGBB|ColorName]
 540*
 541* @param string $Name
 542* @param array $Options OPTIONAL Instructions on how to log the group
 543* @return true
 544* @throws Exception
 545*/
 546    public function group($Name, $Options = null)
 547    {
 548    
 549        if (!$Name) {
 550            throw $this->newException('You must specify a label for the group!');
 551        }
 552
 553        if ($Options) {
 554            if (!is_array($Options)) {
 555                throw $this->newException('Options must be defined as an array!');
 556            }
 557            if (array_key_exists('Collapsed', $Options)) {
 558                $Options['Collapsed'] = ($Options['Collapsed']) ? 'true' : 'false';
 559            }
 560        }
 561
 562        return $this->fb(null, $Name, FirePHP::GROUP_START, $Options);
 563    }
 564  
 565    /**
 566* Ends a group you have started before
 567*
 568* @return true
 569* @throws Exception
 570*/
 571    public function groupEnd()
 572    {
 573        return $this->fb(null, null, FirePHP::GROUP_END);
 574    }
 575
 576    /**
 577* Log object with label to firebug console
 578*
 579* @see FirePHP::LOG
 580* @param mixes $Object
 581* @param string $Label
 582* @return true
 583* @throws Exception
 584*/
 585    public function log($Object, $Label = null, $Options = array())
 586    {
 587        return $this->fb($Object, $Label, FirePHP::LOG, $Options);
 588    }
 589
 590    /**
 591* Log object with label to firebug console
 592*
 593* @see FirePHP::INFO
 594* @param mixes $Object
 595* @param string $Label
 596* @return true
 597* @throws Exception
 598*/
 599    public function info($Object, $Label = null, $Options = array())
 600    {
 601        return $this->fb($Object, $Label, FirePHP::INFO, $Options);
 602    }
 603
 604    /**
 605* Log object with label to firebug console
 606*
 607* @see FirePHP::WARN
 608* @param mixes $Object
 609* @param string $Label
 610* @return true
 611* @throws Exception
 612*/
 613    public function warn($Object, $Label = null, $Options = array())
 614    {
 615        return $this->fb($Object, $Label, FirePHP::WARN, $Options);
 616    }
 617
 618    /**
 619* Log object with label to firebug console
 620*
 621* @see FirePHP::ERROR
 622* @param mixes $Object
 623* @param string $Label
 624* @return true
 625* @throws Exception
 626*/
 627    public function error($Object, $Label = null, $Options = array())
 628    {
 629        return $this->fb($Object, $Label, FirePHP::ERROR, $Options);
 630    }
 631
 632    /**
 633* Dumps key and variable to firebug server panel
 634*
 635* @see FirePHP::DUMP
 636* @param string $Key
 637* @param mixed $Variable
 638* @return true
 639* @throws Exception
 640*/
 641    public function dump($Key, $Variable, $Options = array())
 642    {
 643        if (!is_string($Key)) {
 644            throw $this->newException('Key passed to dump() is not a string');
 645        }
 646        if (strlen($Key) > 100) {
 647            throw $this->newException('Key passed to dump() is longer than 100 characters');
 648        }
 649        if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) {
 650            throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]');
 651        }
 652        return $this->fb($Variable, $Key, FirePHP::DUMP, $Options);
 653    }
 654  
 655    /**
 656* Log a trace in the firebug console
 657*
 658* @see FirePHP::TRACE
 659* @param string $Label
 660* @return true
 661* @throws Exception
 662*/
 663    public function trace($Label)
 664    {
 665        return $this->fb($Label, FirePHP::TRACE);
 666    }
 667
 668    /**
 669* Log a table in the firebug console
 670*
 671* @see FirePHP::TABLE
 672* @param string $Label
 673* @param string $Table
 674* @return true
 675* @throws Exception
 676*/
 677    public function table($Label, $Table, $Options = array())
 678    {
 679        return $this->fb($Table, $Label, FirePHP::TABLE, $Options);
 680    }
 681
 682    /**
 683* Insight API wrapper
 684*
 685* @see Insight_Helper::to()
 686*/
 687    public static function to()
 688    {
 689        $instance = self::getInstance();
 690        if (!method_exists($instance, '_to')) {
 691            throw new Exception('FirePHP::to() implementation not loaded');
 692        }
 693        $args = func_get_args();
 694        return call_user_func_array(array($instance, '_to'), $args);
 695    }
 696
 697    /**
 698* Insight API wrapper
 699*
 700* @see Insight_Helper::plugin()
 701*/
 702    public static function plugin()
 703    {
 704        $instance = self::getInstance();
 705        if (!method_exists($instance, '_plugin')) {
 706            throw new Exception('FirePHP::plugin() implementation not loaded');
 707        }
 708        $args = func_get_args();
 709        return call_user_func_array(array($instance, '_plugin'), $args);
 710    }
 711
 712    /**
 713* Check if FirePHP is installed on client
 714*
 715* @return boolean
 716*/
 717    public function detectClientExtension()
 718    {
 719        // Check if FirePHP is installed on client via User-Agent header
 720        if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) &&
 721           version_compare($m[1][0], '0.0.6', '>=')) {
 722            return true;
 723        } else
 724        // Check if FirePHP is installed on client via X-FirePHP-Version header
 725        if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader('X-FirePHP-Version'),$m) &&
 726           version_compare($m[1][0], '0.0.6', '>=')) {
 727            return true;
 728        }
 729        return false;
 730    }
 731 
 732    /**
 733* Log varible to Firebug
 734*
 735* @see http://www.firephp.org/Wiki/Reference/Fb
 736* @param mixed $Object The variable to be logged
 737* @return true Return TRUE if message was added to headers, FALSE otherwise
 738* @throws Exception
 739*/
 740    public function fb($Object)
 741    {
 742        if ($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) {
 743            if (!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message
 744                $this->_logUpgradeClientMessage();
 745            }
 746        }
 747
 748        static $insightGroupStack = array();
 749
 750        if (!$this->getEnabled()) {
 751            return false;
 752        }
 753
 754        if ($this->headersSent($filename, $linenum)) {
 755            // If we are logging from within the exception handler we cannot throw another exception
 756            if ($this->inExceptionHandler) {
 757                // Simply echo the error out to the page
 758                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>';
 759            } else {
 760                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.');
 761            }
 762        }
 763      
 764        $Type = null;
 765        $Label = null;
 766        $Options = array();
 767      
 768        if (func_num_args() == 1) {
 769        } else if (func_num_args() == 2) {
 770            switch (func_get_arg(1)) {
 771                case self::LOG:
 772                case self::INFO:
 773                case self::WARN:
 774                case self::ERROR:
 775                case self::DUMP:
 776                case self::TRACE:
 777                case self::EXCEPTION:
 778                case self::TABLE:
 779                case self::GROUP_START:
 780                case self::GROUP_END:
 781                    $Type = func_get_arg(1);
 782                    break;
 783                default:
 784                    $Label = func_get_arg(1);
 785                    break;
 786            }
 787        } else if (func_num_args() == 3) {
 788            $Type = func_get_arg(2);
 789            $Label = func_get_arg(1);
 790        } else if (func_num_args() == 4) {
 791            $Type = func_get_arg(2);
 792            $Label = func_get_arg(1);
 793            $Options = func_get_arg(3);
 794        } else {
 795            throw $this->newException('Wrong number of arguments to fb() function!');
 796        }
 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, -18, 18) == 'FirePHPCore/fb.php' || substr($path, -29, 29) == 'FirePHPCore/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']), -18, 18) == 'FirePHPCore/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']), -18, 18) == 'FirePHPCore/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('engine')->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']), -18, 18) == 'FirePHPCore/fb.php'
 952                       || substr($this->_standardizePath($trace[$i]['file']), -29, 29) == 'FirePHPCore/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']), -18, 18) == 'FirePHPCore/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']), -18, 18) == 'FirePHPCore/fb.php'
1015                           || substr($this->_standardizePath($trace[$i]['file']), -29, 29) == 'FirePHPCore/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']), -18, 18) == 'FirePHPCore/fb.php') {
1022                        /* Skip fb() */
1023                    } else
1024                    if (isset($trace[$i]['file'])
1025                       && substr($this->_standardizePath($trace[$i]['file']), -18, 18) == 'FirePHPCore/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        $structure_index = 1;
1043        if ($Type == self::DUMP) {
1044            $structure_index = 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            $msg_meta = $Options;
1054            $msg_meta['Type'] = $Type;
1055            if ($Label !== null) {
1056                $msg_meta['Label'] = $Label;
1057            }
1058            if (isset($meta['file']) && !isset($msg_meta['File'])) {
1059                $msg_meta['File'] = $meta['file'];
1060            }
1061            if (isset($meta['line']) && !isset($msg_meta['Line'])) {
1062                $msg_meta['Line'] = $meta['line'];
1063            }
1064            $msg = '[' . $this->jsonEncode($msg_meta) . ',' . $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-' . $structure_index . '-' . '1-' . $this->messageIndex,
1077                                     (($i == 0) ? strlen($msg) : '')
1078                                     . '|' . $part . '|'
1079                                     . (($i < count($parts) - 2) ? '\\' : ''));
1080                } else {
1081                    $this->setHeader('X-Wf-1-' . $structure_index . '-' . '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 $_cached_headers = false;
1189        if ($_cached_headers !== false) {
1190            return $_cached_headers;
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 $_cached_headers = $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        $new_table = array();
1267        foreach ($Table as $row) {
1268
1269            if (is_array($row)) {
1270                $new_row = array();
1271
1272                foreach ($row as $item) {
1273                    $new_row[] = $this->encodeObject($item);
1274                }
1275
1276                $new_table[] = $new_row;
1277            }
1278        }
1279
1280        return $new_table;
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        if (is_resource($Object)) {
1300    
1301            return '** ' . (string) $Object . ' **';
1302    
1303        } else if (is_object($Object)) {
1304    
1305            if ($ObjectDepth > $this->options['maxObjectDepth']) {
1306                return '** Max Object Depth (' . $this->options['maxObjectDepth'] . ') **';
1307            }
1308            
1309            foreach ($this->objectStack as $refVal) {
1310                if ($refVal === $Object) {
1311                    return '** Recursion (' . get_class($Object) . ') **';
1312                }
1313            }
1314            array_push($this->objectStack, $Object);
1315                    
1316            $return['__className'] = $class = get_class($Object);
1317            $class_lower = strtolower($class);
1318
1319            $reflectionClass = new ReflectionClass($class);
1320            $properties = array();
1321            foreach ($reflectionClass->getProperties() as $property) {
1322                $properties[$property->getName()] = $property;
1323            }
1324                
1325            $members = (array)$Object;
1326    
1327            foreach ($properties as $plain_name => $property) {
1328    
1329                $name = $raw_name = $plain_name;
1330                if ($property->isStatic()) {
1331                    $name = 'static:' . $name;
1332                }
1333                if ($property->isPublic()) {
1334                    $name = 'public:' . $name;
1335                } else if ($property->isPrivate()) {
1336                    $name = 'private:' . $name;
1337                    $raw_name = "\0" . $class . "\0" . $raw_name;
1338                } else if ($property->isProtected()) {
1339                    $name = 'protected:' . $name;
1340                    $raw_name = "\0" . '*' . "\0" . $raw_name;
1341                }
1342    
1343                if (!(isset($this->objectFilters[$class_lower])
1344                     && is_array($this->objectFilters[$class_lower])
1345                     && in_array($plain_name, $this->objectFilters[$class_lower]))) {
1346    
1347                    if (array_key_exists($raw_name,$members) && !$property->isStatic()) {
1348                        $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1);
1349                    } else {
1350                        if (method_exists($property, 'setAccessible')) {
1351                            $property->setAccessible(true);
1352                            $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1);
1353                        } else
1354                        if ($property->isPublic()) {
1355                            $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1);
1356                        } else {
1357                            $return[$name] = '** Need PHP 5.3 to get value **';
1358                        }
1359                    }
1360                } else {
1361                    $return[$name] = '** Excluded by Filter **';
1362                }
1363            }
1364            
1365            // Include all members that are not defined in the class
1366            // but exist in the object
1367            foreach ($members as $raw_name => $value) {
1368    
1369                $name = $raw_name;
1370
1371                if ($name{0} == "\0") {
1372                    $parts = explode("\0", $name);
1373                    $name = $parts[2];
1374                }
1375
1376                $plain_name = $name;
1377    
1378                if (!isset($properties[$name])) {
1379                    $name = 'undeclared:' . $name;
1380    
1381                    if (!(isset($this->objectFilters[$class_lower])
1382                         && is_array($this->objectFilters[$class_lower])
1383                         && in_array($plain_name, $this->objectFilters[$class_lower]))) {
1384    
1385                        $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1);
1386                    } else {
1387                        $return[$name] = '** Excluded by Filter **';
1388                    }
1389                }
1390            }
1391            
1392            array_pop($this->objectStack);
1393            
1394        } elseif (is_array($Object)) {
1395    
1396            if ($ArrayDepth > $this->options['maxArrayDepth']) {
1397                return '** Max Array Depth (' . $this->options['maxArrayDepth'] . ') **';
1398            }
1399          
1400            foreach ($Object as $key => $val) {
1401
1402                // Encoding the $GLOBALS PHP array causes an infinite loop
1403                // if the recursion is not reset here as it contains
1404                // a reference to itself. This is the only way I have come up
1405                // with to stop infinite recursion in this case.
1406                if ($key == 'GLOBALS'
1407                   && is_array($val)
1408                   && array_key_exists('GLOBALS', $val)) {
1409                    $val['GLOBALS'] = '** Recursion (GLOBALS) **';
1410                }
1411
1412                if (!self::is_utf8($key)) {
1413                    $key = utf8_encode($key);
1414                }
1415
1416                $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1);
1417            }
1418        } else {
1419            if (self::is_utf8($Object)) {
1420                return $Object;
1421            } else {
1422                return utf8_encode($Object);
1423            }
1424        }
1425        return $return;
1426    }
1427
1428    /**
1429* Returns true if $string is valid UTF-8 and false otherwise.
1430*
1431* @param mixed $str String to be tested
1432* @return boolean
1433*/
1434    protected static function is_utf8($str)
1435    {
1436        if(function_exists('mb_detect_encoding')) {
1437            return (mb_detect_encoding($str, 'UTF-8', true) == 'UTF-8');
1438        }
1439        $c = 0;
1440        $b = 0;
1441        $bits = 0;
1442        $len = strlen($str);
1443        for ($i = 0; $i < $len; $i++) {
1444            $c = ord($str[$i]);
1445            if ($c > 128) {
1446                if (($c >= 254)) return false;
1447                elseif ($c >= 252) $bits = 6;
1448                elseif ($c >= 248) $bits = 5;
1449                elseif ($c >= 240) $bits = 4;
1450                elseif ($c >= 224) $bits = 3;
1451                elseif ($c >= 192) $bits = 2;
1452                else return false;
1453                if (($i + $bits) > $len) return false;
1454                while($bits > 1){
1455                    $i++;
1456                    $b = ord($str[$i]);
1457                    if ($b < 128 || $b > 191) return false;
1458                    $bits--;
1459                }
1460            }
1461        }
1462        return true;
1463    }
1464
1465    /**
1466* Converts to and from JSON format.
1467*
1468* JSON (JavaScript Object Notation) is a lightweight data-interchange
1469* format. It is easy for humans to read and write. It is easy for machines
1470* to parse and generate. It is based on a subset of the JavaScript
1471* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
1472* This feature can also be found in Python. JSON is a text format that is
1473* completely language independent but uses conventions that are familiar
1474* to programmers of the C-family of languages, including C, C++, C#, Java,
1475* JavaScript, Perl, TCL, and many others. These properties make JSON an
1476* ideal data-interchange language.
1477*
1478* This package provides a simple encoder and decoder for JSON notation. It
1479* is intended for use with client-side Javascript applications that make
1480* use of HTTPRequest to perform server communication functions - data can
1481* be encoded into JSON notation for use in a client-side javascript, or
1482* decoded from incoming Javascript requests. JSON format is native to
1483* Javascript, and can be directly eval()'ed with no further parsing
1484* overhead
1485*
1486* All strings should be in ASCII or UTF-8 format!
1487*
1488* LICENSE: Redistribution and use in source and binary forms, with or
1489* without modification, are permitted provided that the following
1490* conditions are met: Redistributions of source code must retain the
1491* above copyright notice, this list of conditions and the following
1492* disclaimer. Redistributions in binary form must reproduce the above
1493* copyright notice, this list of conditions and the following disclaimer
1494* in the documentation and/or other materials provided with the
1495* distribution.
1496*
1497* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
1498* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
1499* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
1500* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
1501* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
1502* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
1503* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
1504* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
1505* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) AR…

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