PageRenderTime 50ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/app/Plugin/DebugKit/vendors/fire_cake.php

https://github.com/simkimsia/cake2-practice-app
PHP | 550 lines | 348 code | 11 blank | 191 comment | 43 complexity | 957423017dcefa4142aba1ec27897309 MD5 | raw file
  1. <?php
  2. /**
  3. * FirePHP Class for CakePHP
  4. *
  5. * Provides most of the functionality offered by FirePHPCore
  6. * Interoperates with FirePHP extension for firefox
  7. *
  8. * For more information see: http://www.firephp.org/
  9. *
  10. * PHP versions 4 and 5
  11. *
  12. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  13. * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  14. *
  15. * Licensed under The MIT License
  16. * Redistributions of files must retain the above copyright notice.
  17. *
  18. * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
  19. * @link http://cakephp.org
  20. * @package debug_kit
  21. * @subpackage debug_kit.views.helpers
  22. * @since DebugKit 0.1
  23. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  24. **/
  25. // Dont't allow Debugger to steal the error handler when debug = 0.
  26. if (Configure::read('debug') == 0 && !defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
  27. define('DISABLE_DEFAULT_ERROR_HANDLING', true);
  28. }
  29. App::import('Core', 'Debugger');
  30. if (!function_exists('firecake')) {
  31. function firecake($message, $label = null) {
  32. FireCake::fb($message, $label, 'log');
  33. }
  34. }
  35. class FireCake extends Object {
  36. /**
  37. * Options for FireCake.
  38. *
  39. * @see _defaultOptions and setOptions();
  40. * @var string
  41. */
  42. var $options = array();
  43. /**
  44. * Default Options used in CakeFirePhp
  45. *
  46. * @var string
  47. * @access protected
  48. */
  49. var $_defaultOptions = array(
  50. 'maxObjectDepth' => 10,
  51. 'maxArrayDepth' => 20,
  52. 'useNativeJsonEncode' => true,
  53. 'includeLineNumbers' => true,
  54. );
  55. /**
  56. * Message Levels for messages sent via FirePHP
  57. *
  58. * @var array
  59. */
  60. var $_levels = array(
  61. 'log' => 'LOG',
  62. 'info' => 'INFO',
  63. 'warn' => 'WARN',
  64. 'error' => 'ERROR',
  65. 'dump' => 'DUMP',
  66. 'trace' => 'TRACE',
  67. 'exception' => 'EXCEPTION',
  68. 'table' => 'TABLE',
  69. 'groupStart' => 'GROUP_START',
  70. 'groupEnd' => 'GROUP_END',
  71. );
  72. var $_version = '0.2.1';
  73. /**
  74. * internal messageIndex counter
  75. *
  76. * @var int
  77. * @access protected
  78. */
  79. var $_messageIndex = 1;
  80. /**
  81. * stack of objects encoded by stringEncode()
  82. *
  83. * @var array
  84. **/
  85. var $_encodedObjects = array();
  86. /**
  87. * methodIndex to include in tracebacks when using includeLineNumbers
  88. *
  89. * @var array
  90. **/
  91. var $_methodIndex = array('info', 'log', 'warn', 'error', 'table', 'trace');
  92. /**
  93. * FireCake output status
  94. *
  95. * @var bool
  96. **/
  97. var $_enabled = true;
  98. /**
  99. * get Instance of the singleton
  100. *
  101. * @param string $class Class instance to store in the singleton. Used with subclasses and Tests.
  102. * @access public
  103. * @static
  104. * @return void
  105. */
  106. function &getInstance($class = null) {
  107. static $instance = array();
  108. if (!empty($class)) {
  109. if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) {
  110. $instance[0] =& new $class();
  111. $instance[0]->setOptions();
  112. }
  113. }
  114. if (!isset($instance[0]) || !$instance[0]) {
  115. $instance[0] =& new FireCake();
  116. $instance[0]->setOptions();
  117. }
  118. return $instance[0];
  119. }
  120. /**
  121. * setOptions
  122. *
  123. * @param array $options Array of options to set.
  124. * @access public
  125. * @static
  126. * @return void
  127. */
  128. function setOptions($options = array()) {
  129. $_this =& FireCake::getInstance();
  130. if (empty($_this->options)) {
  131. $_this->options = array_merge($_this->_defaultOptions, $options);
  132. } else {
  133. $_this->options = array_merge($_this->options, $options);
  134. }
  135. }
  136. /**
  137. * Return boolean based on presence of FirePHP extension
  138. *
  139. * @access public
  140. * @return boolean
  141. **/
  142. function detectClientExtension() {
  143. $ua = FireCake::getUserAgent();
  144. if (!preg_match('/\sFirePHP\/([\.|\d]*)\s?/si', $ua, $match) || !version_compare($match[1], '0.0.6', '>=')) {
  145. return false;
  146. }
  147. return true;
  148. }
  149. /**
  150. * Get the Current UserAgent
  151. *
  152. * @access public
  153. * @static
  154. * @return string UserAgent string of active client connection
  155. **/
  156. function getUserAgent() {
  157. return env('HTTP_USER_AGENT');
  158. }
  159. /**
  160. * Disable FireCake output
  161. * All subsequent output calls will not be run.
  162. *
  163. * @return void
  164. **/
  165. function disable() {
  166. $_this =& FireCake::getInstance();
  167. $_this->_enabled = false;
  168. }
  169. /**
  170. * Enable FireCake output
  171. *
  172. * @return void
  173. **/
  174. function enable() {
  175. $_this =& FireCake::getInstance();
  176. $_this->_enabled = true;
  177. }
  178. /**
  179. * Convenience wrapper for LOG messages
  180. *
  181. * @param string $message Message to log
  182. * @param string $label Label for message (optional)
  183. * @access public
  184. * @static
  185. * @return void
  186. */
  187. function log($message, $label = null) {
  188. FireCake::fb($message, $label, 'log');
  189. }
  190. /**
  191. * Convenience wrapper for WARN messages
  192. *
  193. * @param string $message Message to log
  194. * @param string $label Label for message (optional)
  195. * @access public
  196. * @static
  197. * @return void
  198. */
  199. function warn($message, $label = null) {
  200. FireCake::fb($message, $label, 'warn');
  201. }
  202. /**
  203. * Convenience wrapper for INFO messages
  204. *
  205. * @param string $message Message to log
  206. * @param string $label Label for message (optional)
  207. * @access public
  208. * @static
  209. * @return void
  210. */
  211. function info($message, $label = null) {
  212. FireCake::fb($message, $label, 'info');
  213. }
  214. /**
  215. * Convenience wrapper for ERROR messages
  216. *
  217. * @param string $message Message to log
  218. * @param string $label Label for message (optional)
  219. * @access public
  220. * @static
  221. * @return void
  222. */
  223. function error($message, $label = null) {
  224. FireCake::fb($message, $label, 'error');
  225. }
  226. /**
  227. * Convenience wrapper for TABLE messages
  228. *
  229. * @param string $message Message to log
  230. * @param string $label Label for message (optional)
  231. * @access public
  232. * @static
  233. * @return void
  234. */
  235. function table($label, $message) {
  236. FireCake::fb($message, $label, 'table');
  237. }
  238. /**
  239. * Convenience wrapper for DUMP messages
  240. *
  241. * @param string $message Message to log
  242. * @param string $label Unique label for message
  243. * @access public
  244. * @static
  245. * @return void
  246. */
  247. function dump($label, $message) {
  248. FireCake::fb($message, $label, 'dump');
  249. }
  250. /**
  251. * Convenience wrapper for TRACE messages
  252. *
  253. * @param string $label Label for message (optional)
  254. * @access public
  255. * @return void
  256. */
  257. function trace($label) {
  258. FireCake::fb($label, 'trace');
  259. }
  260. /**
  261. * Convenience wrapper for GROUP messages
  262. * Messages following the group call will be nested in a group block
  263. *
  264. * @param string $label Label for group (optional)
  265. * @access public
  266. * @return void
  267. */
  268. function group($label) {
  269. FireCake::fb(null, $label, 'groupStart');
  270. }
  271. /**
  272. * Convenience wrapper for GROUPEND messages
  273. * Closes a group block
  274. *
  275. * @param string $label Label for group (optional)
  276. * @access public
  277. * @return void
  278. */
  279. function groupEnd() {
  280. FireCake::fb(null, null, 'groupEnd');
  281. }
  282. /**
  283. * fb - Send messages with FireCake to FirePHP
  284. *
  285. * Much like FirePHP's fb() this method can be called with various parameter counts
  286. * fb($message) - Just send a message defaults to LOG type
  287. * fb($message, $type) - Send a message with a specific type
  288. * fb($message, $label, $type) - Send a message with a custom label and type.
  289. *
  290. * @param mixed $message Message to output. For other parameters see usage above.
  291. * @static
  292. * @return void
  293. **/
  294. function fb($message) {
  295. $_this =& FireCake::getInstance();
  296. if (headers_sent($filename, $linenum)) {
  297. trigger_error(sprintf(__d('debug_kit', 'Headers already sent in %s on line %s. Cannot send log data to FirePHP.'), $filename, $linenum), E_USER_WARNING);
  298. return false;
  299. }
  300. if (!$_this->_enabled || !$_this->detectClientExtension()) {
  301. return false;
  302. }
  303. $args = func_get_args();
  304. $type = $label = null;
  305. switch (count($args)) {
  306. case 1:
  307. $type = $_this->_levels['log'];
  308. break;
  309. case 2:
  310. $type = $args[1];
  311. break;
  312. case 3:
  313. $type = $args[2];
  314. $label = $args[1];
  315. break;
  316. default:
  317. trigger_error(__d('debug_kit', 'Incorrect parameter count for FireCake::fb()'), E_USER_WARNING);
  318. return false;
  319. }
  320. if (isset($_this->_levels[$type])) {
  321. $type = $_this->_levels[$type];
  322. } else {
  323. $type = $_this->_levels['log'];
  324. }
  325. $meta = array();
  326. $skipFinalObjectEncode = false;
  327. if ($type == $_this->_levels['trace']) {
  328. $trace = debug_backtrace();
  329. if (!$trace) {
  330. return false;
  331. }
  332. $message = $_this->_parseTrace($trace, $args[0]);
  333. $skipFinalObjectEncode = true;
  334. }
  335. if ($_this->options['includeLineNumbers']) {
  336. if (!isset($meta['file']) || !isset($meta['line'])) {
  337. $trace = debug_backtrace();
  338. for ($i = 0, $len = count($trace); $i < $len ; $i++) {
  339. $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
  340. $selfCall = ($keySet &&
  341. strtolower($trace[$i]['class']) == 'firecake' &&
  342. in_array($trace[$i]['function'], $_this->_methodIndex)
  343. );
  344. if ($selfCall) {
  345. $meta['File'] = isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '';
  346. $meta['Line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : '';
  347. break;
  348. }
  349. }
  350. }
  351. }
  352. $structureIndex = 1;
  353. if ($type == $_this->_levels['dump']) {
  354. $structureIndex = 2;
  355. $_this->_sendHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
  356. } else {
  357. $_this->_sendHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
  358. }
  359. $_this->_sendHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
  360. $_this->_sendHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'. $_this->_version);
  361. if ($type == $_this->_levels['groupStart']) {
  362. $meta['Collapsed'] = 'true';
  363. }
  364. if ($type == $_this->_levels['dump']) {
  365. $dump = $_this->jsonEncode($message);
  366. $msg = '{"' . $label .'":' . $dump .'}';
  367. } else {
  368. $meta['Type'] = $type;
  369. if ($label !== null) {
  370. $meta['Label'] = $label;
  371. }
  372. $msg = '[' . $_this->jsonEncode($meta) . ',' . $_this->jsonEncode($message, $skipFinalObjectEncode).']';
  373. }
  374. $lines = explode("\n", chunk_split($msg, 5000, "\n"));
  375. foreach ($lines as $i => $line) {
  376. if (empty($line)) {
  377. continue;
  378. }
  379. $header = 'X-Wf-1-' . $structureIndex . '-1-' . $_this->_messageIndex;
  380. if (count($lines) > 2) {
  381. $first = ($i == 0) ? strlen($msg) : '';
  382. $end = ($i < count($lines) - 2) ? '\\' : '';
  383. $message = $first . '|' . $line . '|' . $end;
  384. $_this->_sendHeader($header, $message);
  385. } else {
  386. $_this->_sendHeader($header, strlen($line) . '|' . $line . '|');
  387. }
  388. $_this->_messageIndex++;
  389. if ($_this->_messageIndex > 99999) {
  390. trigger_error(__d('debug_kit', 'Maximum number (99,999) of messages reached!'), E_USER_WARNING);
  391. }
  392. }
  393. $_this->_sendHeader('X-Wf-1-Index', $_this->_messageIndex - 1);
  394. return true;
  395. }
  396. /**
  397. * Parse a debug backtrace
  398. *
  399. * @param array $trace Debug backtrace output
  400. * @access protected
  401. * @return array
  402. **/
  403. function _parseTrace($trace, $messageName) {
  404. $message = array();
  405. for ($i = 0, $len = count($trace); $i < $len ; $i++) {
  406. $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
  407. $selfCall = ($keySet && $trace[$i]['class'] == 'FireCake');
  408. if (!$selfCall) {
  409. $message = array(
  410. 'Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '',
  411. 'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '',
  412. 'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '',
  413. 'Message' => $messageName,
  414. 'File' => isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '',
  415. 'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '',
  416. 'Args' => isset($trace[$i]['args']) ? $this->stringEncode($trace[$i]['args']) : '',
  417. 'Trace' => $this->_escapeTrace(array_splice($trace, $i + 1))
  418. );
  419. break;
  420. }
  421. }
  422. return $message;
  423. }
  424. /**
  425. * Fix a trace for use in output
  426. *
  427. * @param mixed $trace Trace to fix
  428. * @access protected
  429. * @static
  430. * @return string
  431. **/
  432. function _escapeTrace($trace) {
  433. for ($i = 0, $len = count($trace); $i < $len; $i++) {
  434. if (isset($trace[$i]['file'])) {
  435. $trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']);
  436. }
  437. if (isset($trace[$i]['args'])) {
  438. $trace[$i]['args'] = $this->stringEncode($trace[$i]['args']);
  439. }
  440. }
  441. return $trace;
  442. }
  443. /**
  444. * Encode non string objects to string.
  445. * Filter out recursion, so no errors are raised by json_encode or $javascript->object()
  446. *
  447. * @param mixed $object Object or variable to encode to string.
  448. * @param int $objectDepth Current Depth in object chains.
  449. * @param int $arrayDepth Current Depth in array chains.
  450. * @static
  451. * @return void
  452. **/
  453. function stringEncode($object, $objectDepth = 1, $arrayDepth = 1) {
  454. $_this =& FireCake::getInstance();
  455. $return = array();
  456. if (is_resource($object)) {
  457. return '** ' . (string)$object . '**';
  458. }
  459. if (is_object($object)) {
  460. if ($objectDepth == $_this->options['maxObjectDepth']) {
  461. return '** Max Object Depth (' . $_this->options['maxObjectDepth'] . ') **';
  462. }
  463. foreach ($_this->_encodedObjects as $encoded) {
  464. if ($encoded === $object) {
  465. return '** Recursion (' . get_class($object) . ') **';
  466. }
  467. }
  468. $_this->_encodedObjects[] =& $object;
  469. $return['__className'] = $class = get_class($object);
  470. $properties = (array)$object;
  471. foreach ($properties as $name => $property) {
  472. $return[$name] = FireCake::stringEncode($property, 1, $objectDepth + 1);
  473. }
  474. array_pop($_this->_encodedObjects);
  475. }
  476. if (is_array($object)) {
  477. if ($arrayDepth == $_this->options['maxArrayDepth']) {
  478. return '** Max Array Depth ('. $_this->options['maxArrayDepth'] . ') **';
  479. }
  480. foreach ($object as $key => $value) {
  481. $return[$key] = FireCake::stringEncode($value, 1, $arrayDepth + 1);
  482. }
  483. }
  484. if (is_string($object) || is_numeric($object) || is_bool($object) || is_null($object)) {
  485. return $object;
  486. }
  487. return $return;
  488. }
  489. /**
  490. * Encode an object into JSON
  491. *
  492. * @param mixed $object Object or array to json encode
  493. * @param boolean $doIt
  494. * @access public
  495. * @static
  496. * @return string
  497. **/
  498. function jsonEncode($object, $skipEncode = false) {
  499. $_this =& FireCake::getInstance();
  500. if (!$skipEncode) {
  501. $object = FireCake::stringEncode($object);
  502. }
  503. if (function_exists('json_encode') && $_this->options['useNativeJsonEncode']) {
  504. return json_encode($object);
  505. } else {
  506. return FireCake::_jsonEncode($object);
  507. }
  508. }
  509. /**
  510. * jsonEncode Helper method for PHP4 compatibility
  511. *
  512. * @param mixed $object Something to encode
  513. * @access protected
  514. * @static
  515. * @return string
  516. **/
  517. function _jsonEncode($object) {
  518. if (!class_exists('JavascriptHelper')) {
  519. App::import('Helper', 'Javascript');
  520. }
  521. $javascript =& new JavascriptHelper();
  522. $javascript->useNative = false;
  523. if (is_string($object)) {
  524. return '"' . $javascript->escapeString($object) . '"';
  525. }
  526. return $javascript->object($object);
  527. }
  528. /**
  529. * Send Headers - write headers.
  530. *
  531. * @access protected
  532. * @return void
  533. **/
  534. function _sendHeader($name, $value) {
  535. header($name . ': ' . $value);
  536. }
  537. }