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