summaryrefslogtreecommitdiffstats
path: root/system/core/Output.php
diff options
context:
space:
mode:
Diffstat (limited to 'system/core/Output.php')
-rw-r--r--system/core/Output.php167
1 files changed, 141 insertions, 26 deletions
diff --git a/system/core/Output.php b/system/core/Output.php
index 98deff55c..ce0500e71 100644
--- a/system/core/Output.php
+++ b/system/core/Output.php
@@ -18,7 +18,7 @@
*
* @package CodeIgniter
* @author EllisLab Dev Team
- * @copyright Copyright (c) 2008 - 2012, EllisLab, Inc. (http://ellislab.com/)
+ * @copyright Copyright (c) 2008 - 2013, EllisLab, Inc. (http://ellislab.com/)
* @license http://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
* @link http://codeigniter.com
* @since Version 1.0
@@ -143,7 +143,7 @@ class CI_Output {
* Sets the output string.
*
* @param string $output Output data
- * @return object $this
+ * @return CI_Output
*/
public function set_output($output)
{
@@ -159,7 +159,7 @@ class CI_Output {
* Appends data onto the output string.
*
* @param string $output Data to append
- * @return object $this
+ * @return CI_Output
*/
public function append_output($output)
{
@@ -187,7 +187,7 @@ class CI_Output {
*
* @param string $header Header
* @param bool $replace Whether to replace the old header value, if already set
- * @return object $this
+ * @return CI_Output
*/
public function set_header($header, $replace = TRUE)
{
@@ -211,7 +211,7 @@ class CI_Output {
*
* @param string $mime_type Extension of the file we're outputting
* @param string $charset Character set (default: NULL)
- * @return object $this
+ * @return CI_Output
*/
public function set_content_type($mime_type, $charset = NULL)
{
@@ -239,7 +239,7 @@ class CI_Output {
}
$header = 'Content-Type: '.$mime_type
- .(empty($charset) ? NULL : '; charset='.strtolower($charset));
+ .(empty($charset) ? NULL : '; charset='.$charset);
$this->headers[] = array($header, TRUE);
return $this;
@@ -308,7 +308,7 @@ class CI_Output {
*
* @param int $code Status code (default: 200)
* @param string $text Optional message
- * @return object $this
+ * @return CI_Output
*/
public function set_status_header($code = 200, $text = '')
{
@@ -322,7 +322,7 @@ class CI_Output {
* Enable/disable Profiler
*
* @param bool $val TRUE to enable or FALSE to disable
- * @return object $this
+ * @return CI_Output
*/
public function enable_profiler($val = TRUE)
{
@@ -339,7 +339,7 @@ class CI_Output {
* Profiler section display.
*
* @param array $sections Profiler sections
- * @return object $this
+ * @return CI_Output
*/
public function set_profiler_sections($sections)
{
@@ -363,7 +363,7 @@ class CI_Output {
* Set Cache
*
* @param int $time Cache expiration time in seconds
- * @return object $this
+ * @return CI_Output
*/
public function cache($time)
{
@@ -710,9 +710,7 @@ class CI_Output {
{
case 'text/html':
- $size_before = strlen($output);
-
- if ($size_before === 0)
+ if (($size_before = strlen($output)) === 0)
{
return '';
}
@@ -728,13 +726,13 @@ class CI_Output {
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);
+ $output = str_replace($s, $this->_minify_script_style($s, TRUE), $output);
}
// Minify the javascript in <script> tags.
foreach ($javascript_clean[0] as $s)
{
- $javascript_mini[] = $this->minify($s, 'text/javascript');
+ $javascript_mini[] = $this->_minify_script_style($s, TRUE);
}
// Replace multiple spaces with a single space.
@@ -780,19 +778,10 @@ class CI_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.
+ $output = $this->_minify_script_style($output);
+
break;
default: break;
@@ -801,6 +790,132 @@ class CI_Output {
return $output;
}
+ // --------------------------------------------------------------------
+
+ /**
+ * Minify Style and Script
+ *
+ * Reduce excessive size of CSS/JavaScript content. To remove spaces this
+ * script walks the string as an array and determines if the pointer is inside
+ * a string created by single quotes or double quotes. spaces inside those
+ * strings are not stripped. Opening and closing tags are severed from
+ * the string initially and saved without stripping whitespace to preserve
+ * the tags and any associated properties if tags are present
+ *
+ * Minification logic/workflow is similar to methods used by Douglas Crockford
+ * in JSMIN. http://www.crockford.com/javascript/jsmin.html
+ *
+ * KNOWN ISSUE: ending a line with a closing parenthesis ')' and no semicolon
+ * where there should be one will break the Javascript. New lines after a
+ * closing parenthesis are not recognized by the script. For best results
+ * be sure to terminate lines with a semicolon when appropriate.
+ *
+ * @param string $output Output to minify
+ * @param bool $has_tags Specify if the output has style or script tags
+ * @return string Minified output
+ */
+ protected function _minify_script_style($output, $has_tags = FALSE)
+ {
+ // We only need this if there are tags in the file
+ if ($has_tags === TRUE)
+ {
+ // Remove opening tag and save for later
+ $pos = strpos($output, '>') + 1;
+ $open_tag = substr($output, 0, $pos);
+ $output = substr_replace($output, '', 0, $pos);
+
+ // Remove closing tag and save it for later
+ $end_pos = strlen($output);
+ $pos = strpos($output, '</');
+ $closing_tag = substr($output, $pos, $end_pos);
+ $output = substr_replace($output, '', $pos);
+ }
+
+ // Remove CSS comments
+ $output = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!i', '', $output);
+
+ // Remove spaces around curly brackets, colons,
+ // semi-colons, parenthesis, commas
+ $output = preg_replace('!\s*(:|;|,|}|{|\(|\))\s*!i', '$1', $output);
+
+ // Replace tabs with spaces
+ // Replace carriage returns & multiple new lines with single new line
+ // and trim any leading or trailing whitespace
+ $output = trim(preg_replace(array('/\t+/', '/\r/', '/\n+/'), array(' ', "\n", "\n"), $output));
+
+ // Remove spaces when safe to do so.
+ $in_string = $in_dstring = $prev = FALSE;
+ $array_output = str_split($output);
+ foreach ($array_output as $key => $value)
+ {
+ if ($in_string === FALSE && $in_dstring === FALSE)
+ {
+ if ($value === ' ')
+ {
+ // Get the next element in the array for comparisons
+ $next = $array_output[$key + 1];
+
+ // Strip spaces preceded/followed by a non-ASCII character
+ // or not preceded/followed by an alphanumeric
+ // or not preceded/followed \ $ and _
+ if ((preg_match('/^[\x20-\x7f]*$/D', $next) OR preg_match('/^[\x20-\x7f]*$/D', $prev))
+ && ( ! ctype_alnum($next) OR ! ctype_alnum($prev))
+ && ! in_array($next, array('\\', '_', '$'), TRUE)
+ && ! in_array($prev, array('\\', '_', '$'), TRUE)
+ )
+ {
+ unset($array_output[$key]);
+ }
+ }
+ else
+ {
+ // Save this value as previous for the next iteration
+ // if it is not a blank space
+ $prev = $value;
+ }
+ }
+
+ if ($value === "'")
+ {
+ $in_string = ! $in_string;
+ }
+ elseif ($value === '"')
+ {
+ $in_dstring = ! $in_dstring;
+ }
+ }
+
+ // Put the string back together after spaces have been stripped
+ $output = implode($array_output);
+
+ // Remove new line characters unless previous or next character is
+ // printable or Non-ASCII
+ preg_match_all('/[\n]/', $output, $lf, PREG_OFFSET_CAPTURE);
+ $removed_lf = 0;
+ foreach ($lf as $feed_position)
+ {
+ foreach ($feed_position as $position)
+ {
+ $position = $position[1] - $removed_lf;
+ $next = $output[$position + 1];
+ $prev = $output[$position - 1];
+ if ( ! ctype_print($next) && ! ctype_print($prev)
+ && ! preg_match('/^[\x20-\x7f]*$/D', $next)
+ && ! preg_match('/^[\x20-\x7f]*$/D', $prev)
+ )
+ {
+ $output = substr_replace($output, '', $position, 1);
+ $removed_lf++;
+ }
+ }
+ }
+
+ // Put the opening and closing tags back if applicable
+ return isset($open_tag)
+ ? $open_tag.$output.$closing_tag
+ : $output;
+ }
+
}
/* End of file Output.php */