You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
20 KiB

7 years ago
  1. <?php
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP
  6. *
  7. * This content is released under the MIT License (MIT)
  8. *
  9. * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a copy
  12. * of this software and associated documentation files (the "Software"), to deal
  13. * in the Software without restriction, including without limitation the rights
  14. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15. * copies of the Software, and to permit persons to whom the Software is
  16. * furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included in
  19. * all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27. * THE SOFTWARE.
  28. *
  29. * @package CodeIgniter
  30. * @author EllisLab Dev Team
  31. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
  32. * @copyright Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
  33. * @license http://opensource.org/licenses/MIT MIT License
  34. * @link https://codeigniter.com
  35. * @since Version 1.0.0
  36. * @filesource
  37. */
  38. defined('BASEPATH') OR exit('No direct script access allowed');
  39. /**
  40. * CodeIgniter Profiler Class
  41. *
  42. * This class enables you to display benchmark, query, and other data
  43. * in order to help with debugging and optimization.
  44. *
  45. * Note: At some point it would be good to move all the HTML in this class
  46. * into a set of template files in order to allow customization.
  47. *
  48. * @package CodeIgniter
  49. * @subpackage Libraries
  50. * @category Libraries
  51. * @author EllisLab Dev Team
  52. * @link https://codeigniter.com/user_guide/general/profiling.html
  53. */
  54. class CI_Profiler {
  55. /**
  56. * List of profiler sections available to show
  57. *
  58. * @var array
  59. */
  60. protected $_available_sections = array(
  61. 'benchmarks',
  62. 'get',
  63. 'memory_usage',
  64. 'post',
  65. 'uri_string',
  66. 'controller_info',
  67. 'queries',
  68. 'http_headers',
  69. 'session_data',
  70. 'config'
  71. );
  72. /**
  73. * Number of queries to show before making the additional queries togglable
  74. *
  75. * @var int
  76. */
  77. protected $_query_toggle_count = 25;
  78. /**
  79. * Reference to the CodeIgniter singleton
  80. *
  81. * @var object
  82. */
  83. protected $CI;
  84. // --------------------------------------------------------------------
  85. /**
  86. * Class constructor
  87. *
  88. * Initialize Profiler
  89. *
  90. * @param array $config Parameters
  91. */
  92. public function __construct($config = array())
  93. {
  94. $this->CI =& get_instance();
  95. $this->CI->load->language('profiler');
  96. // default all sections to display
  97. foreach ($this->_available_sections as $section)
  98. {
  99. if ( ! isset($config[$section]))
  100. {
  101. $this->_compile_{$section} = TRUE;
  102. }
  103. }
  104. $this->set_sections($config);
  105. log_message('info', 'Profiler Class Initialized');
  106. }
  107. // --------------------------------------------------------------------
  108. /**
  109. * Set Sections
  110. *
  111. * Sets the private _compile_* properties to enable/disable Profiler sections
  112. *
  113. * @param mixed $config
  114. * @return void
  115. */
  116. public function set_sections($config)
  117. {
  118. if (isset($config['query_toggle_count']))
  119. {
  120. $this->_query_toggle_count = (int) $config['query_toggle_count'];
  121. unset($config['query_toggle_count']);
  122. }
  123. foreach ($config as $method => $enable)
  124. {
  125. if (in_array($method, $this->_available_sections))
  126. {
  127. $this->_compile_{$method} = ($enable !== FALSE);
  128. }
  129. }
  130. }
  131. // --------------------------------------------------------------------
  132. /**
  133. * Auto Profiler
  134. *
  135. * This function cycles through the entire array of mark points and
  136. * matches any two points that are named identically (ending in "_start"
  137. * and "_end" respectively). It then compiles the execution times for
  138. * all points and returns it as an array
  139. *
  140. * @return array
  141. */
  142. protected function _compile_benchmarks()
  143. {
  144. $profile = array();
  145. foreach ($this->CI->benchmark->marker as $key => $val)
  146. {
  147. // We match the "end" marker so that the list ends
  148. // up in the order that it was defined
  149. if (preg_match('/(.+?)_end$/i', $key, $match)
  150. && isset($this->CI->benchmark->marker[$match[1].'_end'], $this->CI->benchmark->marker[$match[1].'_start']))
  151. {
  152. $profile[$match[1]] = $this->CI->benchmark->elapsed_time($match[1].'_start', $key);
  153. }
  154. }
  155. // Build a table containing the profile data.
  156. // Note: At some point we should turn this into a template that can
  157. // be modified. We also might want to make this data available to be logged
  158. $output = "\n\n"
  159. .'<fieldset id="ci_profiler_benchmarks" style="border:1px solid #900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  160. ."\n"
  161. .'<legend style="color:#900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_benchmarks')."&nbsp;&nbsp;</legend>"
  162. ."\n\n\n<table style=\"width:100%;\">\n";
  163. foreach ($profile as $key => $val)
  164. {
  165. $key = ucwords(str_replace(array('_', '-'), ' ', $key));
  166. $output .= '<tr><td style="padding:5px;width:50%;color:#000;font-weight:bold;background-color:#ddd;">'
  167. .$key.'&nbsp;&nbsp;</td><td style="padding:5px;width:50%;color:#900;font-weight:normal;background-color:#ddd;">'
  168. .$val."</td></tr>\n";
  169. }
  170. return $output."</table>\n</fieldset>";
  171. }
  172. // --------------------------------------------------------------------
  173. /**
  174. * Compile Queries
  175. *
  176. * @return string
  177. */
  178. protected function _compile_queries()
  179. {
  180. $dbs = array();
  181. // Let's determine which databases are currently connected to
  182. foreach (get_object_vars($this->CI) as $name => $cobject)
  183. {
  184. if (is_object($cobject))
  185. {
  186. if ($cobject instanceof CI_DB)
  187. {
  188. $dbs[get_class($this->CI).':$'.$name] = $cobject;
  189. }
  190. elseif ($cobject instanceof CI_Model)
  191. {
  192. foreach (get_object_vars($cobject) as $mname => $mobject)
  193. {
  194. if ($mobject instanceof CI_DB)
  195. {
  196. $dbs[get_class($cobject).':$'.$mname] = $mobject;
  197. }
  198. }
  199. }
  200. }
  201. }
  202. if (count($dbs) === 0)
  203. {
  204. return "\n\n"
  205. .'<fieldset id="ci_profiler_queries" style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  206. ."\n"
  207. .'<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries').'&nbsp;&nbsp;</legend>'
  208. ."\n\n\n<table style=\"border:none; width:100%;\">\n"
  209. .'<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
  210. .$this->CI->lang->line('profiler_no_db')
  211. ."</td></tr>\n</table>\n</fieldset>";
  212. }
  213. // Load the text helper so we can highlight the SQL
  214. $this->CI->load->helper('text');
  215. // Key words we want bolded
  216. $highlight = array('SELECT', 'DISTINCT', 'FROM', 'WHERE', 'AND', 'LEFT&nbsp;JOIN', 'ORDER&nbsp;BY', 'GROUP&nbsp;BY', 'LIMIT', 'INSERT', 'INTO', 'VALUES', 'UPDATE', 'OR&nbsp;', 'HAVING', 'OFFSET', 'NOT&nbsp;IN', 'IN', 'LIKE', 'NOT&nbsp;LIKE', 'COUNT', 'MAX', 'MIN', 'ON', 'AS', 'AVG', 'SUM', '(', ')');
  217. $output = "\n\n";
  218. $count = 0;
  219. foreach ($dbs as $name => $db)
  220. {
  221. $hide_queries = (count($db->queries) > $this->_query_toggle_count) ? ' display:none' : '';
  222. $total_time = number_format(array_sum($db->query_times), 4).' '.$this->CI->lang->line('profiler_seconds');
  223. $show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_hide').'\'?\''.$this->CI->lang->line('profiler_section_show').'\':\''.$this->CI->lang->line('profiler_section_hide').'\';">'.$this->CI->lang->line('profiler_section_hide').'</span>)';
  224. if ($hide_queries !== '')
  225. {
  226. $show_hide_js = '(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_queries_db_'.$count.'\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)';
  227. }
  228. $output .= '<fieldset style="border:1px solid #0000FF;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  229. ."\n"
  230. .'<legend style="color:#0000FF;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_database')
  231. .':&nbsp; '.$db->database.' ('.$name.')&nbsp;&nbsp;&nbsp;'.$this->CI->lang->line('profiler_queries')
  232. .': '.count($db->queries).' ('.$total_time.')&nbsp;&nbsp;'.$show_hide_js."</legend>\n\n\n"
  233. .'<table style="width:100%;'.$hide_queries.'" id="ci_profiler_queries_db_'.$count."\">\n";
  234. if (count($db->queries) === 0)
  235. {
  236. $output .= '<tr><td style="width:100%;color:#0000FF;font-weight:normal;background-color:#eee;padding:5px;">'
  237. .$this->CI->lang->line('profiler_no_queries')."</td></tr>\n";
  238. }
  239. else
  240. {
  241. foreach ($db->queries as $key => $val)
  242. {
  243. $time = number_format($db->query_times[$key], 4);
  244. $val = highlight_code($val);
  245. foreach ($highlight as $bold)
  246. {
  247. $val = str_replace($bold, '<strong>'.$bold.'</strong>', $val);
  248. }
  249. $output .= '<tr><td style="padding:5px;vertical-align:top;width:1%;color:#900;font-weight:normal;background-color:#ddd;">'
  250. .$time.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;font-weight:normal;background-color:#ddd;">'
  251. .$val."</td></tr>\n";
  252. }
  253. }
  254. $output .= "</table>\n</fieldset>";
  255. $count++;
  256. }
  257. return $output;
  258. }
  259. // --------------------------------------------------------------------
  260. /**
  261. * Compile $_GET Data
  262. *
  263. * @return string
  264. */
  265. protected function _compile_get()
  266. {
  267. $output = "\n\n"
  268. .'<fieldset id="ci_profiler_get" style="border:1px solid #cd6e00;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  269. ."\n"
  270. .'<legend style="color:#cd6e00;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_get_data')."&nbsp;&nbsp;</legend>\n";
  271. if (count($_GET) === 0)
  272. {
  273. $output .= '<div style="color:#cd6e00;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_get').'</div>';
  274. }
  275. else
  276. {
  277. $output .= "\n\n<table style=\"width:100%;border:none;\">\n";
  278. foreach ($_GET as $key => $val)
  279. {
  280. is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
  281. $val = (is_array($val) OR is_object($val))
  282. ? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
  283. : htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
  284. $output .= '<tr><td style="width:50%;color:#000;background-color:#ddd;padding:5px;">&#36;_GET['
  285. .$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#cd6e00;font-weight:normal;background-color:#ddd;">'
  286. .$val."</td></tr>\n";
  287. }
  288. $output .= "</table>\n";
  289. }
  290. return $output.'</fieldset>';
  291. }
  292. // --------------------------------------------------------------------
  293. /**
  294. * Compile $_POST Data
  295. *
  296. * @return string
  297. */
  298. protected function _compile_post()
  299. {
  300. $output = "\n\n"
  301. .'<fieldset id="ci_profiler_post" style="border:1px solid #009900;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  302. ."\n"
  303. .'<legend style="color:#009900;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_post_data')."&nbsp;&nbsp;</legend>\n";
  304. if (count($_POST) === 0 && count($_FILES) === 0)
  305. {
  306. $output .= '<div style="color:#009900;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->lang->line('profiler_no_post').'</div>';
  307. }
  308. else
  309. {
  310. $output .= "\n\n<table style=\"width:100%;\">\n";
  311. foreach ($_POST as $key => $val)
  312. {
  313. is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
  314. $val = (is_array($val) OR is_object($val))
  315. ? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
  316. : htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
  317. $output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">&#36;_POST['
  318. .$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'
  319. .$val."</td></tr>\n";
  320. }
  321. foreach ($_FILES as $key => $val)
  322. {
  323. is_int($key) OR $key = "'".htmlspecialchars($key, ENT_QUOTES, config_item('charset'))."'";
  324. $val = (is_array($val) OR is_object($val))
  325. ? '<pre>'.htmlspecialchars(print_r($val, TRUE), ENT_QUOTES, config_item('charset')).'</pre>'
  326. : htmlspecialchars($val, ENT_QUOTES, config_item('charset'));
  327. $output .= '<tr><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">&#36;_FILES['
  328. .$key.']&nbsp;&nbsp; </td><td style="width:50%;padding:5px;color:#009900;font-weight:normal;background-color:#ddd;">'
  329. .$val."</td></tr>\n";
  330. }
  331. $output .= "</table>\n";
  332. }
  333. return $output.'</fieldset>';
  334. }
  335. // --------------------------------------------------------------------
  336. /**
  337. * Show query string
  338. *
  339. * @return string
  340. */
  341. protected function _compile_uri_string()
  342. {
  343. return "\n\n"
  344. .'<fieldset id="ci_profiler_uri_string" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  345. ."\n"
  346. .'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_uri_string')."&nbsp;&nbsp;</legend>\n"
  347. .'<div style="color:#000;font-weight:normal;padding:4px 0 4px 0;">'
  348. .($this->CI->uri->uri_string === '' ? $this->CI->lang->line('profiler_no_uri') : $this->CI->uri->uri_string)
  349. .'</div></fieldset>';
  350. }
  351. // --------------------------------------------------------------------
  352. /**
  353. * Show the controller and function that were called
  354. *
  355. * @return string
  356. */
  357. protected function _compile_controller_info()
  358. {
  359. return "\n\n"
  360. .'<fieldset id="ci_profiler_controller_info" style="border:1px solid #995300;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  361. ."\n"
  362. .'<legend style="color:#995300;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_controller_info')."&nbsp;&nbsp;</legend>\n"
  363. .'<div style="color:#995300;font-weight:normal;padding:4px 0 4px 0;">'.$this->CI->router->class.'/'.$this->CI->router->method
  364. .'</div></fieldset>';
  365. }
  366. // --------------------------------------------------------------------
  367. /**
  368. * Compile memory usage
  369. *
  370. * Display total used memory
  371. *
  372. * @return string
  373. */
  374. protected function _compile_memory_usage()
  375. {
  376. return "\n\n"
  377. .'<fieldset id="ci_profiler_memory_usage" style="border:1px solid #5a0099;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  378. ."\n"
  379. .'<legend style="color:#5a0099;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_memory_usage')."&nbsp;&nbsp;</legend>\n"
  380. .'<div style="color:#5a0099;font-weight:normal;padding:4px 0 4px 0;">'
  381. .(($usage = memory_get_usage()) != '' ? number_format($usage).' bytes' : $this->CI->lang->line('profiler_no_memory'))
  382. .'</div></fieldset>';
  383. }
  384. // --------------------------------------------------------------------
  385. /**
  386. * Compile header information
  387. *
  388. * Lists HTTP headers
  389. *
  390. * @return string
  391. */
  392. protected function _compile_http_headers()
  393. {
  394. $output = "\n\n"
  395. .'<fieldset id="ci_profiler_http_headers" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  396. ."\n"
  397. .'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_headers')
  398. .'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_httpheaders_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
  399. .'<table style="width:100%;display:none;" id="ci_profiler_httpheaders_table">'."\n";
  400. foreach (array('HTTP_ACCEPT', 'HTTP_USER_AGENT', 'HTTP_CONNECTION', 'SERVER_PORT', 'SERVER_NAME', 'REMOTE_ADDR', 'SERVER_SOFTWARE', 'HTTP_ACCEPT_LANGUAGE', 'SCRIPT_NAME', 'REQUEST_METHOD',' HTTP_HOST', 'REMOTE_HOST', 'CONTENT_TYPE', 'SERVER_PROTOCOL', 'QUERY_STRING', 'HTTP_ACCEPT_ENCODING', 'HTTP_X_FORWARDED_FOR', 'HTTP_DNT') as $header)
  401. {
  402. $val = isset($_SERVER[$header]) ? htmlspecialchars($_SERVER[$header], ENT_QUOTES, config_item('charset')) : '';
  403. $output .= '<tr><td style="vertical-align:top;width:50%;padding:5px;color:#900;background-color:#ddd;">'
  404. .$header.'&nbsp;&nbsp;</td><td style="width:50%;padding:5px;color:#000;background-color:#ddd;">'.$val."</td></tr>\n";
  405. }
  406. return $output."</table>\n</fieldset>";
  407. }
  408. // --------------------------------------------------------------------
  409. /**
  410. * Compile config information
  411. *
  412. * Lists developer config variables
  413. *
  414. * @return string
  415. */
  416. protected function _compile_config()
  417. {
  418. $output = "\n\n"
  419. .'<fieldset id="ci_profiler_config" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  420. ."\n"
  421. .'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_config').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_config_table\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show')."</span>)</legend>\n\n\n"
  422. .'<table style="width:100%;display:none;" id="ci_profiler_config_table">'."\n";
  423. foreach ($this->CI->config->config as $config => $val)
  424. {
  425. if (is_array($val) OR is_object($val))
  426. {
  427. $val = print_r($val, TRUE);
  428. }
  429. $output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
  430. .$config.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;background-color:#ddd;">'.htmlspecialchars($val, ENT_QUOTES, config_item('charset'))."</td></tr>\n";
  431. }
  432. return $output."</table>\n</fieldset>";
  433. }
  434. // --------------------------------------------------------------------
  435. /**
  436. * Compile session userdata
  437. *
  438. * @return string
  439. */
  440. protected function _compile_session_data()
  441. {
  442. if ( ! isset($this->CI->session))
  443. {
  444. return;
  445. }
  446. $output = '<fieldset id="ci_profiler_csession" style="border:1px solid #000;padding:6px 10px 10px 10px;margin:20px 0 20px 0;background-color:#eee;">'
  447. .'<legend style="color:#000;">&nbsp;&nbsp;'.$this->CI->lang->line('profiler_session_data').'&nbsp;&nbsp;(<span style="cursor: pointer;" onclick="var s=document.getElementById(\'ci_profiler_session_data\').style;s.display=s.display==\'none\'?\'\':\'none\';this.innerHTML=this.innerHTML==\''.$this->CI->lang->line('profiler_section_show').'\'?\''.$this->CI->lang->line('profiler_section_hide').'\':\''.$this->CI->lang->line('profiler_section_show').'\';">'.$this->CI->lang->line('profiler_section_show').'</span>)</legend>'
  448. .'<table style="width:100%;display:none;" id="ci_profiler_session_data">';
  449. foreach ($this->CI->session->userdata() as $key => $val)
  450. {
  451. if (is_array($val) OR is_object($val))
  452. {
  453. $val = print_r($val, TRUE);
  454. }
  455. $output .= '<tr><td style="padding:5px;vertical-align:top;color:#900;background-color:#ddd;">'
  456. .$key.'&nbsp;&nbsp;</td><td style="padding:5px;color:#000;background-color:#ddd;">'.htmlspecialchars($val, ENT_QUOTES, config_item('charset'))."</td></tr>\n";
  457. }
  458. return $output."</table>\n</fieldset>";
  459. }
  460. // --------------------------------------------------------------------
  461. /**
  462. * Run the Profiler
  463. *
  464. * @return string
  465. */
  466. public function run()
  467. {
  468. $output = '<div id="codeigniter_profiler" style="clear:both;background-color:#fff;padding:10px;">';
  469. $fields_displayed = 0;
  470. foreach ($this->_available_sections as $section)
  471. {
  472. if ($this->_compile_{$section} !== FALSE)
  473. {
  474. $func = '_compile_'.$section;
  475. $output .= $this->{$func}();
  476. $fields_displayed++;
  477. }
  478. }
  479. if ($fields_displayed === 0)
  480. {
  481. $output .= '<p style="border:1px solid #5a0099;padding:10px;margin:20px 0;background-color:#eee;">'
  482. .$this->CI->lang->line('profiler_no_profiles').'</p>';
  483. }
  484. return $output.'</div>';
  485. }
  486. }