%PDF- %PDF-
| Direktori : /home/lightco1/luminero.com.au/plugins/system/jsnmobilize/libraries/joomlashine/response/ |
| Current File : /home/lightco1/luminero.com.au/plugins/system/jsnmobilize/libraries/joomlashine/response/minify.php |
<?php
/**
* @version $Id$
* @package JSN_Mobilize
* @subpackage SystemPlugin
* @author JoomlaShine Team <support@joomlashine.com>
* @copyright Copyright (C) 2012 JoomlaShine.com. All Rights Reserved.
* @license GNU/GPL v2 or later http://www.gnu.org/licenses/gpl-2.0.html
*
* Websites: http://www.joomlashine.com
* Technical Support: Feedback - http://www.joomlashine.com/contact-us/get-support.html
*/
// No direct access to this file
defined('_JEXEC') or die('Restricted access');
// Import Joomla file library
jimport('joomla.filesystem.file');
/**
* Class for minifying assets loaded in HTML response body.
*
* @package JSN_Mobilize
* @subpackage SystemPlugin
* @since 1.0.0
*/
class JSNResponseMinify
{
/**
* Minify all stylesheets found in response body.
*
* @param string $path Absolute path to the directory for storing minified stylesheet.
* @param string $responseBody Generated HTML response body.
* @param boolean $setNewResponse Set new response body directly or return as string.
*
* @return mixed
*/
public static function css($path, $responseBody = '', $setNewResponse = true)
{
// Initialize reponse body
!empty($responseBody) OR $responseBody = JResponse::getBody();
// Get all stylesheets loaded in reponse body
if (preg_match_all('#[\r\n\s\t]*<link([^>]+)? type=("|\')text/css("|\')([^>]+)?>#i', $responseBody, $matches, PREG_SET_ORDER))
{
// Group stylesheet by media type
foreach ($matches AS $match)
{
if (strpos($match[0], ' href=') === false)
{
continue;
}
// Get stylesheet media type
if (preg_match('/media=("|\')([^"\']+)("|\')/i', $match[0], $media))
{
$media = $media[2];
}
else
{
$media = 'all';
}
// Get link to stylesheet
if (preg_match('/href=("|\')([^"\']+)("|\')/i', $match[0], $link))
{
// Store stylesheet info for minify later
$stylesheets[$media][$match[0]] = $link[2];
}
}
}
// Check if minification file already exists
isset($stylesheets) OR $stylesheets = array();
foreach ($stylesheets AS $media => $files)
{
// Generate minification file path
$minifiedFile = $path . DS . 'css_' . md5(json_encode($files)) . '.php';
if (is_readable($minifiedFile))
{
// Generate replacement
$replace = str_replace('\\', '/', str_replace(JPATH_ROOT, JURI::root(true), $minifiedFile));
$replace = '<link media="' . $media . '" type="text/css" href="' . $replace . '" rel="stylesheet" />';
// Update response body
self::updateResponseBody($responseBody, $replace, array_keys($files));
// Do not minify these stylesheets again
unset($stylesheets[$media]);
}
}
if (count($stylesheets))
{
// Read stylesheets
foreach ($stylesheets AS $media => $files)
{
foreach ($files AS $tag => $file)
{
if (substr($file, 0, 1) == '/')
{
// Get absolute file path
$file = str_replace(JURI::root(true), JPATH_ROOT, $file);
if (!($content = JFile::read($file)))
{
// Convert to full file URI
$file = JURI::root() . $file;
}
}
// If remote file, get its content via HTTP client
if (substr($file, 0, 5) == 'http:' OR substr($file, 0, 6) == 'https:')
{
$http = new JHttp;
$content = $http->get($file);
if (!empty($content->body))
{
$content = $content->body;
}
}
// $JVersion = new JVersion;
// $JVersion = $JVersion->getShortVersion();
// Look for all relative path in file content
if (preg_match_all('/url\(("|\')?([^"\'\)]+)("|\')?\)/i', $content, $matches, PREG_SET_ORDER))
{
foreach ($matches AS $match)
{
// Preset replacement
$replace = (substr($file, 0, 5) == 'http:' OR substr($file, 0, 6) == 'https:')
? dirname($file)
: dirname(str_replace(JPATH_ROOT, JURI::root(true), $file));
if (substr($match[2], 0, 1) == '.')
{
foreach (explode('/', $match[2]) AS $level)
{
if ($level == '..')
{
$replace = dirname($replace);
}
elseif ($level != '.')
{
$replace .= "/{$level}";
}
}
}
elseif (!preg_match('#^(https?://|/)#i', $match[2]))
{
$replace .= "/{$match[2]}";
}
// Replace relative path with absolute equivalent
$content = str_replace($match[0], str_replace($match[2], $replace, $match[0]), $content);
}
}
// Store file content for combine later
$stylesheets[$media][$tag] = $content;
}
}
// Combine files and set compress header for combined file
$minified = self::process($path, 'css', $stylesheets, true);
// Update response body
foreach ($stylesheets AS $media => $files)
{
// Generate replacement
$replace = str_replace('\\', '/', str_replace(JPATH_ROOT, JURI::root(true), $minified[$media]));
$replace = '<link media="' . $media . '" type="text/css" href="' . $replace . '" rel="stylesheet" />';
// Update response body
self::updateResponseBody($responseBody, $replace, array_keys($files));
}
}
// Set new response body directly or return it?
return $setNewResponse ? JResponse::setBody($responseBody) : $responseBody;
}
/**
* Minify all Javascript files found in response body.
*
* @param string $path Absolute path to the directory for storing minified script.
* @param string $responseBody Generated HTML response body.
* @param boolean $setNewResponse Set new response body directly or return as string.
*
* @return mixed
*/
public static function js($path, $responseBody = '', $setNewResponse = true)
{
// Initialize reponse body
!empty($responseBody) OR $responseBody = JResponse::getBody();
// Get all script files loaded in reponse body
if (preg_match_all('#[\r\n\s\t]*<script([^>]+)? type=("|\')text/javascript("|\')([^>]+)?>([\s\t\r\n]+)?</script>#i', $responseBody, $matches, PREG_SET_ORDER))
{
foreach ($matches AS $match)
{
if (strpos($match[0], ' src=') === false)
{
continue;
}
// Get link to script file
if (preg_match('/src=("|\')([^"\']+)("|\')/i', $match[0], $link))
{
// Store script file info for minify later
$scripts[$match[0]] = $link[2];
}
}
}
// Check if minification file already exists
isset($scripts) OR $scripts = array();
if (count($scripts))
{
// Generate minification file path
$minifiedFile = $path . DS . 'js_' . md5(json_encode($scripts)) . '.php';
if (is_readable($minifiedFile))
{
// Generate replacement
$replace = str_replace('\\', '/', str_replace(JPATH_ROOT, JURI::root(true), $minifiedFile));
$replace = '<script type="text/javascript" src="' . $replace . '"></script>';
// Update response body
self::updateResponseBody($responseBody, $replace, array_keys($scripts));
// Do not minify these stylesheets again
unset($scripts);
}
}
if (isset($scripts))
{
// Combine files and set compress header for combined file
$minified = self::process($path, 'js', array(0 => $scripts));
// Generate replacement
$replace = str_replace('\\', '/', str_replace(JPATH_ROOT, JURI::root(true), $minified[0]));
$replace = '<script type="text/javascript" src="' . $replace . '"></script>';
// Update response body
self::updateResponseBody($responseBody, $replace, array_keys($scripts));
}
// Set new response body directly or return it?
return $setNewResponse ? JResponse::setBody($responseBody) : $responseBody;
}
/**
* Combine files and set compress header for combined file.
*
* Below is an example of <b>$files</b> parameter to minify some stylesheets:
*
* <pre>array(
* 'screen' => array('screen1.css', 'screen2.css'),
* 'print' => array('print1.css', 'print2.css')
* )</pre>
*
* And the return value after execution this method is:
*
* <pre>array(
* 'screen' => 'absolute/path/to/combined/file',
* 'print' => 'absolute/path/to/combined/file'
* )</pre>
*
* For combine Javascript files, the <b>$files</b> parameter look like below:
*
* <pre>array(
* 0 => array('script1.js', 'script2.js', 'script3.js', 'script4.js')
* )</pre>
*
* @param string $path Absolute path to the directory for storing minified file.
* @param string $type Either 'css' or 'js'.
* @param array $list Array of files to combine.
* @param boolean $isContent Set to true if $files contains file content instead of file path.
*
* @return array
*/
protected static function process($path, $type, $list, $isContent = false)
{
// Combine file content
foreach ($list AS $media => $files)
{
foreach ($files AS $file)
{
isset($minified[$media]) OR $minified[$media] = '';
if ($isContent)
{
$tmp = $file;
}
else
{
// Read file content
if (substr($file, 0, 1) == '/')
{
// Get absolute file path
$file = str_replace(JURI::root(true), JPATH_ROOT, $file);
if (!($tmp = JFile::read($file)))
{
// Convert to full file URI
$file = JURI::root() . $file;
}
}
// If remote file, get its content via HTTP client
if (substr($file, 0, 5) == 'http:' OR substr($file, 0, 6) == 'https:')
{
$http = new JHttp;
$tmp = $http->get($file);
if (!empty($tmp->body))
{
$tmp = $tmp->body;
}
}
}
$minified[$media] .= "\n{$tmp}";
}
}
// Save combined file
foreach ($list AS $media => $files)
{
// Generate minification file path
$minifiedFile = $path . DS . $type . '_' . md5(json_encode($files)) . '.php';
// Add header to compress asset file
$minified[$media] = '<?php
// Initialize ob_gzhandler function to send and compress data
ob_start("ob_gzhandler");
// Send the requisite header information and character set
header("content-type: ' . ($type == 'js' ? 'text/javascript' : 'text/css') . '; charset: UTF-8");
// Check cached credentials and reprocess accordingly
header("cache-control: must-revalidate");
// Set variable for duration of cached content
$offset = 365 * 60 * 60;
// Set variable specifying format of expiration header
$expire = "expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";
// Send cache expiration header to the client broswer
header($expire);
?>
' . self::cleanCode($minified[$media], $type);
// Write minification file
JFile::write($minifiedFile, $minified[$media]);
// Store path to minification file
$minified[$media] = $minifiedFile;
}
return $minified;
}
/**
* Clean Javascript or CSS source code.
*
* @param string $code The source code to minify.
* @param string $type The type of code, 'css' or 'js'.
*
* @return string The minified code.
*/
protected static function cleanCode($code, $type)
{
// Initialize variable
$minified = $code;
// Replace multiple new-line with just one
$minified = preg_replace('/[\r\n]{2,99}/', "\n", $minified);
// Replace multiple white-space with just one
$minified = preg_replace('/[^\S\n]{2,99}/', ' ', $minified);
// Minify CSS code
if ($type == 'css')
{
// Remove all comments
$minified = preg_replace('#[\s\t\r\n]+/\*(.|[\r\n])*?\*/#', '', $minified);
// Remove unnecessary white-space/new-line
$minified = preg_replace('/\s+(\{|\})/', '\1', $minified);
$minified = preg_replace('/([\{:;])\s+/', '\1', $minified);
// Remove unnecessary semi-colon
$minified = str_replace(';}/', '}', $minified);
// Remove all remaining unnecessary white-space/new-line
$minified = preg_replace('/\n\s*/', '', $minified);
}
return $minified;
}
/**
* Update HTML response body.
*
* @param string &$responseBody Generated HTML response body.
* @param string $replacement Tag to inject into response body.
* @param array $tags Array of tags to remove from response body.
*
* @return void
*/
protected static function updateResponseBody(&$responseBody, $replacement, $tags)
{
// Initialize variable
$first = true;
// Do replacement
foreach ((array) $tags AS $tag)
{
if ($first)
{
// Replace old tag with new tag
$responseBody = str_replace($tag, "\n\t{$replacement}", $responseBody);
$first = false;
}
else
{
// Remove old tag from response body
$responseBody = str_replace($tag, '', $responseBody);
}
}
}
}