php+nginx 下载的压缩包提示损坏
环境:php+nginx+华为云存储obs或阿里云oss或亚马逊等云存储产品
场景:文件在华为云,通过分片获取文件,输出到页面下载。
问题:下载的压缩文件提示损坏,小的文件没有问题,大的文件不行,从5M以上就开始提示了。起初以为是下载的文件不完整,但是看了一下文件大小,和源文件是匹配的,1G以上的文件也试过,大小相同,但是就是无法解压。
扩展:从华为云获取到的内容写入到文件,这个文件是完整的,但是直接输出到浏览器,提示损坏,因为服务器的磁盘有限和节省时间,并不打算使用nginx的sendfile功能,网上查了一下大部分是缓冲或者是nginx的临时文件问题,但是我的现象似乎并不符合。
下面贴上部分代码,写入文件的部分是测试用的,可以忽略:
<?php
header('Content-Type: application/octet-stream');
//声明浏览器返回大小是按字节进行计算
header('Accept-Ranges:bytes');
//告诉浏览器文件的总大小
//header('Content-Length:' . $fileSize); //注意是'Content-Length:' 非Accept-Length
//声明下载文件的名称
header('Content-Disposition:attachment;filename=' . basename($fileInfo['path'])); //声明作为附件处理和下载后文件的名称
#计算分片大小和需要分片的数量
$blockSize = 5 * 1024 * 1024; // 5MB
$blockCount = intval($objectSize / $blockSize);
if ($objectSize % $blockSize !== 0) {
$blockCount++;
}
//var_dump(compact('blockCount'));
#开始进行分片下载
$fp = fopen($localFilePath, 'wb');
$promise = null;
ob_clean();
ob_end_clean();
ob_implicit_flush();
header('X-Accel-Buffering: no');
for ($i = 0; $i < $blockCount; $i++) {
$startPos = $i * $blockSize;
$endPos = ($i + 1 === $blockCount) ? $objectSize - 1 : ($startPos + $blockSize - 1);
$range = sprintf('bytes=%d-%d', $startPos, $endPos);
//echo "range: $range;\r\n";
$p = $obsClient->getObjectAsync([
'Bucket' => $bucket,
'Key' => $fileInfo['url'],
'Range' => $range,
], function ($exception, $resp) use ($startPos, $i, $range, $fp) {
fseek($fp, $startPos, 0);
//printf("%s\n", $range);
//printf("%s\n", $range);
try {
while (!$resp['Body']->eof()) {
$str = $resp['Body']->read(655360);
fwrite($fp, $str);
echo $str;
if(ob_get_level()>0){
ob_flush();
flush();
}
//sleep(1);
//echo "strlen:" . strlen($str) . "\r\n";
//echo $str;
// $str = $resp ['Body']->read(65536);
// fwrite($fp, $str);
}
} catch (Exception $exception) {
//printf($exception);
}
$resp['Body']->close();
//printf("Part#" . strval($i) . " done\n\n");
});
if ($promise === null) {
$promise = $p;
}
}
$promise->wait();
fclose($fp);
$obsClient->close();
// return $localFilePath;
exit();
?>
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
根据排查,基本确定了不是缓冲,nginx等问题,最终定位问题在华为云obs提供的sdk。上面代码是通过sdk中的异步获取文件内容:getObjectAsync,通过txt文档测试,直接输出,下载的文档是乱的,里面内容跟源文件顺序不一样,不清楚为什么写入文件的话,文件是对的,但是直接输出却是乱的,所以这里将获取文件的方式改成了getObject,同步获取,这样的顺序就不会乱了。下面贴一下调整后的代码: