PHP 7.1 session截断主因是serialize_handler=php用|分隔导致解析提前终止,应改用php_serialize;文件存储可能因I/O失败静默丢数据;strlen误判UTF-8多字节字符长度造成“假截断”。

session.serialize_handler 配置导致序列化截断
PHP 7.1 默认 session.serialize_handler 是 php,它用竖线 | 分隔键值,且对值长度不做校验。当字符串含未转义的 | 或 !(比如 JSON 字符串、base64 编码内容),php 反序列化器会在第一个非法分隔符处提前终止解析,后续数据被丢弃——看起来像“取出后变短”,实则是解析失败。
解决方法是切换为更健壮的处理器:
- 改用
php_serialize:它用serialize()格式,无分隔符风险,PHP 5.5.2+ 支持 - 在
php.ini中设session.serialize_handler = php_serialize - 或运行时设置:
ini_set('session.serialize_handler', 'php_serialize');(需在session_start()前)
session.save_handler = files 的文件写入限制
默认 session.save_handler = files 把 session 数据写成单个文件。若长字符串(如 >1MB)写入时遭遇磁盘 I/O 错误、临时目录空间不足、或文件系统单文件大小限制(如 FAT32 的 4GB 限制不构成问题,但某些容器环境挂载卷有配额),session_write_close() 可能静默失败,导致下次读取时只拿到旧的、较短的数据。
排查建议:
立即学习“PHP免费学习笔记(深入)”;
- 检查
session.save_path目录权限和磁盘剩余空间:df -h和ls -l /var/lib/php/sessions/ - 确认 session 文件实际内容是否完整:
tail -c 100 /var/lib/php/sessions/sess_* - 换用
memcached或redis存储 session,绕过文件系统瓶颈
mb_strlen() 误判引发的“假截断”错觉
很多开发者在存入前用 strlen() 判断长度,取出后又用 strlen() 检查,发现“变短了”。但真实原因是:原始字符串含 UTF-8 多字节字符(如 emoji、中文),strlen() 返回的是字节数,而 session 序列化/反序列化过程本身不修改字节流——你只是用错了长度函数。
验证方式:
- 存入前:
var_dump(strlen($str), mb_strlen($str, 'UTF-8')); - 取出后做同样对比,若两组
mb_strlen()结果一致,说明没截断,只是strlen()不适用 - 统一改用
mb_strlen($str, 'UTF-8'),并确保mb_internal_encoding('UTF-8')已设置
session.use_strict_mode 和垃圾回收干扰
虽然不直接导致截断,但 session.use_strict_mode = 0(PHP 7.1 默认)时,若 session ID 被复用或存在并发写入竞争,可能触发 session 文件被覆盖或部分写入。尤其当多个请求同时向同一个 session 写入大字符串,files handler 的锁机制不够强,容易出现数据不一致。
关键点:
- 启用严格模式:
ini_set('session.use_strict_mode', '1'); - 避免在多个并发请求中反复写入超大字符串到同一 session key
- 大体积数据优先考虑存 Redis 或数据库,而非 session
真正卡住 session 长字符串的,往往不是 PHP 本身,而是序列化格式缺陷、文件存储不可靠、或开发者用错了长度判断方式——别急着怀疑 $_SESSION,先看 session.serialize_handler 和实际 session 文件内容。



















