Aws-sdk-php: All multipart uploads end up having Content-Type "application/octet-stream"

Created on 3 Oct 2017  路  9Comments  路  Source: aws/aws-sdk-php

Recently I was wondering why my uploaded videos won't play in a browser when accusing the url directly. I discovered that the wrong content-type was set during upload.

I traced the issue back to this peace of code.
Where getInitiateParams() overwrites the previously set content-type in $params.
https://github.com/aws/aws-sdk-php/blob/c0321509cccc20e6f0051ce9e36369e465388029/src/S3/MultipartUploadingTrait.php#L96-L111

It calls the function getSourceMimeType() from
https://github.com/aws/aws-sdk-php/blob/4da9a3b61473b378dea34c2b211cb3654ec3effb/src/S3/MultipartUploader.php#L136-L142

Which tries to figure out the content-type from the source. Since the source is a "php://temp" stream. It will return "application/octet-stream".
This forces the function getInitiateParams() to overwrite the previously set content-type in $params.

Which is annoying all files larger uploaded via MultipartUpload will have a content-type of "application/octet-stream".

I'm using Flysysteme AWS-S3_V3 Atapter to upload files but all its doing its calling the upload function on the S3Client

https://github.com/thephpleague/flysystem-aws-s3-v3/blob/3837b6a354fb2a3cac58ec84bcb135b20a183d31/src/AwsS3Adapter.php#L573-L594

So there shouldn't be anything wrong with that.

Do I miss something or is is intended and if so why?

There was a pull request addressing that issue but there is not much information for it.
https://github.com/aws/aws-sdk-php/pull/1367

Hope somebody can help.

Thank You
Alex

bug pr-under-review

Most helpful comment

I had this similar issue. Below is how I solved it.

It's the params parameter that we need to pass with ContentType key & value.

$uploader = new MultipartUploader($s3Client, $file->getRealPath(), [
    'bucket' => env('AWS_BUCKET'),
    'key' => $path,
    'params' => [
        'ContentType' => $file->getMimeType()
    ]
]);


\GuzzleHttp\Promise\all($s3FileUploadPromises)->wait();

All 9 comments

Can you please post how you're generating the values to pass to Flysystem? Most insterested around:

Since the source is a "php://temp" stream.

Sure.

I read the file and store the content in a variable and pass it to flysysteme with a destination path, which then calls the upload function on the S3Client.

https://github.com/aws/aws-sdk-php/blob/2d0508ddeac51bbb0e0f86465db6b7ac50a597fb/src/S3/S3ClientTrait.php#L24-L34

Which creates the ObjectUploader which creates the stream here

https://github.com/aws/aws-sdk-php/blob/c0321509cccc20e6f0051ce9e36369e465388029/src/S3/ObjectUploader.php#L57

The body is then passed to the MultipartUploader which is the source.

Hope that helps.
Let me know if you need anything else.

Thanks for the added info. How is the $body value you pass to flysystem generated (file_get_contents(), fopen(), etc.)?

its a simple file_get_contents() to a path on the local drive.

Thanks @tiran133. I've confirmed this issue and have started review on the PR that attempts to fix it.

This fix was released in version 3.36.28.

Well this is still happening with me. The fix seems to no work.
This is my code

        $s3->upload(...['params' => [
            'CacheControl' => 'max-age=2592000',
            'ContentType' => mime_content_type($file)
        ]]);

same problem to me.

protected function getSourceMimeType()
{
    if ($uri = $this->source->getMetadata('uri'))
    {
        return Psr7\mimetype_from_filename($uri) ?: 'application/octet-stream';
    }
}
Psr7\mimetype_from_filename($uri);

the SDK code tries to get the file extension from the URL, but if the URL did not contain extension then application/octet-stream returned, well...

so why not to get wrapper_data?

$headers = $this->source->getMetadata('wrapper_data');

then pick up the content-type from the headers, see https://www.php.net/manual/en/function.stream-get-meta-data.php

I had this similar issue. Below is how I solved it.

It's the params parameter that we need to pass with ContentType key & value.

$uploader = new MultipartUploader($s3Client, $file->getRealPath(), [
    'bucket' => env('AWS_BUCKET'),
    'key' => $path,
    'params' => [
        'ContentType' => $file->getMimeType()
    ]
]);


\GuzzleHttp\Promise\all($s3FileUploadPromises)->wait();
Was this page helpful?
0 / 5 - 0 ratings