Skip to content

Instantly share code, notes, and snippets.

@meglio
Created September 17, 2012 15:08
Show Gist options
  • Save meglio/3737913 to your computer and use it in GitHub Desktop.
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
<?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