blob: f76550e2bc34a345c49fffbd864dfa5663e1529d [file] [log] [blame]
Derek Allardd2df9bc2007-04-15 17:41:17 +00001<?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
Derek Allard3d879d52008-01-18 19:41:32 +00008 * @author ExpressionEngine Dev Team
Derek Allardd2df9bc2007-04-15 17:41:17 +00009 * @copyright Copyright (c) 2006, 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 // --------------------------------------------------------------------
97
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 */
110 function set_header($header)
111 {
112 $this->headers[] = $header;
113 }
114
115 // --------------------------------------------------------------------
116
117 /**
118 * Enable/disable Profiler
119 *
120 * @access public
121 * @param bool
122 * @return void
123 */
124 function enable_profiler($val = TRUE)
125 {
126 $this->enable_profiler = (is_bool($val)) ? $val : TRUE;
127 }
128
129 // --------------------------------------------------------------------
130
131 /**
132 * Set Cache
133 *
134 * @access public
135 * @param integer
136 * @return void
137 */
138 function cache($time)
139 {
Derek Allard73274992008-05-05 16:39:18 +0000140 $this->cache_expiration = (! is_numeric($time)) ? 0 : $time;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000141 }
142
143 // --------------------------------------------------------------------
144
145 /**
146 * Display Output
147 *
148 * All "view" data is automatically put into this variable by the controller class:
149 *
150 * $this->final_output
151 *
152 * This function sends the finalized output data to the browser along
153 * with any server headers and profile data. It also stops the
154 * benchmark timer so the page rendering speed and memory usage can be shown.
155 *
156 * @access public
157 * @return mixed
158 */
159 function _display($output = '')
160 {
161 // Note: We use globals because we can't use $CI =& get_instance()
162 // since this function is sometimes called by the caching mechanism,
163 // which happens before the CI super object is available.
164 global $BM, $CFG;
165
166 // --------------------------------------------------------------------
167
168 // Set the output data
169 if ($output == '')
170 {
171 $output =& $this->final_output;
172 }
173
174 // --------------------------------------------------------------------
175
176 // Do we need to write a cache file?
177 if ($this->cache_expiration > 0)
178 {
179 $this->_write_cache($output);
180 }
181
182 // --------------------------------------------------------------------
183
184 // Parse out the elapsed time and memory usage,
185 // then swap the pseudo-variables with the data
186
187 $elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
188 $output = str_replace('{elapsed_time}', $elapsed, $output);
189
Derek Allard73274992008-05-05 16:39:18 +0000190 $memory = (! function_exists('memory_get_usage')) ? '0' : round(memory_get_usage()/1024/1024, 2).'MB';
Derek Allardd2df9bc2007-04-15 17:41:17 +0000191 $output = str_replace('{memory_usage}', $memory, $output);
192
193 // --------------------------------------------------------------------
194
195 // Is compression requested?
196 if ($CFG->item('compress_output') === TRUE)
197 {
198 if (extension_loaded('zlib'))
199 {
200 if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) AND strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
201 {
202 ob_start('ob_gzhandler');
203 }
204 }
205 }
206
207 // --------------------------------------------------------------------
208
209 // Are there any server headers to send?
210 if (count($this->headers) > 0)
211 {
212 foreach ($this->headers as $header)
213 {
214 @header($header);
215 }
216 }
217
218 // --------------------------------------------------------------------
219
220 // Does the get_instance() function exist?
221 // If not we know we are dealing with a cache file so we'll
222 // simply echo out the data and exit.
Derek Allard73274992008-05-05 16:39:18 +0000223 if (! function_exists('get_instance'))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000224 {
225 echo $output;
226 log_message('debug', "Final output sent to browser");
227 log_message('debug', "Total execution time: ".$elapsed);
228 return TRUE;
229 }
230
231 // --------------------------------------------------------------------
232
233 // Grab the super object. We'll need it in a moment...
234 $CI =& get_instance();
235
236 // Do we need to generate profile data?
237 // If so, load the Profile class and run it.
238 if ($this->enable_profiler == TRUE)
239 {
240 $CI->load->library('profiler');
241
242 // If the output data contains closing </body> and </html> tags
243 // we will remove them and add them back after we insert the profile data
244 if (preg_match("|</body>.*?</html>|is", $output))
245 {
246 $output = preg_replace("|</body>.*?</html>|is", '', $output);
247 $output .= $CI->profiler->run();
248 $output .= '</body></html>';
249 }
250 else
251 {
252 $output .= $CI->profiler->run();
253 }
254 }
255
256 // --------------------------------------------------------------------
257
258 // Does the controller contain a function named _output()?
259 // If so send the output there. Otherwise, echo it.
260 if (method_exists($CI, '_output'))
261 {
262 $CI->_output($output);
263 }
264 else
265 {
266 echo $output; // Send it to the browser!
267 }
268
269 log_message('debug', "Final output sent to browser");
270 log_message('debug', "Total execution time: ".$elapsed);
271 }
272
273 // --------------------------------------------------------------------
274
275 /**
276 * Write a Cache File
277 *
278 * @access public
279 * @return void
280 */
281 function _write_cache($output)
282 {
283 $CI =& get_instance();
284 $path = $CI->config->item('cache_path');
285
286 $cache_path = ($path == '') ? BASEPATH.'cache/' : $path;
287
Derek Allard73274992008-05-05 16:39:18 +0000288 if (! is_dir($cache_path) OR ! is_really_writable($cache_path))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000289 {
290 return;
291 }
292
293 $uri = $CI->config->item('base_url').
294 $CI->config->item('index_page').
295 $CI->uri->uri_string();
296
297 $cache_path .= md5($uri);
298
Derek Allard73274992008-05-05 16:39:18 +0000299 if (! $fp = @fopen($cache_path, 'wb'))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000300 {
Derek Allardd8856802007-05-24 03:49:37 +0000301 log_message('error', "Unable to write cache file: ".$cache_path);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000302 return;
303 }
304
305 $expire = time() + ($this->cache_expiration * 60);
306
307 flock($fp, LOCK_EX);
308 fwrite($fp, $expire.'TS--->'.$output);
309 flock($fp, LOCK_UN);
310 fclose($fp);
Derek Jones3ad8efe2008-04-04 18:56:04 +0000311 @chmod($cache_path, DIR_WRITE_MODE);
Derek Allardd2df9bc2007-04-15 17:41:17 +0000312
313 log_message('debug', "Cache file written: ".$cache_path);
314 }
315
316 // --------------------------------------------------------------------
317
318 /**
319 * Update/serve a cached file
320 *
321 * @access public
322 * @return void
323 */
324 function _display_cache(&$CFG, &$RTR)
325 {
Rick Ellis30b40152007-07-20 00:01:13 +0000326 $URI =& load_class('URI');
Derek Allardd2df9bc2007-04-15 17:41:17 +0000327
328 $cache_path = ($CFG->item('cache_path') == '') ? BASEPATH.'cache/' : $CFG->item('cache_path');
329
Derek Allard73274992008-05-05 16:39:18 +0000330 if (! is_dir($cache_path) OR ! is_really_writable($cache_path))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000331 {
332 return FALSE;
333 }
334
335 // Build the file path. The file name is an MD5 hash of the full URI
336 $uri = $CFG->item('base_url').
337 $CFG->item('index_page').
Rick Ellis30b40152007-07-20 00:01:13 +0000338 $URI->uri_string;
Derek Allardd2df9bc2007-04-15 17:41:17 +0000339
340 $filepath = $cache_path.md5($uri);
341
Derek Allard73274992008-05-05 16:39:18 +0000342 if (! @file_exists($filepath))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000343 {
344 return FALSE;
345 }
346
Derek Allard73274992008-05-05 16:39:18 +0000347 if (! $fp = @fopen($filepath, 'rb'))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000348 {
349 return FALSE;
350 }
351
352 flock($fp, LOCK_SH);
353
354 $cache = '';
355 if (filesize($filepath) > 0)
356 {
357 $cache = fread($fp, filesize($filepath));
358 }
359
360 flock($fp, LOCK_UN);
361 fclose($fp);
362
363 // Strip out the embedded timestamp
Derek Allard73274992008-05-05 16:39:18 +0000364 if (! preg_match("/(\d+TS--->)/", $cache, $match))
Derek Allardd2df9bc2007-04-15 17:41:17 +0000365 {
366 return FALSE;
367 }
368
369 // Has the file expired? If so we'll delete it.
370 if (time() >= trim(str_replace('TS--->', '', $match['1'])))
371 {
372 @unlink($filepath);
373 log_message('debug', "Cache file has expired. File deleted");
374 return FALSE;
375 }
376
377 // Display the cache
378 $this->_display(str_replace($match['0'], '', $cache));
379 log_message('debug', "Cache file is current. Sending it to browser.");
380 return TRUE;
381 }
382
383
384}
385// END Output Class
Derek Jonesa3ffbbb2008-05-11 18:18:29 +0000386
387/* End of file Output.php */
388/* Location: ./system/libraries/Output.php */