php 8.3 校验字符串长度须先用 mb_strlen($str, 'utf-8') 判断字符数是否超 varchar(n),再按 $charlen * 4 估算最大字节数,对比字段真实字节上限,双重校验防静默截断。

PHP 8.3 判断字符串长度是否超出数据库限制,核心是**按字符数校验 + 按字节上限兜底**,不能只看 strlen() 或只比对 VARCHAR(n) 的 n 值。尤其在 utf8mb4 编码下,一个 emoji 或生僻字占 4 字节,但仍是 1 个字符——数据库按字符数截断(如 VARCHAR(255) 最多存 255 个字符),而底层存储受字节总量约束(255 × 4 = 1020 字节)。错用函数或忽略编码,会导致“明明没超字符数却写不进”或“看似安全实则被静默截断”。
必须用 mb_strlen() 校验字符数
PHP 默认的 strlen() 返回字节数,对 UTF-8 中文、emoji 严重失真:
"你好" → strlen() 返回 6,mb_strlen("你好", "UTF-8") 才返回 2。
所有长度判断逻辑都应基于用户感知的“字符个数”,也就是数据库字段定义的字符上限(如 VARCHAR(100) 表示最多 100 个字符)。
- 统一调用
mb_strlen($str, 'UTF-8'),第二个参数不可省略 - 确保
mbstring扩展已启用(PHP 8.3 默认开启,但可加extension_loaded('mbstring')防御性检查) - 对空值或非字符串类型先过滤:
!is_string($str) || $str === ''
同步估算最大可能字节数
字符数合规 ≠ 能安全入库。utf8mb4 下单字符最多占 4 字节,所以 255 字符理论上最多消耗 1020 字节。若字段真实字节上限低于此值(比如表定义混乱、连接字符集不一致),仍会报错 SQLSTATE[22001]。
- 计算公式:
$charLen = mb_strlen($str, 'UTF-8'); $maxBytes = $charLen * 4; - 查清目标字段的真实字节上限:执行
SHOW FULL COLUMNS FROM table_name LIKE 'column_name';,看 Collation 是否为utf8mb4_*;再结合建表语句中该字段的VARCHAR(n)和字符集推算(如 utf8mb4 → n × 4) - 不要硬编码 1020——不同字段、不同字符集(如 legacy utf8 是 ×3)、甚至某些 MySQL 版本的行格式会影响实际可用字节数
入库前做双重校验 + 连接层防护
仅靠 PHP 层判断不够,要和数据库协同防御:
- PDO 或 MySQLi 连接时强制指定字符集:
charset=utf8mb4,避免客户端以 latin1 解析导致隐式转换 - 启用 MySQL 严格模式(
STRICT_TRANS_TABLES),让超长写入抛出异常而非静默截断 - 业务代码中组合判断:
if (mb_strlen($str, 'UTF-8') > $maxChars || ($charLen * 4) > $columnMaxBytes) { throw new InvalidArgumentException("字符串超出字段限制"); } - 插入失败时捕获
PDOException并检查$e->getCode() === '22001',用于日志归因或降级处理
补充:防乱码截断与输入清洗
长度判断只是第一步,后续操作也需配套:
- 截取要用
mb_substr($str, 0, $limit, 'UTF-8'),不是substr(),否则中文/emoji 中间切断会输出乱码 - 接收用户输入后先清理:
$clean = trim(preg_replace('/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/u', '', $str));,去掉控制字符和零宽空格,避免它们虚增字节数 - 用
mb_check_encoding($str, 'UTF-8')验证是否真为合法 UTF-8,防止“假中文”字节流干扰判断
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











