enriqg9's avatar

Filesystem file uploaded to amazon s3 gets corrupted when downloaded

I am uploading files to Amazon S3 with Laravel filesystem. The upload process works great, however, when I download the files get corrupted. I have manually downloaded the files from the S3 bucket and that way the files don't get corrupted, so I figured that the problem is not the upload.

I am uploading the files like this:

/**
 * 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;
}

And downloading like this:

/**
 * @param Document $document
 * @return Response
 */
public function download(Document $document)
{
    $file = Storage::cloud()->get($document->path);

    return response($file, 200)->withHeaders([
        'Content-Type'        =>  'application/octet-stream',
        'Content-Disposition' => 'attachment; filename="' . $document->name . '"'
    ]);
}

Any idea on what I am doing wrong?

0 likes
5 replies
willvincent's avatar

Try this:

/**
 * @param Document $document
 * @return Response
 */
public function download(Document $document)
{
    $stream = fopen(Storage::cloud()->get($document->path), 'r');
    $headers = [
        'Content-Type'        =>  'application/octet-stream',
        'Content-Disposition' => 'attachment; filename="' . $document->name . '"'
    ];

    return \Response::stream(function() use ($stream) {              
        while (!feof($stream)) {                                     
            echo fread($stream, 1024);                               
        }                                                            
        fclose($stream);                                             
    }, 200, $headers);
}
enriqg9's avatar

@willvincent Thanks for your response. I am getting this: "fopen() expects parameter 1 to be a valid path, string given" . I tried with the following code, mixing what you suggested, I am able to get a downloaded file, but it still is corrupted.

/**
     * Download document from S3.
     *
     * @param Document $document
     * @return Response
     */
    public function download(Document $document)
    {
        $s3Client = Storage::cloud()->getAdapter()->getClient();

        $s3Client->registerStreamWrapper();

        $stream = fopen('s3://bucket/' . $document->path, 'r');

        $headers = [
            'Content-Type'        => 'application/octet-stream',
            'Content-Disposition' => 'attachment; filename="' . $document->name . '"'
        ];

        return \Response::stream(function () use ($stream) {
            while (!feof($stream)) {
                echo fread($stream, 1024);
            }
            fclose($stream);
        }, 200, $headers);
    }
willvincent's avatar

I'd bet the problem is with the headers... what happens if you omit them? Maybe add these headers as well:

Content-Transfer-Encoding: binary
Connection: Keep-Alive
Content-Length: $size
enriqg9's avatar

@willvincent If I omit the headers I get all the file content returned as a string into the browser. And using the extra headers results on a corrupted file as well :(

enriqg9's avatar
enriqg9
OP
Best Answer
Level 13

The problem was that I had a whitespace on a config file before the <?php tag which was corrupting my files.

1 like

Please or to participate in this conversation.