PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms 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
Possible License(s): GPL-2.0, LGPL-2.1, BSD-3-Clause

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

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