前端效能優化中,CSS 內引用的圖片、字型等靜態資源需長期快取(`Cache-Control: max-age=31536000`),但更新時必須強制瀏覽器下載新版。常見做法是在 URL 後附加版本參數(如 `bg.png?v=202401151200`)。本文實作 CSSUpdate 類別,掃描 CSS 模板目錄,自動為指定副檔名的 URL 附加時間戳,輸出至正式目錄,實現零手工維護的版本控制。
<?php
class CSSUpdate {
private $csstmpl_path = null;
private $css_path = null;
private $replacetags = [];
private $search_child = false;
private $convert_num = 0;
private $is_ready = 0;
public function __construct($csstmpl_path, $css_path, array $replacetags = [], $search_child = false) {
if (!is_dir($csstmpl_path) || !is_dir($css_path) || empty($replacetags)) {
$this->is_ready = 0;
} else {
$this->csstmpl_path = $csstmpl_path;
$this->css_path = $css_path;
$this->replacetags = $replacetags;
$this->search_child = $search_child;
$this->is_ready = 1;
}
}
public function update() {
if ($this->is_ready == 0) {
$this->response('csstmpl or csspath or replacetags error');
return;
}
$this->traversing($this->csstmpl_path);
$this->response('convert num: ' . $this->convert_num);
}
private function traversing($path) {
$handle = opendir($path);
while (($file = readdir($handle)) !== false) {
if ($file === '.' || $file === '..') continue;
$curfile = $path . '/' . $file;
if (is_dir($curfile)) {
if ($this->search_child) {
$this->traversing($curfile);
}
} elseif ($this->checkExt($curfile)) {
$dfile = str_replace($this->csstmpl_path, $this->css_path, $curfile);
$this->create($curfile, $dfile);
$this->response($curfile . ' convert to ' . $dfile . ' success');
$this->convert_num++;
}
}
closedir($handle);
}
private function checkExt($file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
return $ext === 'css';
}
private function create($tmplfile, $dfile) {
$content = file_get_contents($tmplfile);
foreach ($this->replacetags as $tag) {
// 替換 url(...) 內的指定副檔名
$content = str_replace($tag, $tag . '?' . date('YmdHis'), $content);
}
$dir = dirname($dfile);
if (!is_dir($dir)) mkdir($dir, 0755, true);
file_put_contents($dfile, $content);
}
private function response($msg) {
echo $msg . "
\n";
}
}
?>
<?php
require 'CSSUpdate.class.php';
define('ROOT_PATH', dirname(__FILE__));
$csstmpl_path = ROOT_PATH . '/csstmpl'; // 模板目錄(開發維護)
$css_path = ROOT_PATH . '/css'; // 正式目錄(Web 存取)
$replacetags = ['.png', '.jpg', '.gif', '.woff', '.woff2', '.ttf', '.eot', '.svg'];
$css = new CSSUpdate($csstmpl_path, $css_path, $replacetags, true); // true=掃描子目錄
$css->update();
| 階段 | 內容 |
|---|---|
模板檔 csstmpl/style.css | .logo { background: url(../img/logo.png); } |
| 執行 update() | 掃描到 `.png`,替換為 `.png?20240115120000` |
輸出檔 css/style.css | .logo { background: url(../img/logo.png?20240115120000); } |