Created
September 17, 2012 15:08
-
-
Save meglio/3737913 to your computer and use it in GitHub Desktop.
css.php joins and minifies css files from html template into cached.css and controls Cache-Control headers based on mtime of all files engaged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
header('Content-Type: text/css'); | |
$cacheFile = __DIR__.'/css/cached.css'; | |
$listFile = __DIR__.'/css/cached-list.txt'; | |
$htmlFile = __DIR__.'/tmpl/web/html5.twig'; | |
$htmlTime = filemtime($htmlFile); | |
$cacheTime = file_exists($cacheFile)? filemtime($cacheFile) : 0; | |
# Update list of cached css files if it does not exist yet or if html file changed | |
if (!file_exists($listFile) || filemtime($listFile) < $htmlTime) | |
{ | |
$html = file_get_contents($htmlFile); | |
preg_match('|<head.+</head\s*?>|is', $html, $m); | |
$body = $m[0]; | |
# http://regexr.com?32712 | |
$regex = <<<REGEX | |
/<link[^>]+href\s*=\s*('|")(?P<link1>[^'"]+?\.css)('|")|{{\s*css\s*\(\s*('|")(?P<link2>[^)'"]+)('|")\s*\)\s*}}/is | |
REGEX; | |
preg_match_all($regex, $body, $matches, PREG_SET_ORDER); | |
$files = []; | |
foreach($matches as $match) | |
{ | |
if (isset($match['link1']) && !empty($match['link1'])) | |
$link = $match['link1']; | |
elseif (isset($match['link2']) && !empty($match['link2'])) | |
$link = $match['link2']; | |
else | |
continue; | |
if (strtolower(substr($link, -4)) == '.css' && file_exists($filePath = __DIR__.$link)) | |
$files[] = $filePath; | |
} | |
if (file_exists($listFile)) | |
unlink($listFile); | |
file_put_contents($listFile, join("\n", $files)); | |
$forceUpdate = true; | |
} | |
if (!file_exists($cacheFile)) | |
$forceUpdate = true; | |
# ?update=1 in DEBUG mode forces update, even if cached.css already exists | |
if (!isset($forceUpdate) && file_exists($cacheFile) && array_key_exists('update', $_GET)) | |
{ | |
$configFile = __DIR__.'/proj/config.php'; | |
if (file_exists($configFile) && is_readable($configFile)) | |
{ | |
require $configFile; | |
if (defined('DEBUG') && DEBUG) | |
$forceUpdate = true; | |
} | |
} | |
# Update if filemtime() for any of files from the list is changed | |
if (!isset($forceUpdate)) | |
{ | |
if (!isset($files)) | |
$files = file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); | |
$maxTime = 0; | |
foreach($files as $f) | |
$maxTime = max($maxTime, filemtime($f)); | |
if ($maxTime > $cacheTime) | |
$forceUpdate = true; | |
} | |
# Generate cached.css | |
if (isset($forceUpdate)) | |
{ | |
require(__DIR__.'/proj/utils/CSSmin.php'); | |
$filters = array ( | |
"ImportImports" => false, | |
"RemoveComments" => true, | |
"RemoveEmptyRulesets" => true, | |
"RemoveEmptyAtBlocks" => true, | |
"ConvertLevel3AtKeyframes" => array("RemoveSource" => false), | |
"ConvertLevel3Properties" => true, | |
"Variables" => true, | |
"RemoveLastDelarationSemiColon" => true | |
); | |
$plugins = array ( | |
"Variables" => true, | |
"ConvertFontWeight" => true, | |
"ConvertHslColors" => true, | |
"ConvertRgbColors" => true, | |
"ConvertNamedColors" => true, | |
"CompressColorValues" => true, | |
"CompressUnitValues" => true, | |
"CompressExpressionValues" => true | |
); | |
if (!isset($files)) | |
$files = file($listFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); | |
$css = ''; | |
foreach($files as $file) | |
{ | |
# Try to find .min file - use already minified files if they are found; for example, it is good for files of frameworks | |
if (preg_match('|\.min\.css$|is', $file)) | |
$minified = file_get_contents($file); | |
else | |
{ | |
$minFile = preg_replace('|\.css$|is', '.min.css', $file, 1); | |
if (file_exists($minFile)) | |
$minified = file_get_contents($minFile); | |
else | |
$minified = CssMin::minify(file_get_contents($file), $filters, $plugins); | |
} | |
$css .= $minified."\n"; | |
} | |
if (file_exists($cacheFile)) | |
unlink($cacheFile); // unlink clears the cache automatically | |
file_put_contents($cacheFile, $css); | |
$cacheTime = filemtime($cacheFile); | |
} | |
# Output | |
if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $cacheTime) | |
{ | |
header('HTTP/1.1 304 Not Modified'); | |
die(); | |
} | |
header('Last-Modified: '.gmdate('D, d M Y H:i:s', $cacheTime).' GMT'); | |
$offset = 3600 * 24 * 30; | |
header("Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . ' GMT'); | |
header("Cache-Control: public, max-age=3600, must-revalidate"); | |
die(file_get_contents($cacheFile)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment