PHP 8.1 不兼容 ThinkPHP 5.1,因框架未适配其严格类型和废弃机制,会导致 TypeError、PATH_INFO 为空、runtime 写入失败、PDO 连接异常等问题,需降级 PHP 或修改 Nginx 配置、权限、数据库连接方式等。

PHP 8.1 直接跑 ThinkPHP 5.1 会报错,别硬上
ThinkPHP 5.1 官方最低要求是 PHP 5.6,但**它没适配 PHP 8.0+ 的严格类型和废弃机制**。你在 PHP 8.1 下启动 TP5 项目,大概率遇到 Fatal error: Uncaught TypeError 或 Deprecated: Function mysql_connect() is deprecated 这类错误——不是配置问题,是框架底层代码和 PHP 运行时根本对不上号。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 先确认你真需要 TP5 —— 如果只是维护老站,降级到 PHP 7.4 是最稳的方案(它能跑 TP5 且自带
E_DEPRECATED提示,帮你提前发现 PHP 8 的雷) - 如果必须用 PHP 8.1,别指望“改几行 config 就行”,得动框架源码或加兼容层:比如在
thinkphp/library/think/Db.php里把mysql_*调用全换成mysqli_*,或引入symfony/polyfill-php80补缺失函数 - 检查
composer.json中"php": ">=5.6.0"这种宽松约束,改成"php": "^7.4 || ^8.1"并加"platform-check": false(仅测试环境),否则composer install会直接拒绝安装
PATH_INFO 和 URL 重写在 Nginx 下失效
TP5 默认用 PATH_INFO 模式解析路由(如 /index.php/user/login),但 PHP 8.1 + Nginx 组合下,$_SERVER['PATH_INFO'] 经常为空,导致所有路由 404 —— 这不是 ThinkPHP 错了,是 Nginx 的 fastcgi_split_path_info 正则在新版 PHP 的 CGI SAPI 下行为更严格。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在 Nginx 配置的
location ~ \.php$块里,确保有这三行:fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;fastcgi_param PATH_INFO $fastcgi_path_info;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; - 别漏掉
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;—— PHP 8.1 对这个参数更敏感,缺了就拿不到路径信息 - 验证方法:在控制器里加
dump($_SERVER['PATH_INFO']);,访问/index.php/test/index,输出应为/test/index;如果是空,说明正则没匹配上,要检查 Nginx 配置是否被 include 覆盖
runtime 目录写入失败、日志不生成
TP5 的 runtime 目录要存缓存、日志、模板编译文件,PHP 8.1 默认启用了更严格的 opcache.validate_timestamps=0 和 disable_functions,加上 CentOS 默认 SELinux 开启,很容易出现 file_put_contents(): failed to open stream: Permission denied。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 先关 SELinux 临时验证:
sudo setenforce 0;若好了,说明是上下文问题,用sudo semanage fcontext -a -t httpd_sys_rw_content_t "/path/to/runtime(/.*)?"然后sudo restorecon -Rv /path/to/runtime - 权限别只用
chmod -R 755——runtime必须是775,且属主属组设成 Web 服务用户:sudo chown -R nginx:nginx /path/to/runtime(Nginx)或sudo chown -R apache:apache /path/to/runtime(Apache) - 检查
php.ini是否禁用了file_put_contents:disable_functions = exec,passthru,shell_exec,system后面别带它;同时确认open_basedir没锁死runtime路径
数据库连接报 SQLSTATE[HY000] [2002] No such file or directory
这不是 MySQL 没启,而是 PHP 8.1 下 pdo_mysql 扩展默认用 Unix socket 连接(localhost),但 CentOS 上 MariaDB 的 socket 路径可能不是 /var/lib/mysql/mysql.sock,或者 PHP 编译时没指定对的路径。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 查真实 socket 路径:
mysqladmin variables | grep socket,拿到路径后,在 TP5 的config/database.php里显式写:'hostname' => '127.0.0.1'(强制走 TCP)或者'unix_socket' => '/run/mysqld/mysqld.sock' - 确认扩展已加载:
php -m | grep pdo_mysql,没输出就装:sudo yum install php-pdo php-mysqlnd(注意是mysqlnd,不是mysql) - TP5 的 PDO 连接字符串里不能留空端口,如果用了
'host' => 'localhost', 'port' => '',PHP 8.1 会当字符串处理出错,删掉'port'键或设为3306
最麻烦的点往往不在框架本身,而在 PHP 8.1 的扩展加载顺序、opcache 预编译行为、还有 CentOS 的 SELinux 上下文 —— 这些东西不报具体错误,只让 runtime 目录突然变只读、日志静默消失、PDO 连接超时却不提示原因。调的时候别只盯着 ThinkPHP 日志,/var/log/php-fpm/www-error.log 和 dmesg | grep avc 往往才是真相所在。



















