修复:批量添加禁用词 UTF-8 编码错误
- 新增 sanitizeUtf8() 私有方法: 去除 BOM、零宽字符、非法 UTF-8 字节、控制字符 防止从聊天/文档复制时混入隐藏字符导致 json_encode 失败 - batchStore() 先净化 words 和 reason 输入 - preg_split 加 /u 修饰符(完整 Unicode 支持) - 响应加 JSON_UNESCAPED_UNICODE 防中文被转义
This commit is contained in:
@@ -97,11 +97,14 @@ class ForbiddenUsernameController extends Controller
|
|||||||
'words.required' => '请输入至少一个词语。',
|
'words.required' => '请输入至少一个词语。',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// 支持换行、逗号、中文逗号、空格分隔
|
// 净化输入:去除非法 UTF-8 字节(零宽字符、BOM、控制字符等),防止 json_encode 失败
|
||||||
$rawWords = preg_split('/[\r\n,,\s]+/', $validated['words']);
|
$rawInput = $this->sanitizeUtf8($validated['words']);
|
||||||
$reason = trim($validated['reason'] ?? '');
|
$reason = $this->sanitizeUtf8(trim($validated['reason'] ?? ''));
|
||||||
|
|
||||||
// 过滤空串、截断过长、去重
|
// 支持换行、逗号、中文逗号、空格分隔
|
||||||
|
$rawWords = preg_split('/[\r\n,,\s]+/u', $rawInput);
|
||||||
|
|
||||||
|
// 过滤空串、超长词、去重
|
||||||
$words = collect($rawWords)
|
$words = collect($rawWords)
|
||||||
->map(fn ($w) => trim($w))
|
->map(fn ($w) => trim($w))
|
||||||
->filter(fn ($w) => $w !== '' && mb_strlen($w) <= 50)
|
->filter(fn ($w) => $w !== '' && mb_strlen($w) <= 50)
|
||||||
@@ -112,11 +115,11 @@ class ForbiddenUsernameController extends Controller
|
|||||||
return response()->json(['status' => 'error', 'message' => '没有有效的词语,请检查输入。'], 422);
|
return response()->json(['status' => 'error', 'message' => '没有有效的词语,请检查输入。'], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 查询已存在的(批量一次查询)
|
// 批量查询已存在的词(一次查询)
|
||||||
$existing = UsernameBlacklist::permanent()
|
$existing = UsernameBlacklist::permanent()
|
||||||
->whereIn('username', $words->all())
|
->whereIn('username', $words->all())
|
||||||
->pluck('username')
|
->pluck('username')
|
||||||
->flip(); // 转为键名方便 has() 查询
|
->flip();
|
||||||
|
|
||||||
$now = Carbon::now();
|
$now = Carbon::now();
|
||||||
$added = 0;
|
$added = 0;
|
||||||
@@ -124,7 +127,7 @@ class ForbiddenUsernameController extends Controller
|
|||||||
|
|
||||||
foreach ($words as $word) {
|
foreach ($words as $word) {
|
||||||
if ($existing->has($word)) {
|
if ($existing->has($word)) {
|
||||||
continue; // 跳过已存在
|
continue;
|
||||||
}
|
}
|
||||||
$rows[] = [
|
$rows[] = [
|
||||||
'username' => $word,
|
'username' => $word,
|
||||||
@@ -143,7 +146,27 @@ class ForbiddenUsernameController extends Controller
|
|||||||
$skipped = $words->count() - $added;
|
$skipped = $words->count() - $added;
|
||||||
$msg = "成功添加 {$added} 个词语".($skipped > 0 ? ",跳过 {$skipped} 个(已存在)" : '').'。';
|
$msg = "成功添加 {$added} 个词语".($skipped > 0 ? ",跳过 {$skipped} 个(已存在)" : '').'。';
|
||||||
|
|
||||||
return response()->json(['status' => 'success', 'message' => $msg, 'added' => $added]);
|
return response()->json(['status' => 'success', 'message' => $msg, 'added' => $added], 200, [], JSON_UNESCAPED_UNICODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 净化字符串,移除非法 UTF-8 字节及常见控制/零宽字符。
|
||||||
|
*
|
||||||
|
* @param string $str 待净化字符串
|
||||||
|
* @return string 合法的 UTF-8 字符串
|
||||||
|
*/
|
||||||
|
private function sanitizeUtf8(string $str): string
|
||||||
|
{
|
||||||
|
// 去除 BOM
|
||||||
|
$str = str_replace("\xEF\xBB\xBF", '', $str);
|
||||||
|
// 去除零宽字符(零宽空格、零宽不连字等)
|
||||||
|
$str = preg_replace('/[\x{200B}-\x{200D}\x{FEFF}\x{00AD}]/u', '', $str);
|
||||||
|
// 转换为合法 UTF-8,忽略非法字节
|
||||||
|
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
|
||||||
|
// 保底:去除控制字符(保留换行 \r\n)
|
||||||
|
$str = preg_replace('/[^\P{C}\r\n]+/u', '', $str);
|
||||||
|
|
||||||
|
return $str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user