Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The mime type is not correctly passed to the S3 adapter via Flysystem storage class #1223

Open
morawskim opened this issue Sep 8, 2021 · 2 comments

Comments

@morawskim
Copy link

morawskim commented Sep 8, 2021

Bug Report

Q A
BC Break no
Bundle version 1.18.0
Symfony version 4.4.20
PHP version 7.4

Summary

The mime type is not correctly passed to the S3 adapter via Flysystem storage class (\Vich\UploaderBundle\Storage\FlysystemStorage).

Current behavior

symfony/validator component works well because the image validator can correctly detect file mime type.
The problem is with integration between vich/uploader-bundle and league/flysystem-aws-s3-v3.
When vich tries to store a file in S3 the method doUpload of class \Vich\UploaderBundle\Storage\FlysystemStorage is called. This method looks like this:

protected function doUpload(PropertyMapping $mapping, UploadedFile $file, ?string $dir, string $name): void
{
    $fs = $this->getFilesystem($mapping);
    $path = !empty($dir) ? $dir.'/'.$name : $name;

    $stream = \fopen($file->getRealPath(), 'rb');
    try {
        $fs->writeStream($path, $stream, [
            'mimetype' => $file->getMimeType(),
        ]);
    } catch (FilesystemException $e) {
        throw new CannotWriteFileException($e->getMessage());
    }
}

In this method, we set option mimetype from file (this is correct because the value will be image/jpg). Because I use an S3 adapter the write method of class \League\Flysystem\AwsS3V3\AwsS3V3Adapter is called. This method is very simple because delegates storing a file to the internal method upload. The source code of this method is below:

private function upload(string $path, $body, Config $config): void
{
    $key = $this->prefixer->prefixPath($path);
    $acl = $this->determineAcl($config);
    $options = $this->createOptionsFromConfig($config);
    $shouldDetermineMimetype = $body !== '' && ! array_key_exists('ContentType', $options);

    if ($shouldDetermineMimetype && $mimeType = $this->mimeTypeDetector->detectMimeType($key, $body)) {
        $options['ContentType'] = $mimeType;
    }

    $this->client->upload($this->bucket, $key, $body, $acl, ['params' => $options]);
}

As you can see S3 adapter expects mime type in key ContentType instead of mimetype.
The default implementation of detectMimeType is based on file extension.
This is not excatly true (you can check \League\MimeTypeDetection\FinfoMimeTypeDetector::detectMimeType), but this not change a lots.

When I want to fetch\check mime type of a file from S3, I get the wrong mime type.

Maybe we could also set key ContentType in \Vich\UploaderBundle\Storage\FlysystemStorage::doUpload?
I can prepare PR if you think that this solution is fine.

How to reproduce

Configure bundle with FlysystemStorage and S3 adapter (you can use Minio as a free and open-source alternative).
Change the file extension from jpg to mp4.

Expected behavior

The correct mime-type should be stored in the file's metadata in S3.

@garak
Copy link
Collaborator

garak commented Sep 30, 2021

I guess that this problem is related to the one discussed in #1217

@gabplch
Copy link

gabplch commented Jul 1, 2024

For all, who will find this issue. The problem is not in Filesystem, but in the method getMimeType() of UploadedFile class. Method will return guessed mime type. If you want one, that you defined earlier, in UploadedFile, use getClientMimeType()

issue can be closed...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants