应使用 mb_strlen($str, 'UTF-8') 进行中文等多字节字符长度校验,因 strlen() 按字节计数会导致中文误判;需配合 trim()、严格 SQL 模式及前端 maxlength 辅助验证。

PHP后端验证 strlen() 和 mb_strlen() 怎么选
单纯用 strlen() 限制中文会出错,因为它按字节计数,一个 UTF-8 中文占 3 字节,strlen('你好') === 6,但你实际想限制的是“2 个字符”,不是 “6 个字节”。必须用 mb_strlen($str, 'UTF-8'),并确保 PHP 已启用 mbstring 扩展(大多数现代环境默认开启)。
常见错误现象:strlen() 把 4 个汉字判成超长(比如设了 max=10,结果 4 个汉字就触发截断或报错);提交含 emoji 的表单时更易崩,因为 emoji 多为 4 字节 UTF-8 序列。
- 表单字段如昵称、标题、简介等需按“字符数”约束,一律用
mb_strlen($input, 'UTF-8') - 若确定只处理 ASCII(如用户名仅限英文数字下划线),
strlen()更快,但场景极窄 - 检查前先
trim()去首尾空格,否则空格也计入长度
HTML 表单的 maxlength 属性为什么不能信
maxlength 是纯前端限制,用户禁用 JS 或用 curl/postman 直接发包就能绕过。它只起提示和基础体验作用,绝不能替代后端校验。
使用场景:配合 JS 做实时字数反馈,或防止用户误输过长内容后被后端直接拒收——但后端仍要完整验证。
立即学习“PHP免费学习笔记(深入)”;
-
对单行文本有效,但对同样适用 -
maxlength按 Unicode 码点计数(现代浏览器),和mb_strlen()行为基本一致,但不处理换行符差异(如\r\n算 2 字符) - 不要在
maxlength里写变量,如maxlength="= $max ?>"—— 若 $max 未过滤可能引 XSS,应先intval()强转
如何在 PHP 表单处理中统一做长度校验
别在每个 $_POST 字段后单独写 if (mb_strlen(...) > 20) { ... },容易漏、难维护。建议封装成校验函数或使用简单规则数组驱动。
$rules = [
'title' => ['max' => 50, 'type' => 'string'],
'content' => ['max' => 1000, 'type' => 'text'],
'nickname' => ['max' => 16, 'type' => 'string']
];
$errors = [];
foreach ($rules as $field => $rule) {
$value = $_POST[$field] ?? '';
if (mb_strlen(trim($value), 'UTF-8') > $rule['max']) {
$errors[$field] = "最多 {$rule['max']} 个字符";
}
}
- 注意:
$_POST值可能为null或数组(如多选框),需提前判断类型,避免mb_strlen(null)警告 - 若字段允许为空,校验前加
if ($value === '' || $value === null) continue; - 数据库字段长度也要同步匹配,比如 MySQL
VARCHAR(50),PHP 就不应允许超过 50 字符入库
MySQL 存储时被截断却没报错?那是 sql_mode 在作怪
PHP 校验通过了,但插入数据库时中文还是被悄悄截断,大概率是 MySQL 运行在宽松模式(如缺失 STRICT_TRANS_TABLES)。此时超长字符串会被静默截断,且不抛异常。
验证方式:执行 SELECT @@sql_mode;,确认结果包含 STRICT_TRANS_TABLES。不包含就需调整配置或连接时设置:
$pdo = new PDO($dsn, $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_INIT_COMMAND => "SET sql_mode='STRICT_TRANS_TABLES'"
]);
- 即使开了严格模式,仍要校验——因为截断发生在 SQL 层,而业务逻辑应在数据进入 SQL 前就拒绝
- 用
CHAR_LENGTH()(非LENGTH())查数据库中实际字符数,CHAR_LENGTH('你好') == 2 - 如果用 Laravel / Symfony 等框架,其 ORM 通常自带长度验证,但底层仍依赖上述原则











