PageRenderTime 73ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/application/libraries/Firephp.php

https://bitbucket.org/mercucci/mercucci
PHP | 1804 lines | 1033 code | 194 blank | 577 comment | 193 complexity | 02e3c18f92e9137b98a6264cacd46941 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1

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

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

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