从带有文件系统的 AWS S3 下载的 Laravel 文件已损坏

Posted

技术标签:

【中文标题】从带有文件系统的 AWS S3 下载的 Laravel 文件已损坏【英文标题】:Laravel file downloaded from AWS S3 with Filesystem gets corrupted 【发布时间】:2016-09-22 09:46:19 【问题描述】:

我正在使用 Laravel 文件系统将文件上传到 Amazon S3。但是,当我下载文件损坏时,上传过程效果很好。我已经从 S3 存储桶手动下载了文件,这样文件就不会损坏,所以我认为问题不在于上传。

我正在上传这样的文件:

/**
 * Upload the file to Amazon S3.
 *
 * @param UploadedFile $file
 * @param $path
 * @return $this|bool
 */
protected function upload(UploadedFile $file, $path)

    $this->filename = $path . '/' . time() . '_' . str_replace(' ', '-', $file->getClientOriginalName());

    $disk = Storage::cloud();

    if ($disk->put($this->filename, fopen($file, 'r+'))) 

        $this->save();

        return $this;
    

    return false;

要下载,我试过这个:

/**
 * @param Document $document
 * @return Response
 */
public function download(Document $document)

    $file = Storage::cloud()->get($document->path);

    $file_info = new finfo(FILEINFO_MIME_TYPE);

    return response($file, 200)->withHeaders([
        'Content-Type'        => $file_info->buffer($file),
        'Content-Disposition' => 'inline; filename="' . $document->name . '"'
    ]);

还有这个:

/**
 * @param Document $document
 * @return Response
 */
public function download(Document $document)

    $stream = Storage::cloud()->getDriver()->readStream($document->path);

    $file = stream_get_contents($stream);

    $file_info = new finfo(FILEINFO_MIME_TYPE);

    return response($file, 200)->withHeaders([
        'Content-Type'        => $file_info->buffer($file),
        'Content-Disposition' => 'inline; filename="' . $document->name . '"'
    ]);

通过这两个下载功能,我得到了文件,但是它们已损坏。任何帮助表示赞赏!

【问题讨论】:

$file_info->buffer($file)的值是多少? @maiorano84 我将主要使用 PDF、Doc/x 和 Dwg。根据流式传输的文件,我从$file_info->buffer($file) 得到"application/pdf""application/vnd.openxmlformats-officedocument.wordprocessingml.document""image/vnd.dwg" 只是为了搞笑,尝试将标题设置为以下内容:[ 'Content-Type' => 'application/octet-stream', 'Content-Disposition' => 'attachment; filename="' . $document->name . '"' ] @maiorano84 我仍然在 Word 文档中得到以下信息:Word 在 file.docx 中发现不可读的内容。是否要恢复此文档的内容?如果您信任此文档的来源,请单击“是”。 由于我以前从未使用过存储层,所以我很难说断开连接可能在哪里。也就是说,Laravel 响应对象确实有一个下载方法。看看this answer 是否有助于为您简化流程。 【参考方案1】:

问题在于输出缓冲区包含空格。在返回响应之前使用ob_end_clean() 解决了这个问题,但是在打开<?php 标记之前在文件上找到一个空格时,不需要使用ob_end_clean()

这是不使用预签名网址的代码:

/**
 * Download document from S3.
 *
 * @param Document $document
 * @return Response
 */
public function download(Document $document)

    $s3Client = Storage::cloud()->getAdapter()->getClient();

    $stream = $s3Client->getObject([
        'Bucket' => 'bucket',
        'Key'    => $document->path
    ]);

    return response($stream['Body'], 200)->withHeaders([
        'Content-Type'        => $stream['ContentType'],
        'Content-Length'      => $stream['ContentLength'],
        'Content-Disposition' => 'inline; filename="' . $document->name . '"'
    ]);

【讨论】:

以上是关于从带有文件系统的 AWS S3 下载的 Laravel 文件已损坏的主要内容,如果未能解决你的问题,请参考以下文章

通过 Java 下载 AWS S3 文件。身份验证调用失败

带有Java的AWS Lambda无法从S3获取文件

从客户端下载 AWS S3 文件

AWS 从 S3 下载对象时出错,“配置文件不能为空”

使用 AWS 开发工具包从 Amazon S3 下载文件后如何删除文件

允许用户从 AWS s3 或 Cloudfront 批量下载文件