最近对服务器上的兰空图床(Lsky Pro)进行 PHP 版本升级,将 PHP 8.0 升级到了 PHP 8.2.28。
升级完成后,网站出现了 HTTP 500 错误。
经过逐步排查,最终发现问题主要涉及两个方面:
- PHP 8.0 升级到 PHP 8.2 后,Nginx 仍然指向旧的 PHP-FPM Socket。
- PHP-FPM 修复后,兰空图床使用的旧版本 Carbon 与 PHP 8.2 存在兼容性问题。
本文记录整个排查和修复过程。
一、运行环境
本次故障环境:
操作系统:OpenCloudOS
Web Server:Nginx
PHP:8.0 → 8.2.28
PHP-FPM:PHP 8.2
项目:兰空图床(Lsky Pro)
框架:Laravel
日期处理库:nesbot/carbon
项目目录:
/www/wwwroot/img.hecady.com
网站实际入口:
/www/wwwroot/img.hecady.com/public/index.php
使用的域名:
img.hecady.com
cdn-img.hecady.com
二、PHP 8.0 升级到 PHP 8.2 后网站出现 500
升级 PHP 后,访问兰空图床出现:
HTTP 500 Internal Server Error
首先没有直接修改兰空图床代码,而是从 Web Server 到 PHP,再到 Laravel 应用层逐级排查。
三、检查 PHP-FPM Socket
PHP 8.0 时使用:
/tmp/php-cgi-80.sock
升级到 PHP 8.2 后使用:
/tmp/php-cgi-82.sock
首先检查 PHP-FPM:
ps -ef | grep -E 'php-fpm|php-cgi' | grep -v grep
检查 Socket:
ls -lah /tmp/php-cgi-*.sock
也可以:
ss -lx | grep php-cgi
确认 PHP 8.2 的 PHP-FPM 已经正常运行,并且:
/tmp/php-cgi-82.sock
存在。
四、检查 Nginx 配置
继续检查 Nginx:
nginx -T
最终确认兰空图床的 PHP 配置:
location ~ [^/]\.php(/|$)
{
try_files $uri =404;
fastcgi_pass unix:/tmp/php-cgi-82.sock;
fastcgi_index index.php;
include fastcgi.conf;
include pathinfo.conf;
}
这里需要特别注意。
PHP 8.0:
/tmp/php-cgi-80.sock
PHP 8.2:
/tmp/php-cgi-82.sock
如果 PHP 已经升级到 8.2,但是 Nginx 仍然连接:
/tmp/php-cgi-80.sock
就会出现:
connect() to unix:/tmp/php-cgi-80.sock failed
因此升级 PHP 后,一定要同时检查 PHP-FPM Socket 和 Nginx 的 fastcgi_pass。
修改完成后执行:
nginx -t
确认:
syntax is ok
test is successful
五、测试 Nginx 到 PHP-FPM 是否正常
为了排除 Nginx 和 PHP-FPM 问题,可以临时创建一个 PHP 测试文件。
进入兰空图床目录:
cd /www/wwwroot/img.hecady.com
创建:
cat > public/test.php <<'EOF'
<?php
phpinfo();
EOF
然后访问:
https://你的域名/test.php
如果能够正常显示 PHPInfo 页面,说明:
Nginx
↓
PHP-FPM 8.2
↓
PHP
整个 PHP 执行链路正常。
测试完成后立即删除:
rm -f public/test.php
六、真正的问题:兰空图床 Carbon 报错
确认 Nginx 和 PHP-FPM 正常后,继续查看兰空图床的 Laravel 错误日志。
最终发现真正的异常:
Carbon\Carbon::setLastErrors():
Argument #1 ($lastErrors) must be of type array, bool given
错误文件:
/www/wwwroot/img.hecady.com/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
这说明:
Nginx 正常
PHP-FPM 正常
PHP 8.2 正常
↓
兰空图床 Laravel 应用层出现异常
↓
Carbon 兼容性问题
七、Carbon 与 PHP 8.2 的兼容性问题
检查 Carbon 源码后,发现第一处代码:
self::setLastErrors(parent::getLastErrors());
问题在于:
parent::getLastErrors()
在某些情况下可能返回:
false
但是 setLastErrors() 需要的是数组。
于是出现:
false
↓
setLastErrors(false)
↓
TypeError
↓
HTTP 500
这就是本次兰空图床升级 PHP 8.2 后出现 500 的核心原因。
八、修复 Carbon 第一处代码
修改之前先备份:
cd /www/wwwroot/img.hecady.com
cp vendor/nesbot/carbon/src/Carbon/Traits/Creator.php \
vendor/nesbot/carbon/src/Carbon/Traits/Creator.php.bak
将:
self::setLastErrors(parent::getLastErrors());
修改为:
self::setLastErrors(parent::getLastErrors() ?: [
"warning_count" => 0,
"warnings" => [],
"error_count" => 0,
"errors" => []
]);
也可以直接执行:
sed -i 's/self::setLastErrors(parent::getLastErrors());/self::setLastErrors(parent::getLastErrors() ?: ["warning_count" => 0, "warnings" => [], "error_count" => 0, "errors" => []]);/' \
/www/wwwroot/img.hecady.com/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
修改完成后,兰空图床前台恢复正常。
九、登录兰空图床后台后再次出现错误
前台恢复后,继续登录兰空图床后台测试。
结果后台又出现相同类型的错误:
Carbon\Carbon::setLastErrors():
Argument #1 ($lastErrors) must be of type array, bool given
继续检查:
sed -n '630,675p' \
/www/wwwroot/img.hecady.com/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
发现另外一处:
$lastErrors = parent::getLastErrors();
后续又执行:
$instance::setLastErrors($lastErrors);
因此这里同样存在:
false → setLastErrors(false)
的问题。
十、修复 Carbon 第二处代码
将:
$lastErrors = parent::getLastErrors();
修改为:
$lastErrors = parent::getLastErrors() ?: [
"warning_count" => 0,
"warnings" => [],
"error_count" => 0,
"errors" => []
];
也可以直接执行:
cd /www/wwwroot/img.hecady.com
sed -i 's/\$lastErrors = parent::getLastErrors();/\$lastErrors = parent::getLastErrors() ?: ["warning_count" => 0, "warnings" => [], "error_count" => 0, "errors" => []];/' \
vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
检查:
grep -n -C 2 "getLastErrors" \
/www/wwwroot/img.hecady.com/vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
确认两处代码都已经处理。
十一、清理兰空图床 Laravel 缓存
修改完成后清理 Laravel 缓存:
cd /www/wwwroot/img.hecady.com
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
然后重启 PHP-FPM:
systemctl restart php-fpm-82
重新测试:
兰空图床前台
↓
用户登录
↓
图片上传
↓
后台管理
最终网站前台和后台均恢复正常。
十二、Primary script unknown 并不是本次故障根因
排查 Nginx 日志时,还发现:
Primary script unknown
GET /webroot/index.php/_environment
但是兰空图床实际入口是:
/www/wwwroot/img.hecady.com/public/index.php
并不存在:
/webroot/index.php
因此这类请求更符合外部扫描或路径探测。
所以:
Primary script unknown并不是本次兰空图床 500 错误的主要原因。
排查服务器日志时,不应该看到某一条错误就直接认定它是根因,需要结合项目实际目录、Nginx 配置、请求路径和异常堆栈综合判断。
十三、为什么不建议直接执行 composer update
发现 Carbon 兼容性问题后,不建议直接执行:
composer update
因为兰空图床属于 Laravel 项目,Composer 可能同时更新:
Carbon
Laravel
Symfony
Illuminate
Guzzle
Monolog
最终可能导致整个项目产生新的依赖冲突。
建议先检查当前版本:
composer show nesbot/carbon
查看 Laravel:
composer show laravel/framework
也可以检查:
grep -A5 -B2 '"name": "nesbot/carbon"' composer.lock
以及:
grep -A5 -B2 '"name": "laravel/framework"' composer.lock
确认当前兰空图床版本和依赖关系后,再制定正式升级方案。
十四、直接修改 vendor 只是临时解决方案
本次为了快速恢复兰空图床正常访问,直接修改了:
vendor/nesbot/carbon/src/Carbon/Traits/Creator.php
这种方式可以作为生产环境故障时的紧急修复方案,但并不是长期最佳方案。
因为以后执行:
composer install
或者重新部署兰空图床时,vendor 目录可能会重新生成,之前修改的代码也可能消失。
长期解决方案应该是:
升级兼容 PHP 8.2 的 Carbon 版本
同时确认当前兰空图床版本对应的 Laravel 是否支持 PHP 8.2。
十五、PHP 升级兰空图床前需要注意什么?
以后升级兰空图床 PHP 版本,建议提前检查:
PHP 版本
php -v
Laravel 版本
composer show laravel/framework
Carbon 版本
composer show nesbot/carbon
PHP-FPM
ps -ef | grep -E 'php-fpm|php-cgi' | grep -v grep
PHP-FPM Socket
ls -lah /tmp/php-cgi-*.sock
Nginx 配置
nginx -T
重点检查:
fastcgi_pass
是否指向当前 PHP 版本对应的 Socket。
同时建议提前备份:
兰空图床项目文件
数据库
composer.json
composer.lock
Nginx 配置
PHP 配置
十六、本次兰空图床故障完整流程
整个故障可以概括为:
兰空图床
↓
PHP 8.0
↓
升级到 PHP 8.2
↓
Nginx 仍连接 PHP 8.0 Socket
↓
修复 fastcgi_pass
↓
PHP-FPM 8.2 正常
↓
兰空图床继续出现 500
↓
查看 Laravel 错误日志
↓
发现 Carbon TypeError
↓
DateTime::getLastErrors() 返回 false
↓
旧 Carbon 直接传递给 setLastErrors()
↓
setLastErrors(false)
↓
TypeError
↓
修复 Carbon 第一处代码
↓
前台恢复
↓
登录后台再次触发第二处代码
↓
修复 Carbon 第二处代码
↓
清理 Laravel 缓存
↓
重启 PHP-FPM
↓
兰空图床前台、后台恢复正常
十七、总结
这次兰空图床从 PHP 8.0 升级到 PHP 8.2 后出现 500,实际上经历了两个阶段。
第一阶段是 PHP-FPM Socket 切换问题:
PHP 8.0
↓
/tmp/php-cgi-80.sock
升级 PHP 8.2 后变成:
/tmp/php-cgi-82.sock
如果 Nginx 没有同步修改 fastcgi_pass,就会导致 PHP 请求无法正常转发。
第二阶段是 Carbon 与 PHP 8.2 的兼容性问题。
旧版本 Carbon 中存在:
parent::getLastErrors()
直接传递给:
setLastErrors()
的代码。
当 getLastErrors() 返回 false 时,就会触发:
Argument #1 ($lastErrors) must be of type array, bool given
最终导致兰空图床返回 HTTP 500。
本次通过临时修复 Carbon 两处代码、清理 Laravel 缓存并重启 PHP-FPM,最终恢复了兰空图床前台和后台。
不过从长期维护角度来看,直接修改 vendor 只是临时方案。更推荐根据当前兰空图床版本,升级到兼容 PHP 8.2 的 Carbon 和 Laravel 依赖版本。
这次故障也再次说明:
PHP 升级不能只关注 PHP 本身,还需要同时检查 Nginx、PHP-FPM、Laravel、Carbon 以及 Composer 依赖之间的兼容性。
对于运行中的兰空图床,升级 PHP 前最好先做好完整备份,并确认当前兰空图床版本与目标 PHP 版本之间的兼容性。