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

/system/core/Output.php

https://gitlab.com/sittipongwork/impro_dashboard
PHP | 575 lines | 245 code | 90 blank | 240 comment | 41 complexity | a0da9187c19fc0cb0cc4f07a79c47dbe MD5 | raw file
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * CodeIgniter
  4. *
  5. * An open source application development framework for PHP 5.1.6 or newer
  6. *
  7. * @package CodeIgniter
  8. * @author EllisLab Dev Team
  9. * @copyright Copyright (c) 2008 - 2014, EllisLab, Inc.
  10. * @copyright Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
  11. * @license http://codeigniter.com/user_guide/license.html
  12. * @link http://codeigniter.com
  13. * @since Version 1.0
  14. * @filesource
  15. */
  16. // ------------------------------------------------------------------------
  17. /**
  18. * Output Class
  19. *
  20. * Responsible for sending final output to browser
  21. *
  22. * @package CodeIgniter
  23. * @subpackage Libraries
  24. * @category Output
  25. * @author EllisLab Dev Team
  26. * @link http://codeigniter.com/user_guide/libraries/output.html
  27. */
  28. class CI_Output {
  29. /**
  30. * Current output string
  31. *
  32. * @var string
  33. * @access protected
  34. */
  35. protected $final_output;
  36. /**
  37. * Cache expiration time
  38. *
  39. * @var int
  40. * @access protected
  41. */
  42. protected $cache_expiration = 0;
  43. /**
  44. * List of server headers
  45. *
  46. * @var array
  47. * @access protected
  48. */
  49. protected $headers = array();
  50. /**
  51. * List of mime types
  52. *
  53. * @var array
  54. * @access protected
  55. */
  56. protected $mime_types = array();
  57. /**
  58. * Determines wether profiler is enabled
  59. *
  60. * @var book
  61. * @access protected
  62. */
  63. protected $enable_profiler = FALSE;
  64. /**
  65. * Determines if output compression is enabled
  66. *
  67. * @var bool
  68. * @access protected
  69. */
  70. protected $_zlib_oc = FALSE;
  71. /**
  72. * List of profiler sections
  73. *
  74. * @var array
  75. * @access protected
  76. */
  77. protected $_profiler_sections = array();
  78. /**
  79. * Whether or not to parse variables like {elapsed_time} and {memory_usage}
  80. *
  81. * @var bool
  82. * @access protected
  83. */
  84. protected $parse_exec_vars = TRUE;
  85. /**
  86. * Constructor
  87. *
  88. */
  89. function __construct()
  90. {
  91. $this->_zlib_oc = @ini_get('zlib.output_compression');
  92. // Get mime types for later
  93. if (defined('ENVIRONMENT') AND file_exists(APPPATH.'config/'.ENVIRONMENT.'/mimes.php'))
  94. {
  95. include APPPATH.'config/'.ENVIRONMENT.'/mimes.php';
  96. }
  97. else
  98. {
  99. include APPPATH.'config/mimes.php';
  100. }
  101. $this->mime_types = $mimes;
  102. log_message('debug', "Output Class Initialized");
  103. }
  104. // --------------------------------------------------------------------
  105. /**
  106. * Get Output
  107. *
  108. * Returns the current output string
  109. *
  110. * @access public
  111. * @return string
  112. */
  113. function get_output()
  114. {
  115. return $this->final_output;
  116. }
  117. // --------------------------------------------------------------------
  118. /**
  119. * Set Output
  120. *
  121. * Sets the output string
  122. *
  123. * @access public
  124. * @param string
  125. * @return void
  126. */
  127. function set_output($output)
  128. {
  129. $this->final_output = $output;
  130. return $this;
  131. }
  132. // --------------------------------------------------------------------
  133. /**
  134. * Append Output
  135. *
  136. * Appends data onto the output string
  137. *
  138. * @access public
  139. * @param string
  140. * @return void
  141. */
  142. function append_output($output)
  143. {
  144. if ($this->final_output == '')
  145. {
  146. $this->final_output = $output;
  147. }
  148. else
  149. {
  150. $this->final_output .= $output;
  151. }
  152. return $this;
  153. }
  154. // --------------------------------------------------------------------
  155. /**
  156. * Set Header
  157. *
  158. * Lets you set a server header which will be outputted with the final display.
  159. *
  160. * Note: If a file is cached, headers will not be sent. We need to figure out
  161. * how to permit header data to be saved with the cache data...
  162. *
  163. * @access public
  164. * @param string
  165. * @param bool
  166. * @return void
  167. */
  168. function set_header($header, $replace = TRUE)
  169. {
  170. // If zlib.output_compression is enabled it will compress the output,
  171. // but it will not modify the content-length header to compensate for
  172. // the reduction, causing the browser to hang waiting for more data.
  173. // We'll just skip content-length in those cases.
  174. if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) == 0)
  175. {
  176. return;
  177. }
  178. $this->headers[] = array($header, $replace);
  179. return $this;
  180. }
  181. // --------------------------------------------------------------------
  182. /**
  183. * Set Content Type Header
  184. *
  185. * @access public
  186. * @param string extension of the file we're outputting
  187. * @return void
  188. */
  189. function set_content_type($mime_type)
  190. {
  191. if (strpos($mime_type, '/') === FALSE)
  192. {
  193. $extension = ltrim($mime_type, '.');
  194. // Is this extension supported?
  195. if (isset($this->mime_types[$extension]))
  196. {
  197. $mime_type =& $this->mime_types[$extension];
  198. if (is_array($mime_type))
  199. {
  200. $mime_type = current($mime_type);
  201. }
  202. }
  203. }
  204. $header = 'Content-Type: '.$mime_type;
  205. $this->headers[] = array($header, TRUE);
  206. return $this;
  207. }
  208. // --------------------------------------------------------------------
  209. /**
  210. * Set HTTP Status Header
  211. * moved to Common procedural functions in 1.7.2
  212. *
  213. * @access public
  214. * @param int the status code
  215. * @param string
  216. * @return void
  217. */
  218. function set_status_header($code = 200, $text = '')
  219. {
  220. set_status_header($code, $text);
  221. return $this;
  222. }
  223. // --------------------------------------------------------------------
  224. /**
  225. * Enable/disable Profiler
  226. *
  227. * @access public
  228. * @param bool
  229. * @return void
  230. */
  231. function enable_profiler($val = TRUE)
  232. {
  233. $this->enable_profiler = (is_bool($val)) ? $val : TRUE;
  234. return $this;
  235. }
  236. // --------------------------------------------------------------------
  237. /**
  238. * Set Profiler Sections
  239. *
  240. * Allows override of default / config settings for Profiler section display
  241. *
  242. * @access public
  243. * @param array
  244. * @return void
  245. */
  246. function set_profiler_sections($sections)
  247. {
  248. foreach ($sections as $section => $enable)
  249. {
  250. $this->_profiler_sections[$section] = ($enable !== FALSE) ? TRUE : FALSE;
  251. }
  252. return $this;
  253. }
  254. // --------------------------------------------------------------------
  255. /**
  256. * Set Cache
  257. *
  258. * @access public
  259. * @param integer
  260. * @return void
  261. */
  262. function cache($time)
  263. {
  264. $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time;
  265. return $this;
  266. }
  267. // --------------------------------------------------------------------
  268. /**
  269. * Display Output
  270. *
  271. * All "view" data is automatically put into this variable by the controller class:
  272. *
  273. * $this->final_output
  274. *
  275. * This function sends the finalized output data to the browser along
  276. * with any server headers and profile data. It also stops the
  277. * benchmark timer so the page rendering speed and memory usage can be shown.
  278. *
  279. * @access public
  280. * @param string
  281. * @return mixed
  282. */
  283. function _display($output = '')
  284. {
  285. // Note: We use globals because we can't use $CI =& get_instance()
  286. // since this function is sometimes called by the caching mechanism,
  287. // which happens before the CI super object is available.
  288. global $BM, $CFG;
  289. // Grab the super object if we can.
  290. if (class_exists('CI_Controller'))
  291. {
  292. $CI =& get_instance();
  293. }
  294. // --------------------------------------------------------------------
  295. // Set the output data
  296. if ($output == '')
  297. {
  298. $output =& $this->final_output;
  299. }
  300. // --------------------------------------------------------------------
  301. // Do we need to write a cache file? Only if the controller does not have its
  302. // own _output() method and we are not dealing with a cache file, which we
  303. // can determine by the existence of the $CI object above
  304. if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
  305. {
  306. $this->_write_cache($output);
  307. }
  308. // --------------------------------------------------------------------
  309. // Parse out the elapsed time and memory usage,
  310. // then swap the pseudo-variables with the data
  311. $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
  312. if ($this->parse_exec_vars === TRUE)
  313. {
  314. $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
  315. $output = str_replace('{elapsed_time}', $elapsed, $output);
  316. $output = str_replace('{memory_usage}', $memory, $output);
  317. }
  318. // --------------------------------------------------------------------
  319. // Is compression requested?
  320. if ($CFG->item('compress_output') === TRUE && $this->_zlib_oc == FALSE)
  321. {
  322. if (extension_loaded('zlib'))
  323. {
  324. if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
  325. {
  326. ob_start('ob_gzhandler');
  327. }
  328. }
  329. }
  330. // --------------------------------------------------------------------
  331. // Are there any server headers to send?
  332. if (count($this->headers) > 0)
  333. {
  334. foreach ($this->headers as $header)
  335. {
  336. @header($header[0], $header[1]);
  337. }
  338. }
  339. // --------------------------------------------------------------------
  340. // Does the $CI object exist?
  341. // If not we know we are dealing with a cache file so we'll
  342. // simply echo out the data and exit.
  343. if ( ! isset($CI))
  344. {
  345. echo $output;
  346. log_message('debug', "Final output sent to browser");
  347. log_message('debug', "Total execution time: ".$elapsed);
  348. return TRUE;
  349. }
  350. // --------------------------------------------------------------------
  351. // Do we need to generate profile data?
  352. // If so, load the Profile class and run it.
  353. if ($this->enable_profiler == TRUE)
  354. {
  355. $CI->load->library('profiler');
  356. if ( ! empty($this->_profiler_sections))
  357. {
  358. $CI->profiler->set_sections($this->_profiler_sections);
  359. }
  360. // If the output data contains closing </body> and </html> tags
  361. // we will remove them and add them back after we insert the profile data
  362. if (preg_match("|</body>.*?</html>|is", $output))
  363. {
  364. $output = preg_replace("|</body>.*?</html>|is", '', $output);
  365. $output .= $CI->profiler->run();
  366. $output .= '</body></html>';
  367. }
  368. else
  369. {
  370. $output .= $CI->profiler->run();
  371. }
  372. }
  373. // --------------------------------------------------------------------
  374. // Does the controller contain a function named _output()?
  375. // If so send the output there. Otherwise, echo it.
  376. if (method_exists($CI, '_output'))
  377. {
  378. $CI->_output($output);
  379. }
  380. else
  381. {
  382. echo $output; // Send it to the browser!
  383. }
  384. log_message('debug', "Final output sent to browser");
  385. log_message('debug', "Total execution time: ".$elapsed);
  386. }
  387. // --------------------------------------------------------------------
  388. /**
  389. * Write a Cache File
  390. *
  391. * @access public
  392. * @param string
  393. * @return void
  394. */
  395. function _write_cache($output)
  396. {
  397. $CI =& get_instance();
  398. $path = $CI->config->item('cache_path');
  399. $cache_path = ($path == '') ? APPPATH.'cache/' : $path;
  400. if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
  401. {
  402. log_message('error', "Unable to write cache file: ".$cache_path);
  403. return;
  404. }
  405. $uri = $CI->config->item('base_url').
  406. $CI->config->item('index_page').
  407. $CI->uri->uri_string();
  408. $cache_path .= md5($uri);
  409. if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))
  410. {
  411. log_message('error', "Unable to write cache file: ".$cache_path);
  412. return;
  413. }
  414. $expire = time() + ($this->cache_expiration * 60);
  415. if (flock($fp, LOCK_EX))
  416. {
  417. fwrite($fp, $expire.'TS--->'.$output);
  418. flock($fp, LOCK_UN);
  419. }
  420. else
  421. {
  422. log_message('error', "Unable to secure a file lock for file at: ".$cache_path);
  423. return;
  424. }
  425. fclose($fp);
  426. @chmod($cache_path, FILE_WRITE_MODE);
  427. log_message('debug', "Cache file written: ".$cache_path);
  428. }
  429. // --------------------------------------------------------------------
  430. /**
  431. * Update/serve a cached file
  432. *
  433. * @access public
  434. * @param object config class
  435. * @param object uri class
  436. * @return void
  437. */
  438. function _display_cache(&$CFG, &$URI)
  439. {
  440. $cache_path = ($CFG->item('cache_path') == '') ? APPPATH.'cache/' : $CFG->item('cache_path');
  441. // Build the file path. The file name is an MD5 hash of the full URI
  442. $uri = $CFG->item('base_url').
  443. $CFG->item('index_page').
  444. $URI->uri_string;
  445. $filepath = $cache_path.md5($uri);
  446. if ( ! @file_exists($filepath))
  447. {
  448. return FALSE;
  449. }
  450. if ( ! $fp = @fopen($filepath, FOPEN_READ))
  451. {
  452. return FALSE;
  453. }
  454. flock($fp, LOCK_SH);
  455. $cache = '';
  456. if (filesize($filepath) > 0)
  457. {
  458. $cache = fread($fp, filesize($filepath));
  459. }
  460. flock($fp, LOCK_UN);
  461. fclose($fp);
  462. // Strip out the embedded timestamp
  463. if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
  464. {
  465. return FALSE;
  466. }
  467. // Has the file expired? If so we'll delete it.
  468. if (time() >= trim(str_replace('TS--->', '', $match['1'])))
  469. {
  470. if (is_really_writable($cache_path))
  471. {
  472. @unlink($filepath);
  473. log_message('debug', "Cache file has expired. File deleted");
  474. return FALSE;
  475. }
  476. }
  477. // Display the cache
  478. $this->_display(str_replace($match['0'], '', $cache));
  479. log_message('debug', "Cache file is current. Sending it to browser.");
  480. return TRUE;
  481. }
  482. }
  483. // END Output Class
  484. /* End of file Output.php */
  485. /* Location: ./system/core/Output.php */