HEX颜色校验应使用Laravel原生regex /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/,支持#abc、#123456、#aabbccdd,拒绝#1234等非法格式;模型中用setColorAttribute统一转小写并存入varchar(9)字段;API响应通过Resource标准化为6位小写HEX。

验证请求体中的颜色字段是否为合法 HEX 格式
HEX 颜色校验最常见也最容易翻车——你以为 #fff 合法,但 Laravel 默认的 regex 规则可能不认;#1234567(带 alpha)看似像 HEX,其实多数前端库不支持,后端硬接会埋坑。
推荐用 Laravel 原生 regex + 显式分组,不依赖第三方包:
['color' => 'required|regex:/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/']
-
#abc、#ABC、#123456、#aabbccdd全部匹配 - 拒绝
#1234(4位)、#ggg(非法字符)、rgb(0,0,0)(不是 HEX) - 注意:Laravel 9+ 的
regex默认启用 PCRE2,无需额外加u或i修饰符 - 若用在 Form Request 中,建议把正则提成常量,避免散落多处难维护
兼容 RGB 和 RGBA 字符串的松散校验
前端传 rgb(255, 0, 0) 或 rgba(0, 0, 0, 0.5) 很常见,但直接塞进数据库或传给 CSS 处理器前,得先确认它真能被解析,而不是靠 JS 侥幸渲染成功。
别用正则硬刚所有 RGB 变体——容易漏空格、小数、百分比写法。更稳的做法是:用 PHP 内置函数试探解析:
if (!is_null(filter_var($value, FILTER_VALIDATE_REGEXP, ['options' => ['regexp' => '/^rgb\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*\)$/']]))) {
// 简单 rgb(0,123,255) 校验
}
- 上面只覆盖基础整数 RGB,不处理 rgba、百分比、空格混用等边界情况
- 真正要全兼容,建议封装一个辅助方法,调用
sscanf()或正则捕获后逐项判断范围:0–255对应 R/G/B,0.0–1.0对应 alpha - 注意:
filter_var()对rgba()无原生支持,强行扩展正则易出错,不如交给专用库如spatie/color——但它不处理字符串输入,需先剥离rgba(...)括号内容
在 Eloquent 模型中自动标准化颜色值
存进数据库前统一转成小写 HEX(如 #ffffff),能省掉后续大量格式判断,也避免 #FFF 和 #fff 被当成不同值。
利用模型的 set*Attribute 方法做归一化:
public function setColorAttribute($value)
{
if (preg_match('/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6}|[0-9A-Fa-f]{8})$/', $value)) {
$this->attributes['color'] = strtolower($value);
} else {
throw new InvalidArgumentException('Invalid HEX color format');
}
}
- 别在
get*Attribute里转——读取时不该改原始值,且可能触发多次转换 - 如果允许 RGB 输入,这里就得先尝试解析再转 HEX,但要注意 alpha 通道丢失风险(HEX 不含透明度)
- 数据库字段建议用
varchar(9):够存#rrggbbaa,又比text更明确语义
API 响应中返回颜色字段时的格式一致性控制
前端反复问“为什么有的接口返 #fff,有的返 #ffffff”,本质是后端没约定输出规范。Laravel 的 API Resource 是最自然的拦截点。
在 Resource 中强制输出 6 位 HEX(补零、转小写、去简写):
public function toArray(Request $request): array
{
return [
'color' => $this->when($this->color, fn () => $this->normalizeHex($this->color)),
];
}
protected function normalizeHex(string $hex): string
{
$hex = ltrim($hex, '#');
if (strlen($hex) === 3) {
$hex = implode('', array_map(fn($c) => $c.$c, str_split($hex)));
}
return '#'.strtolower($hex);
}
- 不建议在数据库层做转换——迁移成本高,且历史数据可能已混杂格式
- 如果业务需要保留原始输入(比如审计用途),就该另存一个
color_raw字段,而非覆盖 - 这个 normalize 逻辑必须和存入时的校验逻辑对齐,否则会出现“存进去是 #abc,取出来是 #aabbcc”,但中间环节误判为变更


















