Completed
Push — master ( 63f9e6...34eb4c )
by Kenji
10s
created

replacing/core/old/3.1.7-Output.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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 - 2018, 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 - 2018, 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
/**
41
 * Output Class
42
 *
43
 * Responsible for sending final output to the browser.
44
 *
45
 * @package		CodeIgniter
46
 * @subpackage	Libraries
47
 * @category	Output
48
 * @author		EllisLab Dev Team
49
 * @link		https://codeigniter.com/user_guide/libraries/output.html
50
 */
51 View Code Duplication
class CI_Output {
52
53
	/**
54
	 * Final output string
55
	 *
56
	 * @var	string
57
	 */
58
	public $final_output;
59
60
	/**
61
	 * Cache expiration time
62
	 *
63
	 * @var	int
64
	 */
65
	public $cache_expiration = 0;
66
67
	/**
68
	 * List of server headers
69
	 *
70
	 * @var	array
71
	 */
72
	public $headers = array();
73
74
	/**
75
	 * List of mime types
76
	 *
77
	 * @var	array
78
	 */
79
	public $mimes =	array();
80
81
	/**
82
	 * Mime-type for the current page
83
	 *
84
	 * @var	string
85
	 */
86
	protected $mime_type = 'text/html';
87
88
	/**
89
	 * Enable Profiler flag
90
	 *
91
	 * @var	bool
92
	 */
93
	public $enable_profiler = FALSE;
94
95
	/**
96
	 * php.ini zlib.output_compression flag
97
	 *
98
	 * @var	bool
99
	 */
100
	protected $_zlib_oc = FALSE;
101
102
	/**
103
	 * CI output compression flag
104
	 *
105
	 * @var	bool
106
	 */
107
	protected $_compress_output = FALSE;
108
109
	/**
110
	 * List of profiler sections
111
	 *
112
	 * @var	array
113
	 */
114
	protected $_profiler_sections =	array();
115
116
	/**
117
	 * Parse markers flag
118
	 *
119
	 * Whether or not to parse variables like {elapsed_time} and {memory_usage}.
120
	 *
121
	 * @var	bool
122
	 */
123
	public $parse_exec_vars = TRUE;
124
125
	/**
126
	 * mbstring.func_overload flag
127
	 *
128
	 * @var	bool
129
	 */
130
	protected static $func_overload;
131
132
	/**
133
	 * Response status (status code, text and is redirection?)
134
	 *
135
	 * @var array
136
	 *
137
	 * added by ci-phpunit-test
138
	 */
139
	public $_status;
140
141
	/**
142
	 * Cookies
143
	 *
144
	 * @var array
145
	 *
146
	 * added by ci-phpunit-test
147
	 */
148
	public $_cookies;
149
150
	/**
151
	 * Class constructor
152
	 *
153
	 * Determines whether zLib output compression will be used.
154
	 *
155
	 * @return	void
156
	 */
157
	public function __construct()
158
	{
159
		$this->_zlib_oc = (bool) ini_get('zlib.output_compression');
160
		$this->_compress_output = (
161
			$this->_zlib_oc === FALSE
162
			&& config_item('compress_output') === TRUE
163
			&& extension_loaded('zlib')
164
		);
165
166
		isset(self::$func_overload) OR self::$func_overload = (extension_loaded('mbstring') && ini_get('mbstring.func_overload'));
167
168
		// Get mime types for later
169
		$this->mimes =& get_mimes();
170
171
		log_message('info', 'Output Class Initialized');
172
	}
173
174
	// --------------------------------------------------------------------
175
176
	/**
177
	 * Get Output
178
	 *
179
	 * Returns the current output string.
180
	 *
181
	 * @return	string
182
	 */
183
	public function get_output()
184
	{
185
		return $this->final_output;
186
	}
187
188
	// --------------------------------------------------------------------
189
190
	/**
191
	 * Set Output
192
	 *
193
	 * Sets the output string.
194
	 *
195
	 * @param	string	$output	Output data
196
	 * @return	CI_Output
197
	 */
198
	public function set_output($output)
199
	{
200
		$this->final_output = $output;
201
		return $this;
202
	}
203
204
	// --------------------------------------------------------------------
205
206
	/**
207
	 * Append Output
208
	 *
209
	 * Appends data onto the output string.
210
	 *
211
	 * @param	string	$output	Data to append
212
	 * @return	CI_Output
213
	 */
214
	public function append_output($output)
215
	{
216
		$this->final_output .= $output;
217
		return $this;
218
	}
219
220
	// --------------------------------------------------------------------
221
222
	/**
223
	 * Set Header
224
	 *
225
	 * Lets you set a server header which will be sent with the final output.
226
	 *
227
	 * Note: If a file is cached, headers will not be sent.
228
	 * @todo	We need to figure out how to permit headers to be cached.
229
	 *
230
	 * @param	string	$header		Header
231
	 * @param	bool	$replace	Whether to replace the old header value, if already set
232
	 * @return	CI_Output
233
	 */
234
	public function set_header($header, $replace = TRUE)
235
	{
236
		// If zlib.output_compression is enabled it will compress the output,
237
		// but it will not modify the content-length header to compensate for
238
		// the reduction, causing the browser to hang waiting for more data.
239
		// We'll just skip content-length in those cases.
240
		if ($this->_zlib_oc && strncasecmp($header, 'content-length', 14) === 0)
241
		{
242
			return $this;
243
		}
244
245
		$this->headers[] = array($header, $replace);
246
		return $this;
247
	}
248
249
	// --------------------------------------------------------------------
250
251
	/**
252
	 * Set Content-Type Header
253
	 *
254
	 * @param	string	$mime_type	Extension of the file we're outputting
255
	 * @param	string	$charset	Character set (default: NULL)
256
	 * @return	CI_Output
257
	 */
258
	public function set_content_type($mime_type, $charset = NULL)
259
	{
260
		if (strpos($mime_type, '/') === FALSE)
261
		{
262
			$extension = ltrim($mime_type, '.');
263
264
			// Is this extension supported?
265
			if (isset($this->mimes[$extension]))
266
			{
267
				$mime_type =& $this->mimes[$extension];
268
269
				if (is_array($mime_type))
270
				{
271
					$mime_type = current($mime_type);
272
				}
273
			}
274
		}
275
276
		$this->mime_type = $mime_type;
277
278
		if (empty($charset))
279
		{
280
			$charset = config_item('charset');
281
		}
282
283
		$header = 'Content-Type: '.$mime_type
284
			.(empty($charset) ? '' : '; charset='.$charset);
285
286
		$this->headers[] = array($header, TRUE);
287
		return $this;
288
	}
289
290
	// --------------------------------------------------------------------
291
292
	/**
293
	 * Get Current Content-Type Header
294
	 *
295
	 * @return	string	'text/html', if not already set
296
	 */
297
	public function get_content_type()
298
	{
299
		for ($i = 0, $c = count($this->headers); $i < $c; $i++)
300
		{
301
			if (sscanf($this->headers[$i][0], 'Content-Type: %[^;]', $content_type) === 1)
302
			{
303
				return $content_type;
304
			}
305
		}
306
307
		return 'text/html';
308
	}
309
310
	// --------------------------------------------------------------------
311
312
	/**
313
	 * Get Header
314
	 *
315
	 * @param	string	$header
316
	 * @return	string
317
	 */
318
	public function get_header($header)
319
	{
320
		// Combine headers already sent with our batched headers
321
		$headers = array_merge(
322
			// We only need [x][0] from our multi-dimensional array
323
			array_map('array_shift', $this->headers),
324
			headers_list()
325
		);
326
327
		if (empty($headers) OR empty($header))
328
		{
329
			return NULL;
330
		}
331
332
		// Count backwards, in order to get the last matching header
333
		for ($c = count($headers) - 1; $c > -1; $c--)
334
		{
335
			if (strncasecmp($header, $headers[$c], $l = self::strlen($header)) === 0)
336
			{
337
				return trim(self::substr($headers[$c], $l+1));
338
			}
339
		}
340
341
		return NULL;
342
	}
343
344
	// --------------------------------------------------------------------
345
346
	/**
347
	 * Set HTTP Status Header
348
	 *
349
	 * As of version 1.7.2, this is an alias for common function
350
	 * set_status_header().
351
	 *
352
	 * @param	int	$code	Status code (default: 200)
353
	 * @param	string	$text	Optional message
354
	 * @return	CI_Output
355
	 */
356
	public function set_status_header($code = 200, $text = '')
357
	{
358
		set_status_header($code, $text);
359
		return $this;
360
	}
361
362
	// --------------------------------------------------------------------
363
364
	/**
365
	 * Enable/disable Profiler
366
	 *
367
	 * @param	bool	$val	TRUE to enable or FALSE to disable
368
	 * @return	CI_Output
369
	 */
370
	public function enable_profiler($val = TRUE)
371
	{
372
		$this->enable_profiler = is_bool($val) ? $val : TRUE;
373
		return $this;
374
	}
375
376
	// --------------------------------------------------------------------
377
378
	/**
379
	 * Set Profiler Sections
380
	 *
381
	 * Allows override of default/config settings for
382
	 * Profiler section display.
383
	 *
384
	 * @param	array	$sections	Profiler sections
385
	 * @return	CI_Output
386
	 */
387
	public function set_profiler_sections($sections)
388
	{
389
		if (isset($sections['query_toggle_count']))
390
		{
391
			$this->_profiler_sections['query_toggle_count'] = (int) $sections['query_toggle_count'];
392
			unset($sections['query_toggle_count']);
393
		}
394
395
		foreach ($sections as $section => $enable)
396
		{
397
			$this->_profiler_sections[$section] = ($enable !== FALSE);
398
		}
399
400
		return $this;
401
	}
402
403
	// --------------------------------------------------------------------
404
405
	/**
406
	 * Set Cache
407
	 *
408
	 * @param	int	$time	Cache expiration time in minutes
409
	 * @return	CI_Output
410
	 */
411
	public function cache($time)
412
	{
413
		$this->cache_expiration = is_numeric($time) ? $time : 0;
414
		return $this;
415
	}
416
417
	// --------------------------------------------------------------------
418
419
	/**
420
	 * Display Output
421
	 *
422
	 * Processes and sends finalized output data to the browser along
423
	 * with any server headers and profile data. It also stops benchmark
424
	 * timers so the page rendering speed and memory usage can be shown.
425
	 *
426
	 * Note: All "view" data is automatically put into $this->final_output
427
	 *	 by controller class.
428
	 *
429
	 * @uses	CI_Output::$final_output
430
	 * @param	string	$output	Output data override
431
	 * @return	void
432
	 *
433
	 * modified by ci-phpunit-test
434
	 */
435
	public function _display($output = '')
436
	{
437
		// Note:  We use load_class() because we can't use $CI =& get_instance()
438
		// since this function is sometimes called by the caching mechanism,
439
		// which happens before the CI super object is available.
440
		$BM =& load_class('Benchmark', 'core');
441
		$CFG =& load_class('Config', 'core');
442
443
		// Grab the super object if we can.
444
		if (class_exists('CI_Controller', FALSE))
445
		{
446
			$CI =& get_instance();
447
		}
448
449
		// --------------------------------------------------------------------
450
451
		// Set the output data
452
		if ($output === '')
453
		{
454
			$output =& $this->final_output;
455
		}
456
457
		// --------------------------------------------------------------------
458
459
		// Do we need to write a cache file? Only if the controller does not have its
460
		// own _output() method and we are not dealing with a cache file, which we
461
		// can determine by the existence of the $CI object above
462
		if ($this->cache_expiration > 0 && isset($CI) && ! method_exists($CI, '_output'))
463
		{
464
			$this->_write_cache($output);
465
		}
466
467
		// --------------------------------------------------------------------
468
469
		// Parse out the elapsed time and memory usage,
470
		// then swap the pseudo-variables with the data
471
472
		$elapsed = $BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
473
474
		if ($this->parse_exec_vars === TRUE)
475
		{
476
			$memory	= round(memory_get_usage() / 1024 / 1024, 2).'MB';
477
			$output = str_replace(array('{elapsed_time}', '{memory_usage}'), array($elapsed, $memory), $output);
478
		}
479
480
		// --------------------------------------------------------------------
481
482
		// Is compression requested?
483
		if (isset($CI) // This means that we're not serving a cache file, if we were, it would already be compressed
484
			&& $this->_compress_output === TRUE
485
			&& isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
486
		{
487
			ob_start('ob_gzhandler');
488
		}
489
490
		// --------------------------------------------------------------------
491
492
		// Are there any server headers to send?
493
		if (count($this->headers) > 0)
494
		{
495
			foreach ($this->headers as $header)
496
			{
497
//				@header($header[0], $header[1]);
498
			}
499
		}
500
501
		// --------------------------------------------------------------------
502
503
		// Does the $CI object exist?
504
		// If not we know we are dealing with a cache file so we'll
505
		// simply echo out the data and exit.
506
		if ( ! isset($CI))
507
		{
508
			if ($this->_compress_output === TRUE)
509
			{
510
				if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== FALSE)
511
				{
512
//					header('Content-Encoding: gzip');
513
//					header('Content-Length: '.self::strlen($output));
514
				}
515
				else
516
				{
517
					// User agent doesn't support gzip compression,
518
					// so we'll have to decompress our cache
519
					$output = gzinflate(self::substr($output, 10, -8));
520
				}
521
			}
522
523
			echo $output;
524
			log_message('info', 'Final output sent to browser');
525
			log_message('debug', 'Total execution time: '.$elapsed);
526
			return;
527
		}
528
529
		// --------------------------------------------------------------------
530
531
		// Do we need to generate profile data?
532
		// If so, load the Profile class and run it.
533
		if ($this->enable_profiler === TRUE)
534
		{
535
			$CI->load->library('profiler');
536
			if ( ! empty($this->_profiler_sections))
537
			{
538
				$CI->profiler->set_sections($this->_profiler_sections);
539
			}
540
541
			// If the output data contains closing </body> and </html> tags
542
			// we will remove them and add them back after we insert the profile data
543
			$output = preg_replace('|</body>.*?</html>|is', '', $output, -1, $count).$CI->profiler->run();
544
			if ($count > 0)
545
			{
546
				$output .= '</body></html>';
547
			}
548
		}
549
550
		// Does the controller contain a function named _output()?
551
		// If so send the output there.  Otherwise, echo it.
552
		if (method_exists($CI, '_output'))
553
		{
554
			$CI->_output($output);
555
		}
556
		else
557
		{
558
			echo $output; // Send it to the browser!
559
		}
560
561
		log_message('info', 'Final output sent to browser');
562
		log_message('debug', 'Total execution time: '.$elapsed);
563
	}
564
565
	// --------------------------------------------------------------------
566
567
	/**
568
	 * Write Cache
569
	 *
570
	 * @param	string	$output	Output data to cache
571
	 * @return	void
572
	 */
573
	public function _write_cache($output)
574
	{
575
		$CI =& get_instance();
576
		$path = $CI->config->item('cache_path');
577
		$cache_path = ($path === '') ? APPPATH.'cache/' : $path;
578
579
		if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
580
		{
581
			log_message('error', 'Unable to write cache file: '.$cache_path);
582
			return;
583
		}
584
585
		$uri = $CI->config->item('base_url')
586
			.$CI->config->item('index_page')
587
			.$CI->uri->uri_string();
588
589
		if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
590
		{
591
			if (is_array($cache_query_string))
592
			{
593
				$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
594
			}
595
			else
596
			{
597
				$uri .= '?'.$_SERVER['QUERY_STRING'];
598
			}
599
		}
600
601
		$cache_path .= md5($uri);
602
603
		if ( ! $fp = @fopen($cache_path, 'w+b'))
604
		{
605
			log_message('error', 'Unable to write cache file: '.$cache_path);
606
			return;
607
		}
608
609
		if ( ! flock($fp, LOCK_EX))
610
		{
611
			log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
612
			fclose($fp);
613
			return;
614
		}
615
616
		// If output compression is enabled, compress the cache
617
		// itself, so that we don't have to do that each time
618
		// we're serving it
619
		if ($this->_compress_output === TRUE)
620
		{
621
			$output = gzencode($output);
622
623
			if ($this->get_header('content-type') === NULL)
624
			{
625
				$this->set_content_type($this->mime_type);
626
			}
627
		}
628
629
		$expire = time() + ($this->cache_expiration * 60);
630
631
		// Put together our serialized info.
632
		$cache_info = serialize(array(
633
			'expire'	=> $expire,
634
			'headers'	=> $this->headers
635
		));
636
637
		$output = $cache_info.'ENDCI--->'.$output;
638
639
		for ($written = 0, $length = self::strlen($output); $written < $length; $written += $result)
640
		{
641
			if (($result = fwrite($fp, self::substr($output, $written))) === FALSE)
642
			{
643
				break;
644
			}
645
		}
646
647
		flock($fp, LOCK_UN);
648
		fclose($fp);
649
650
		if ( ! is_int($result))
0 ignored issues
show
The variable $result does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
651
		{
652
			@unlink($cache_path);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
653
			log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
654
			return;
655
		}
656
657
		chmod($cache_path, 0640);
658
		log_message('debug', 'Cache file written: '.$cache_path);
659
660
		// Send HTTP cache-control headers to browser to match file cache settings.
661
		$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
662
	}
663
664
	// --------------------------------------------------------------------
665
666
	/**
667
	 * Update/serve cached output
668
	 *
669
	 * @uses	CI_Config
670
	 * @uses	CI_URI
671
	 *
672
	 * @param	object	&$CFG	CI_Config class instance
673
	 * @param	object	&$URI	CI_URI class instance
674
	 * @return	bool	TRUE on success or FALSE on failure
675
	 */
676
	public function _display_cache(&$CFG, &$URI)
677
	{
678
		$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
679
680
		// Build the file path. The file name is an MD5 hash of the full URI
681
		$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
682
683
		if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
684
		{
685
			if (is_array($cache_query_string))
686
			{
687
				$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
688
			}
689
			else
690
			{
691
				$uri .= '?'.$_SERVER['QUERY_STRING'];
692
			}
693
		}
694
695
		$filepath = $cache_path.md5($uri);
696
697
		if ( ! file_exists($filepath) OR ! $fp = @fopen($filepath, 'rb'))
698
		{
699
			return FALSE;
700
		}
701
702
		flock($fp, LOCK_SH);
703
704
		$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
705
706
		flock($fp, LOCK_UN);
707
		fclose($fp);
708
709
		// Look for embedded serialized file info.
710
		if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
711
		{
712
			return FALSE;
713
		}
714
715
		$cache_info = unserialize($match[1]);
716
		$expire = $cache_info['expire'];
717
718
		$last_modified = filemtime($filepath);
719
720
		// Has the file expired?
721
		if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
722
		{
723
			// If so we'll delete it.
724
			@unlink($filepath);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
725
			log_message('debug', 'Cache file has expired. File deleted.');
726
			return FALSE;
727
		}
728
729
		// Send the HTTP cache control headers
730
		$this->set_cache_header($last_modified, $expire);
731
732
		// Add headers from cache file.
733
		foreach ($cache_info['headers'] as $header)
734
		{
735
			$this->set_header($header[0], $header[1]);
736
		}
737
738
		// Display the cache
739
		$this->_display(self::substr($cache, self::strlen($match[0])));
740
		log_message('debug', 'Cache file is current. Sending it to browser.');
741
		return TRUE;
742
	}
743
744
	// --------------------------------------------------------------------
745
746
	/**
747
	 * Delete cache
748
	 *
749
	 * @param	string	$uri	URI string
750
	 * @return	bool
751
	 */
752
	public function delete_cache($uri = '')
753
	{
754
		$CI =& get_instance();
755
		$cache_path = $CI->config->item('cache_path');
756
		if ($cache_path === '')
757
		{
758
			$cache_path = APPPATH.'cache/';
759
		}
760
761
		if ( ! is_dir($cache_path))
762
		{
763
			log_message('error', 'Unable to find cache path: '.$cache_path);
764
			return FALSE;
765
		}
766
767
		if (empty($uri))
768
		{
769
			$uri = $CI->uri->uri_string();
770
771
			if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
772
			{
773
				if (is_array($cache_query_string))
774
				{
775
					$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
776
				}
777
				else
778
				{
779
					$uri .= '?'.$_SERVER['QUERY_STRING'];
780
				}
781
			}
782
		}
783
784
		$cache_path .= md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
785
786
		if ( ! @unlink($cache_path))
787
		{
788
			log_message('error', 'Unable to delete cache file for '.$uri);
789
			return FALSE;
790
		}
791
792
		return TRUE;
793
	}
794
795
	// --------------------------------------------------------------------
796
797
	/**
798
	 * Set Cache Header
799
	 *
800
	 * Set the HTTP headers to match the server-side file cache settings
801
	 * in order to reduce bandwidth.
802
	 *
803
	 * @param	int	$last_modified	Timestamp of when the page was last modified
804
	 * @param	int	$expiration	Timestamp of when should the requested page expire from cache
805
	 * @return	void
806
	 *
807
	 * modified by ci-phpunit-test
808
	 */
809
	public function set_cache_header($last_modified, $expiration)
810
	{
811
		$max_age = $expiration - $_SERVER['REQUEST_TIME'];
0 ignored issues
show
$max_age is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
812
813
		if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && $last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']))
814
		{
815
			$this->set_status_header(304);
816
			exit;
0 ignored issues
show
Coding Style Compatibility introduced by
The method set_cache_header() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
817
		}
818
819
//		header('Pragma: public');
820
//		header('Cache-Control: max-age='.$max_age.', public');
821
//		header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
822
//		header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
823
	}
824
825
	// --------------------------------------------------------------------
826
827
	/**
828
	 * Byte-safe strlen()
829
	 *
830
	 * @param	string	$str
831
	 * @return	int
832
	 */
833
	protected static function strlen($str)
834
	{
835
		return (self::$func_overload)
836
			? mb_strlen($str, '8bit')
837
			: strlen($str);
838
	}
839
840
	// --------------------------------------------------------------------
841
842
	/**
843
	 * Byte-safe substr()
844
	 *
845
	 * @param	string	$str
846
	 * @param	int	$start
847
	 * @param	int	$length
848
	 * @return	string
849
	 */
850
	protected static function substr($str, $start, $length = NULL)
851
	{
852
		if (self::$func_overload)
853
		{
854
			// mb_substr($str, $start, null, '8bit') returns an empty
855
			// string on PHP 5.3
856
			isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
857
			return mb_substr($str, $start, $length, '8bit');
858
		}
859
860
		return isset($length)
861
			? substr($str, $start, $length)
862
			: substr($str, $start);
863
	}
864
}
865