Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Validator] Add support for SVG files to image validation constraint #15460

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

Closed
keichinger opened this issue Aug 5, 2015 · 16 comments
Closed

Comments

@keichinger
Copy link
Contributor

With the rise of SVG images all over the web I think it's pretty fair to say that having support for the already existing Image validator constraint would benefit everyone.

Let's have a look at the following scenario where we'd like to give the opportunity to someone to upload either a GIF, JPEG, PNG or an SVG.

# validation.yml

AppBundle\Entity\MyEntity:
    properties:
        # ...
        file:
            - Image:
                mimeTypes:
                    - image/gif
                    - image/jpeg
                    - image/png
                    - image/svg+xml
                minWidth: 1920
                minHeight: 1080
                # ...

The MIME type Google Chrome is sending matches images/svg+xml and still I'm getting the following error message: "This file is not a valid image."

A solution to this problem would be to write a custom validation constraint. However, I'm pretty sure that this is one of the things that might be needed more often in the future so the best place for it is inside the Symfony Core.

Opinions?

@apfelbox
Copy link
Contributor

apfelbox commented Aug 5, 2015

The problem seems to lie in the current MimeTypeGuessers. It currently doesn't sufficiently support SVG. Regular SVG files are recognized correctly and everything works, but minimized SVGs produce an error.

Simple test script:

use Symfony\Component\HttpFoundation\File\File;


$svg = new File("example.svg");
var_dump($svg->getMimeType()); // string 'image/svg+xml' (length=13)

// example_after_svgo.svg is a minified SVG file, created with the following command
//
//      $ svgo --output=example_after_svgo.svg example.svg
//
// https://www.npmjs.com/package/svgo

$svgMin = new File("example_after_svgo.svg");
var_dump($svgMin->getMimeType()); // string 'text/plain' (length=10)

I think a way to solve this is to register another guesser, a specialized SvgMimeTypeGuesser (or something like that…). This mime type guesser checks whether the file is valid XML and the single root node is <svg ..></svg> (a suggested here).

That way both the form would work correctly and the mimetype guessing would be improved globally.

@yguedidi
Copy link
Contributor

yguedidi commented Aug 5, 2015

@cH40z-Lord Just to be sure, is it a typo in your PR description or Google Chrome send you images/svg+xml? (note the "s")

@keichinger
Copy link
Contributor Author

@yguedidi sorry, it is indeed a typo.

@apfelbox
Copy link
Contributor

apfelbox commented Aug 5, 2015

@yguedidi @cH40z-Lord right, but keep in mind that the mimetype as provided from the browser is discarded and instead the mimetype is fetched from the actual uploaded file.

This is necessary as the mimetype of the request can be altered to be anything and doesn't have to be connected to the file itself.

@apfelbox
Copy link
Contributor

apfelbox commented Aug 6, 2015

@xabbuh as I read it, you should add the HttpFoundation and/or Filesystem label too, as the actual error lies in Symfony\Component\HttpFoundation\File\File (if I read that correctly).

@keichinger
Copy link
Contributor Author

I've started to implement a first rough prototype that addresses the issues discussed here.

Right now I've got a working SvgMimeTypeGuesser that reads the file's contents and checks for an <svg ...> root node, as recommended by @apfelbox.

Now I wanted to have a look at the Image constraint and think about how to integrate SVG images (and possibly other vector formats for the future) into it.

My proposed changes would look like this:

1) VectorImage and BitmapImage constraints

  • Rename Image constraint to BitmapImage
  • Add VectorImage constraint (right now only validates SVG but is open for extensions) and corresponding validator class

That way everything is nice and separated from each other.
What I'm wondering about is how we could make it possible that the user could upload either a bitmap image or a vector image.

Given my example from above:

# validation.yml

AppBundle\Entity\MyEntity:
    properties:
        file:
            # formerly Image
            - BitmapImage:
                # ....
            # New!
            - VectorImage:
                # ....

Obviously that would require the uploaded file to pass both validators, which is very unlikely to happen. So we would need to extend Symfony in a way to have allow or-constraints.

Maybe it can be easily done by creating a new AnyConstraint class which then can be used like this:

# validation.yml

