summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--application/config/config.php13
-rw-r--r--system/core/Output.php167
2 files changed, 177 insertions, 3 deletions
diff --git a/application/config/config.php b/application/config/config.php
index 7da889f81..726e3a71c 100644
--- a/application/config/config.php
+++ b/application/config/config.php
@@ -359,6 +359,18 @@ $config['compress_output'] = FALSE;
/*
|--------------------------------------------------------------------------
+| Minify
+|--------------------------------------------------------------------------
+|
+| Removes extra characters (usually unnecessary spaces) from your
+| output for faster page load speeds. Makes your outputted HTML source
+| code less readable.
+|
+*/
+$config['minify_output'] = FALSE;
+
+/*
+|--------------------------------------------------------------------------
| Master Time Reference
|--------------------------------------------------------------------------
|
@@ -398,5 +410,6 @@ $config['rewrite_short_tags'] = FALSE;
$config['proxy_ips'] = '';
+
/* End of file config.php */
/* Location: ./application/config/config.php */
diff --git a/system/core/Output.php b/system/core/Output.php
index 5588ffe8e..8a0f14e02 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -67,6 +67,12 @@ class CI_Output {
public $mimes = array();
/**
+ * Mime-type for the current page
+ *
+ * @var string
+ */
+ protected $mime_type = 'text/html';
+ /**
* Determines wether profiler is enabled
*
* @var book
@@ -217,6 +223,8 @@ class CI_Output {
}
}
}
+
+ $this->mime_type = $mime_type;
if (empty($charset))
{
@@ -350,6 +358,15 @@ class CI_Output {
{
$output =& $this->final_output;
}
+
+ // --------------------------------------------------------------------
+
+ // Is minify requested?
+ if ($CFG->item('minify_output') === TRUE)
+ {
+ $output = $this->minify($output, $this->mime_type);
+ }
+
// --------------------------------------------------------------------
@@ -493,6 +510,9 @@ class CI_Output {
@chmod($cache_path, FILE_WRITE_MODE);
log_message('debug', 'Cache file written: '.$cache_path);
+
+ // Send HTTP cache-control headers to browser to match file cache settings.
+ $this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
// --------------------------------------------------------------------
@@ -530,13 +550,22 @@ class CI_Output {
return FALSE;
}
- // Has the file expired? If so we'll delete it.
- if (time() >= trim(str_replace('TS--->', '', $match[1])) && is_really_writable($cache_path))
+ $last_modified = filemtime($cache_path);
+ $expire = trim(str_replace('TS--->', '', $match[1]));
+
+ // Has the file expired?
+ if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
+ // If so we'll delete it.
@unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
+ else
+ {
+ // Or else send the HTTP cache control headers.
+ $this->set_cache_header($last_modified, $expire);
+ }
// Display the cache
$this->_display(str_replace($match[0], '', $cache));
@@ -544,7 +573,139 @@ class CI_Output {
return TRUE;
}
+
+ // --------------------------------------------------------------------
+ /**
+ * Set the HTTP headers to match the server-side file cache settings
+ * in order to reduce bandwidth.
+ *
+ * @param int timestamp of when the page was last modified
+ * @param int timestamp of when should the requested page expire from cache
+ * @return void
+ */
+ public function set_cache_header($last_modified, $expiration)
+ {
+ $max_age = $expiration - $_SERVER['REQUEST_TIME'];
+
+ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && ($last_modified <= strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE'])))
+ {
+ $this->set_status_header(304);
+ exit;
+ }
+ else
+ {
+ header('Pragma: public');
+ header('Cache-Control: max-age=' . $max_age . ', public');
+ header('Expires: '.gmdate('D, d M Y H:i:s', $expiration).' GMT');
+ header('Last-modified: '.gmdate('D, d M Y H:i:s', $last_modified).' GMT');
+ }
+ }
+
+
+
+
+ // --------------------------------------------------------------------
+ /**
+ * Reduce excessive size of HTML content.
+ *
+ * @param string
+ * @param string
+ * @return string
+ */
+ public function minify($output, $type='text/html')
+ {
+ switch ($type)
+ {
+ case 'text/html':
+
+ $size_before = strlen($output);
+
+ // Find all the <pre>,<code>,<textarea>, and <javascript> tags
+ // We'll want to return them to this unprocessed state later.
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_clean);
+ preg_match_all('{<code.+</code>}msU', $output, $codes_clean);
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_clean);
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_clean);
+
+ // Minify the CSS in all the <style> tags.
+ preg_match_all('{<style.+</style>}msU', $output, $style_clean);
+ foreach ($style_clean[0] as $s)
+ {
+ $output = str_replace($s, $this->minify($s, 'text/css'), $output);
+ }
+
+ // Minify the javascript in <script> tags.
+ foreach ($javascript_clean[0] as $s)
+ {
+ $javascript_mini[] = $this->minify($s, 'text/javascript');
+ }
+
+ // Replace multiple spaces with a single space.
+ $output = preg_replace('!\s{2,}!', ' ', $output);
+
+ // Remove comments (non-MSIE conditionals)
+ $output = preg_replace('{\s*<!--[^\[].*-->\s*}msU', '', $output);
+
+ // Remove spaces around block-level elements.
+ $output = preg_replace('{\s*(</?(html|head|title|meta|script|link|style|body|h[1-6]|div|p|br).*>)\s+}msU', '$1', $output);
+
+ // Replace mangled <pre> etc. tags with unprocessed ones.
+
+ if ( ! empty($pres_clean))
+ {
+ preg_match_all('{<pre.+</pre>}msU', $output, $pres_messed);
+ $output = str_replace($pres_messed[0], $pres_clean[0], $output);
+ }
+
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<code.+</code>}msU', $output, $codes_messed);
+ $output = str_replace($codes_messed[0], $codes_clean[0], $output);
+ }
+
+ if ( ! empty($codes_clean))
+ {
+ preg_match_all('{<textarea.+</textarea>}msU', $output, $textareas_messed);
+ $output = str_replace($textareas_messed[0], $textareas_clean[0], $output);
+ }
+
+ if (isset($javascript_mini))
+ {
+ preg_match_all('{<script.+</script>}msU', $output, $javascript_messed);
+ $output = str_replace($javascript_messed[0], $javascript_mini, $output);
+ }
+
+ $size_removed = $size_before - strlen($output);
+ $savings_percent = round(($size_removed / $size_before * 100));
+
+ log_message('debug', 'Minifier shaved '.($size_removed / 1000).'KB ('.$savings_percent.'%) off final HTML output.');
+
+ break;
+
+
+ case 'text/css':
+
+ //Remove CSS comments
+ $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $output);
+
+ // Remove spaces around curly brackets, colons,
+ // semi-colons, parenthesis, commas
+ $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!', '$1', $output);
+
+ break;
+
+
+ case 'text/javascript':
+
+ // Currently leaves JavaScript untouched.
+ break;
+ }
+
+ return $output;
+ }
+
+
}
/* End of file Output.php */
-/* Location: ./system/core/Output.php */ \ No newline at end of file
+/* Location: ./system/core/Output.php */