Laravel如何校验Gmail存在以规避`.`、`+`字符导致的重复注册问题
基于Laravel实现防Gmail别名重复的邮箱存在性验证
核心实现思路
Gmail 别名的核心特征是仅对@gmail.com和@googlemail.com后缀的邮箱生效:用户名中.会被完全忽略,+之后的所有后缀内容会被自动截断。我们只需要提前对输入邮箱做标准化归一处理,再用归一化后的结果做存在性校验即可,同时要注意不要对其他邮箱服务商的地址做额外处理,避免误伤正常规则。
具体实现步骤
1. 编写邮箱标准化辅助函数
可以在项目中新增通用辅助方法,用于处理邮箱归一化:
if (! function_exists('normalize_email')) { function normalize_email(string $email): string { // 统一转为小写,避免大小写差异导致的重复 $email = strtolower($email); // 拆分用户名和域名 [$username, $domain] = explode('@', $email, 2); // 仅对Gmail公开域名做特殊处理 if (in_array($domain, ['gmail.com', 'googlemail.com'])) { // 移除+及之后的所有内容 $username = strstr($username, '+', true) ?: $username; // 移除用户名中所有的. $username = str_replace('.', '', $username); } return sprintf('%s@%s', $username, $domain); } }
2. 新增标准化邮箱存储字段
需要在用户表中新增normalized_email字段用于唯一校验,原始邮箱字段保留用于给用户发送邮件等业务场景,避免篡改用户提交的原始邮箱。
迁移文件示例:
Schema::table('users', function (Blueprint $table) { $table->string('normalized_email')->unique()->after('email'); });
用户注册写入数据时,同步把标准化后的邮箱存入该字段。
3. 替换原有exists验证规则
不再直接用原始邮箱做exists校验,改为用标准化后的邮箱查询normalized_email字段:
// 注册场景的验证规则示例 $validated = $request->validate([ 'email' => [ 'required', 'email', // 自定义校验逻辑,替换原有exists:users,email function ($attribute, $value, $fail) { $normalizedEmail = normalize_email($value); if (\App\Models\User::where('normalized_email', $normalizedEmail)->exists()) { $fail('该邮箱地址已被注册'); } }, ], // 其他验证规则... ]);
扩展说明
如果需要支持企业版G Suite的自定义域名,可自行在辅助函数的Gmail域名判断列表中添加对应域名即可。
内容的提问来源于stack exchange,提问作者Thinh Nguyen
相关产品推荐
相关产品推荐

