PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/server/app/Plugin/DebugKit/Lib/FireCake.php

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