blob: 2263fdfb9c70b7895d804ddc0a569c30881f72d0 [file] [log] [blame]
Derek Jones0b59f272008-05-13 04:22:33 +00001<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
Derek Allardd2df9bc2007-04-15 17:41:17 +00002/**
3 * CodeIgniter
4 *
5 * An open source application development framework for PHP 4.3.2 or newer
6 *
7 * @package CodeIgniter
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Rick Ellise4a7db42008-09-12 23:35:09 +00009 * @copyright Copyright (c) 2008, EllisLab, Inc.
Derek Jones7a9193a2008-01-21 18:39:20 +000010 * @license http://codeigniter.com/user_guide/license.html
11 * @link http://codeigniter.com
Derek Allardd2df9bc2007-04-15 17:41:17 +000012 * @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
Derek Allard3d879d52008-01-18 19:41:32 +000026 * @author ExpressionEngine Dev Team
Derek Jones7a9193a2008-01-21 18:39:20 +000027 * @link http://codeigniter.com/user_guide/libraries/output.html
Derek Allardd2df9bc2007-04-15 17:41:17 +000028 */
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 // --------------------------------------------------------------------
Derek Allard66f07242008-01-18 22:36:14 +000074
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 // --------------------------------------------------------------------
Rick Ellisc3b33be2008-10-01 01:31:36 +000097
Derek Allardd2df9bc2007-04-15 17:41:17 +000098 /**
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 */
Rick Ellisc3b33be2008-10-01 01:31:36 +0000110 function set_header($header, $replace = TRUE)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000111 {
Rick Ellisc3b33be2008-10-01 01:31:36 +0000112 $this->headers[] = array($header, $replace);
113 }
114
115 // --------------------------------------------------------------------
116
117 /**
118 * Set HTTP Status Header
119 *
120 * @access public
121 * @param int the status code
122 * @param string
123 * @return void
124 */
125 function set_status_header($code, $text='')
126 {
127 if ( ! in_array($code, array(200, 304, 401, 404)) AND $text == '')
128 {
129 show_error('You must submit a status message and a status code');
130 }
131
132 if ($text == '')
133 {
134 switch($code)
135 {
136 case 200: $text = 'OK';
137 break;
138 case 304: $text = 'Not Modified';
139 break;
140 case 401: $text = 'Unauthorized';
141 break;
142 case 404: $text = 'Not Found';
143 break;
144 }
145 }
146
147 if (substr(php_sapi_name(), 0, 3) == 'cgi')
148 {
149 @header("Status: {$code} {$text}", TRUE);
150 }
151 elseif ($_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.1' OR $_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.0')
152 {
153 @header($_SERVER['SERVER_PROTOCOL']." {$code} {$text}", TRUE, $code);
154 }
155 else
156 {
157 @header("HTTP/1.1 {$code} {$text}", TRUE, $code);
158 }
Derek Allardd2df9bc2007-04-15 17:41:17 +0000159 }
160
161 // --------------------------------------------------------------------
162
163 /**
164 * Enable/disable Profiler
165 *
166 * @access public
167 * @param bool
168 * @return void
169 */
170 function enable_profiler($val = TRUE)
171 {
172 $this->enable_profiler = (is_bool($val)) ? $val : TRUE;
173 }
174
175 // --------------------------------------------------------------------
176
177 /**
178 * Set Cache
179 *
180 * @access public
181 * @param integer
182 * @return void
183 */
184 function cache($time)
185 {
Derek Jones0b59f272008-05-13 04:22:33 +0000186 $this->cache_expiration = ( ! is_numeric($time)) ? 0 : $time;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000187 }
188
189 // --------------------------------------------------------------------
190
191 /**
192 * Display Output
193 *
194 * All "view" data is automatically put into this variable by the controller class:
195 *
196 * $this->final_output
197 *
198 * This function sends the finalized output data to the browser along
199 * with any server headers and profile data. It also stops the
200 * benchmark timer so the page rendering speed and memory usage can be shown.
201 *
202 * @access public
203 * @return mixed
204 */
205 function _display($output = '')
206 {
207 // Note: We use globals because we can't use $CI =& get_instance()
208 // since this function is sometimes called by the caching mechanism,
209 // which happens before the CI super object is available.
210 global $BM, $CFG;
211
212 // --------------------------------------------------------------------
213
214 // Set the output data
215 if ($output == '')
216 {
217 $output =& $this->final_output;
218 }
219
220 // --------------------------------------------------------------------
221
222 // Do we need to write a cache file?
223 if ($this->cache_expiration > 0)
224 {
225 $this->_write_cache($output);
226 }
227
228 // --------------------------------------------------------------------
229
230 // Parse out the elapsed time and memory usage,
231 // then swap the pseudo-variables with the data
Rick Ellisc3b33be2008-10-01 01:31:36 +0000232
Derek Allardd2df9bc2007-04-15 17:41:17 +0000233 $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
234 $output = str_replace('{elapsed_time}', $elapsed, $output);
235
Derek Jones0b59f272008-05-13 04:22:33 +0000236 $memory = ( ! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
Derek Allardd2df9bc2007-04-15 17:41:17 +0000237 $output = str_replace('{memory_usage}', $memory, $output);
238
239 // --------------------------------------------------------------------
240
241 // Is compression requested?
242 if ($CFG->item('compress_output') === TRUE)
243 {
244 if (extension_loaded('zlib'))
245 {
246 if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
247 {
248 ob_start('ob_gzhandler');
249 }
250 }
251 }
252
253 // --------------------------------------------------------------------
254
255 // Are there any server headers to send?
256 if (count($this->headers) > 0)
257 {
258 foreach ($this->headers as $header)
259 {
Rick Ellisc3b33be2008-10-01 01:31:36 +0000260 @header($header[0], $header[1]);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000261 }
262 }
263
264 // --------------------------------------------------------------------
265
266 // Does the get_instance() function exist?
267 // If not we know we are dealing with a cache file so we'll
268 // simply echo out the data and exit.
Derek Jones0b59f272008-05-13 04:22:33 +0000269 if ( ! function_exists('get_instance'))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000270 {
271 echo $output;
272 log_message('debug', "Final output sent to browser");
273 log_message('debug', "Total execution time: ".$elapsed);
274 return TRUE;
275 }
276
277 // --------------------------------------------------------------------
278
279 // Grab the super object. We'll need it in a moment...
280 $CI =& get_instance();
281
282 // Do we need to generate profile data?
283 // If so, load the Profile class and run it.
284 if ($this->enable_profiler == TRUE)
285 {
286 $CI->load->library('profiler');
287
288 // If the output data contains closing </body> and </html> tags
289 // we will remove them and add them back after we insert the profile data
290 if (preg_match("|</body>.*?</html>|is", $output))
291 {
292 $output = preg_replace("|</body>.*?</html>|is", '', $output);
293 $output .= $CI->profiler->run();
294 $output .= '</body></html>';
295 }
296 else
297 {
298 $output .= $CI->profiler->run();
299 }
300 }
301
302 // --------------------------------------------------------------------
303
304 // Does the controller contain a function named _output()?
305 // If so send the output there. Otherwise, echo it.
306 if (method_exists($CI, '_output'))
307 {
308 $CI->_output($output);
309 }
310 else
311 {
312 echo $output; // Send it to the browser!
313 }
314
315 log_message('debug', "Final output sent to browser");
316 log_message('debug', "Total execution time: ".$elapsed);
317 }
318
319 // --------------------------------------------------------------------
320
321 /**
322 * Write a Cache File
323 *
324 * @access public
325 * @return void
326 */
327 function _write_cache($output)
328 {
329 $CI =& get_instance();
330 $path = $CI->config->item('cache_path');
331
332 $cache_path = ($path == '') ? BASEPATH.'cache/' : $path;
333
Derek Jones0b59f272008-05-13 04:22:33 +0000334 if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000335 {
336 return;
337 }
338
339 $uri = $CI->config->item('base_url').
340 $CI->config->item('index_page').
341 $CI->uri->uri_string();
342
343 $cache_path .= md5($uri);
344
Rick Ellisc3b33be2008-10-01 01:31:36 +0000345 if ( ! $fp = @fopen($cache_path, FOPEN_WRITE_CREATE_DESTRUCTIVE))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000346 {
Derek Allardd8856802007-05-24 03:49:37 +0000347 log_message('error', "Unable to write cache file: ".$cache_path);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000348 return;
349 }
350
351 $expire = time() + ($this->cache_expiration * 60);
352
353 flock($fp, LOCK_EX);
354 fwrite($fp, $expire.'TS--->'.$output);
355 flock($fp, LOCK_UN);
356 fclose($fp);
Derek Jones3ad8efe2008-04-04 18:56:04 +0000357 @chmod($cache_path, DIR_WRITE_MODE);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000358
359 log_message('debug', "Cache file written: ".$cache_path);
360 }
361
362 // --------------------------------------------------------------------
363
364 /**
365 * Update/serve a cached file
366 *
367 * @access public
368 * @return void
369 */
Derek Allard57aea152008-06-06 14:17:57 +0000370 function _display_cache(&$CFG, &$URI)
Derek Allardd2df9bc2007-04-15 17:41:17 +0000371 {
Derek Allardd2df9bc2007-04-15 17:41:17 +0000372 $cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path');
373
Derek Jones0b59f272008-05-13 04:22:33 +0000374 if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000375 {
376 return FALSE;
377 }
378
379 // Build the file path. The file name is an MD5 hash of the full URI
380 $uri = $CFG->item('base_url').
381 $CFG->item('index_page').
Rick Ellis30b40152007-07-20 00:01:13 +0000382 $URI->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000383
384 $filepath = $cache_path.md5($uri);
385
Derek Jones0b59f272008-05-13 04:22:33 +0000386 if ( ! @file_exists($filepath))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000387 {
388 return FALSE;
389 }
390
Rick Ellisc3b33be2008-10-01 01:31:36 +0000391 if ( ! $fp = @fopen($filepath, FOPEN_READ))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000392 {
393 return FALSE;
394 }
395
396 flock($fp, LOCK_SH);
397
398 $cache = '';
399 if (filesize($filepath) > 0)
400 {
401 $cache = fread($fp, filesize($filepath));
402 }
403
404 flock($fp, LOCK_UN);
405 fclose($fp);
406
407 // Strip out the embedded timestamp
Derek Jones0b59f272008-05-13 04:22:33 +0000408 if ( ! preg_match("/(\d+TS--->)/", $cache, $match))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000409 {
410 return FALSE;
411 }
412
413 // Has the file expired? If so we'll delete it.
414 if (time() >= trim(str_replace('TS--->', '', $match['1'])))
415 {
416 @unlink($filepath);
417 log_message('debug', "Cache file has expired. File deleted");
418 return FALSE;
419 }
420
421 // Display the cache
422 $this->_display(str_replace($match['0'], '', $cache));
423 log_message('debug', "Cache file is current. Sending it to browser.");
424 return TRUE;
425 }
426
427
428}
429// END Output Class
Derek Jones0b59f272008-05-13 04:22:33 +0000430
431/* End of file Output.php */
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000432/* Location: ./system/libraries/Output.php */