Laravel 上传文件至 BackBlaze 问题排查记
背景
之前用 Laravel 把 图床 重写了,在我自建的 Docker 集群中运行了一段时间后,我发现,大于 2M 的图片无论怎么都上传不了,而且也没有报错。一直断断续续地排查,终于在 1024 节日找到了问题所在。
排查过程
php.ini 配置
一般使用 PHP 开发,大文件无法上传,第一直觉都是先怀疑 PHP 的配置问题,无非就是两个参数 upload_max_filesize
和 max_post_size
。
所以我先是修改了 Docker 镜像打包的代码,把这两个参数都提高到了 8M。然而发现并没有什么用,大于 2M 的图片依旧上传失败。
更换 GD 为 Imagick
排查过程中,还发现了图床不能处理 BMP 格式的图片。于是修改了 Dockerfile,安装 Imagick,将 Intervention/image 这个库的驱动改为 Imagick,完美解决。
最终的 Debug
定下心来,在关键位置打了断点,发现大文件上传时,会抛出异常 Received error from B2: Sha1 did not match data received
。对比了文件的 sha1 值和传给 B2 的值,两个是一样的,最终定位在传给 B2 的一个文件大小的参数上。
查看了源码,确实发现有点坑。图床代码将本地图片推送到 B2,用的是大众推荐的写法 Storage::disk('b2')->put('path/to/file', Storage::disk('local')->get('path/to/file'));
,但是由于 Storage::disk('local')->get('path/to/file')
获取到的是字符串形式的内容,最终通过下面代码计算大小时,远比实际值要小。
1 | if (is_resource($options['Body'])) { |
猜测是 B2 那边根据传的「文件大小」这个参数对内容做了截取,再计算 sha1 值,发现不对之后抛出异常。找到问题之后,改写推送代码,解决了这个叫人头大的 Bug。
1 | $localFile = Storage::getDriver()->readStream($localPath); |