AppBundle\Entity\MyEntity:
    properties:
        file:
            - Any:
                MustPass:
                    # formerly Image
                    - BitmapImage:
                        # ....
                    # New!
                    - VectorImage:
                        # ....

This new AnyConstraint class would of course work with any Constraint class. If we want to take it a step further we could add an AllConstraint class for the same behaviour that we have now: all validators must pass.

2) Extend Image constraint

  • Extend Image constraint to be able to parse any kind of vector images
  • Add a lot of new properties to Image constraint for each feature we want to support for vector graphics
  • Add a switch inside the validate() function to either parse Bitmap based images or vector images

Conclusion

I'd love to hear your opinions on both proposals. Personally I'd probably go for the first one as it seems to be the most straight forward way to solve it.

/cc @stof @webmozart

@javiereguiluz
Copy link
Member

The reported issue is legit in my opinion. But the proposed solutions look very complex.

As @apfelbox said, the problem only occurs when the SVG is minimized with svgo tool:

// example_after_svgo.svg is a minified SVG file, created with the following command
//
//      $ svgo --output=example_after_svgo.svg example.svg
//
// https://www.npmjs.com/package/svgo

$svgMin = new File("example_after_svgo.svg");
var_dump($svgMin->getMimeType()); // string 'text/plain' (length=10)

But if we are talking about minimizing and not compressing, how can the MIME type guesser fail? The file should still be a valid SVG file.

@keichinger
Copy link
Contributor Author

Well the proposed Or-Constraint would be an additional feature to cover for the cases where you accept any kind of Image (Bitmap or Vector). Obviously a PR would only include a SvgValidator and VectorImage Constraint (and a renamed BitmapImage) to support the cases where only either of those are expected.

@COil
Copy link
Contributor

COil commented Sep 19, 2017

Just having a related issue with 3.3: $uploadedFile->guessExtension() on an uploaded svg file returns ".txt"

@homersimpsons
Copy link
Contributor

Hello, is there any plan to fix this ?

@teohhanhui
Copy link
Contributor

The guessed MIME type for SVG files is likely to be wrong out of the box. I just got image/svg with the file command, as used in FileBinaryMimeTypeGuesser.

@ZielinskiLukasz
Copy link

How to fix this?

@teohhanhui
Copy link
Contributor

Here's my workaround: https://gist.github.com/teohhanhui/90bbc4a61888ad2e92a160d8459db300

@xabbuh xabbuh added the Bug label Sep 24, 2018
fabpot added a commit that referenced this issue Jan 17, 2019
This PR was squashed before being merged into the 4.3-dev branch (closes #29896).

Discussion
----------

[Mime] Add the component

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no     <!-- see https://symfony.com/bc -->
| Deprecations? | yes
| Tests pass?   | yes
| Fixed tickets | #28832 #21985 makes #15460 trivial
| License       | MIT
| Doc PR        | symfony/symfony-docs#10886

This has been on my todo-list for X years :)

Commits
-------

bdca5d9 tweaked code
5268389 [Mime] added freedesktop as a source for mime types
74ca91d [Mime] added the component
d7ee0ec [HttpFoundation] updated File code
@javiereguiluz
Copy link
Member

I've run the script shown in #15460 (comment) and with the latest Symfony 4.3 version and Mime component, I get the expected results. I used this SVG image: https://symfony.com/logos/symfony_black_02.svg First, "as is" and second, after running svgo command on it.

The first lines of the original logo are:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
	 width="289.333px" height="122.833px" viewBox="0 0 289.333 122.833" enable-background="new 0 0 289.333 122.833"
	 xml:space="preserve">

The first line of the "compressed" (minified) logo is:

<svg xmlns="http://www.w3.org/2000/svg" width="289.333" height="122.833">

The results of running the script are:

string(13) "image/svg+xml"
string(9) "image/svg"

So, this no longer returns text/plain for the compressed SVG ... and therefore, I think this is fixed and we can close it. Thanks.

@teohhanhui
Copy link
Contributor

teohhanhui commented Jul 12, 2019

@javiereguiluz When was this fixed? In which PR?

EDIT: #29936

@azakero
Copy link

azakero commented Dec 4, 2023

Was this fixed? My svg is being identified as image/png.

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

No branches or pull requests