用 preg_replace 替换 css/html 中的十六进制颜色值需匹配 #fff 和 #ffffff 等格式,推荐正则 /#([0-9a-fa-f]{3}|[0-9a-fa-f]{6})/;rgb()/rgba() 需上下文约束防误替;注意编码转换、大文件流处理、临时文件备份及哈希校验。

用 preg_replace 替换 CSS/HTML 中的十六进制颜色值
PHP 本身没有专用于“替换颜色值”的内置函数,得靠正则匹配 + preg_replace 实现。关键在于写对颜色值的模式:既要覆盖 #fff、#ffffff、rgb(255, 100, 50),又不能误伤类名或数字。推荐用这个模式:/#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})/ 匹配简写和全写十六进制色值。
实际操作时注意:
- 文件读取要用
file_get_contents,别用fread忘记处理编码,UTF-8 文件里中文注释可能被截断 - 替换后必须用
file_put_contents写回,且建议加LOCK_EX防并发写坏 - 如果目标是 CSS 文件,注意不要匹配到
background: #123;里的#123后面跟着分号,但也要兼容空格、换行、斜杠注释等边界情况
替换 rgb() 和 rgba() 需要更谨慎的正则
rgb(255, 0, 128) 类型不能靠简单数字匹配,否则会把 margin: 10px 0 5px 里的 0 也当颜色换掉。推荐用带上下文约束的模式:/rgb\(s*(\d{1,3})s*,s*(\d{1,3})s*,s*(\d{1,3})s*\)/,其中 s* 匹配任意空白(包括换行)。
常见坑点:
立即学习“PHP免费学习笔记(深入)”;
-
rgba()第四个参数是小数或百分比,比如rgba(0,0,0,0.5)或rgba(0,0,0,50%),需额外写分支匹配,否则只替换了前三个数,第四个留着就语法错误 - 有些 CSS 预处理器(如 Sass)支持
rgb($r, $g, $b)变量调用,这种不能动,否则编译失败 —— 建议先过滤掉含$或@的行再处理 - 浏览器兼容性上,
hsl()也得考虑,但多数项目只改 hex 和 rgb,先聚焦这两类更稳妥
批量处理多个文件时,避免硬编码路径和递归过深
用 glob 比 scandir 更直接,比如找所有 CSS 和 HTML:glob(__DIR__ . '/assets/**/*.{css,html}', GLOB_BRACE)。但要注意 ** 在 PHP 5.6+ 才支持,老环境得用 RecursiveIteratorIterator。
执行替换前务必做三件事:
- 用
pathinfo($file, PATHINFO_EXTENSION)过滤出css、html、php等文本文件,跳过png、jpg等二进制文件(否则会损坏) - 对每个文件内容做
mb_detect_encoding检查,非 UTF-8 的(如 GBK)要先转码再替换,否则正则乱码匹配失败 - 替换后用
md5_file($file)对比前后哈希,确认没意外修改其他字符(比如 BOM 或换行符)
线上环境慎用原地替换,优先生成备份再覆盖
直接 file_put_contents($file, $newContent) 风险极高:若正则写错、内存溢出或磁盘满,文件可能变空或截断。必须加保护逻辑:
- 先写入临时文件:
$tmpFile = $file . '.tmp',成功后再rename($tmpFile, $file) - 同时保留上一版备份:
copy($file, $file . '.bak.' . date('Ymd-His')),出问题能秒恢复 - 如果文件大于 2MB,别一次性
file_get_contents,改用stream_filter_append边读边替换,否则 OOM
颜色值替换看着简单,真正上线前最容易翻车的是编码判断和大文件处理 —— 尤其混合了 UTF-8 和 GBK 的老项目,漏掉一个 mb_convert_encoding 就整批文件变乱码。











