From 477bba3003cca2108c099dd944e9d707520b7011 Mon Sep 17 00:00:00 2001 From: lkddi Date: Sun, 1 Mar 2026 14:10:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=EF=BC=9A=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=A6=81=E7=94=A8=E8=AF=8D=20UTF-8=20?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 sanitizeUtf8() 私有方法: 去除 BOM、零宽字符、非法 UTF-8 字节、控制字符 防止从聊天/文档复制时混入隐藏字符导致 json_encode 失败 - batchStore() 先净化 words 和 reason 输入 - preg_split 加 /u 修饰符(完整 Unicode 支持) - 响应加 JSON_UNESCAPED_UNICODE 防中文被转义 --- .../Admin/ForbiddenUsernameController.php | 39 +++++++++++++++---- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/Admin/ForbiddenUsernameController.php b/app/Http/Controllers/Admin/ForbiddenUsernameController.php index 8af441a..a667b65 100644 --- a/app/Http/Controllers/Admin/ForbiddenUsernameController.php +++ b/app/Http/Controllers/Admin/ForbiddenUsernameController.php @@ -97,11 +97,14 @@ class ForbiddenUsernameController extends Controller 'words.required' => '请输入至少一个词语。', ]); - // 支持换行、逗号、中文逗号、空格分隔 - $rawWords = preg_split('/[\r\n,,\s]+/', $validated['words']); - $reason = trim($validated['reason'] ?? ''); + // 净化输入:去除非法 UTF-8 字节(零宽字符、BOM、控制字符等),防止 json_encode 失败 + $rawInput = $this->sanitizeUtf8($validated['words']); + $reason = $this->sanitizeUtf8(trim($validated['reason'] ?? '')); - // 过滤空串、截断过长、去重 + // 支持换行、逗号、中文逗号、空格分隔 + $rawWords = preg_split('/[\r\n,,\s]+/u', $rawInput); + + // 过滤空串、超长词、去重 $words = collect($rawWords) ->map(fn ($w) => trim($w)) ->filter(fn ($w) => $w !== '' && mb_strlen($w) <= 50) @@ -112,11 +115,11 @@ class ForbiddenUsernameController extends Controller return response()->json(['status' => 'error', 'message' => '没有有效的词语,请检查输入。'], 422); } - // 查询已存在的(批量一次查询) + // 批量查询已存在的词(一次查询) $existing = UsernameBlacklist::permanent() ->whereIn('username', $words->all()) ->pluck('username') - ->flip(); // 转为键名方便 has() 查询 + ->flip(); $now = Carbon::now(); $added = 0; @@ -124,7 +127,7 @@ class ForbiddenUsernameController extends Controller foreach ($words as $word) { if ($existing->has($word)) { - continue; // 跳过已存在 + continue; } $rows[] = [ 'username' => $word, @@ -143,7 +146,27 @@ class ForbiddenUsernameController extends Controller $skipped = $words->count() - $added; $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; } /**