Skip to content
Permalink
Browse files

feature #29896 [Mime] Add the component (fabpot)

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
  • Loading branch information...
fabpot committed Jan 17, 2019
2 parents 5aa0967 + bdca5d9 commit db6784bb095de2c6ef0ab424efd5b06e71e3feef
Showing with 3,945 additions and 68 deletions.
  1. +1 −0 composer.json
  2. +37 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddMimeTypeGuesserPass.php
  3. +1 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/UnusedTagsPass.php
  4. +8 −0 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
  5. +7 −0 src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
  6. +12 −0 src/Symfony/Bundle/FrameworkBundle/Resources/config/mime_type.xml
  7. +1 −0 src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml
  8. +42 −0 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/AddMimeTypeGuesserPassTest.php
  9. +3 −2 src/Symfony/Bundle/FrameworkBundle/composer.json
  10. +8 −14 src/Symfony/Component/HttpFoundation/File/File.php
  11. +6 −0 src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php
  12. +4 −0 src/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesserInterface.php
  13. +5 −0 src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
  14. +5 −0 src/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php
  15. +6 −0 src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php
  16. +3 −0 src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php
  17. +3 −0 src/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesserInterface.php
  18. +2 −5 src/Symfony/Component/HttpFoundation/File/UploadedFile.php
  19. +3 −40 src/Symfony/Component/HttpFoundation/Tests/File/FileTest.php
  20. +1 −2 src/Symfony/Component/HttpFoundation/Tests/File/MimeType/MimeTypeTest.php
  21. +1 −0 src/Symfony/Component/HttpFoundation/composer.json
  22. +3 −0 src/Symfony/Component/Mime/.gitignore
  23. +90 −0 src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php
  24. +60 −0 src/Symfony/Component/Mime/FileinfoMimeTypeGuesser.php
  25. +19 −0 src/Symfony/Component/Mime/LICENSE
  26. +37 −0 src/Symfony/Component/Mime/MimeTypeGuesserInterface.php
  27. +3,130 −0 src/Symfony/Component/Mime/MimeTypes.php
  28. +32 −0 src/Symfony/Component/Mime/MimeTypesInterface.php
  29. +14 −0 src/Symfony/Component/Mime/README.md
  30. +104 −0 src/Symfony/Component/Mime/Resources/bin/update_mime_types.php
  31. +102 −0 src/Symfony/Component/Mime/Tests/AbstractMimeTypeGuesserTest.php
  32. +23 −0 src/Symfony/Component/Mime/Tests/FileBinaryMimeTypeGuesserTest.php
  33. +26 −0 src/Symfony/Component/Mime/Tests/FileinfoMimeTypeGuesserTest.php
  34. +1 −0 src/Symfony/Component/Mime/Tests/Fixtures/.unknownextension
  35. 0 src/Symfony/Component/Mime/Tests/Fixtures/directory/.empty
  36. 0 src/Symfony/Component/Mime/Tests/Fixtures/other-file.example
  37. BIN src/Symfony/Component/Mime/Tests/Fixtures/test
  38. BIN src/Symfony/Component/Mime/Tests/Fixtures/test.gif
  39. +60 −0 src/Symfony/Component/Mime/Tests/MimeTypesTest.php
  40. +33 −0 src/Symfony/Component/Mime/composer.json
  41. +31 −0 src/Symfony/Component/Mime/phpunit.xml.dist
  42. +21 −5 src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php
@@ -60,6 +60,7 @@
"symfony/ldap": "self.version",
"symfony/lock": "self.version",
"symfony/messenger": "self.version",
"symfony/mime": "self.version",
"symfony/monolog-bridge": "self.version",
"symfony/options-resolver": "self.version",
"symfony/process": "self.version",
@@ -0,0 +1,37 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Registers custom mime types guessers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class AddMimeTypeGuesserPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
if ($container->has('mime_types')) {
$definition = $container->findDefinition('mime_types');
foreach ($container->findTaggedServiceIds('mime.mime_type_guesser', true) as $id => $attributes) {
$definition->addMethodCall('registerGuesser', [new Reference($id)]);
}
}
}
}
@@ -42,6 +42,7 @@ class UnusedTagsPass implements CompilerPassInterface
'messenger.bus',
'messenger.receiver',
'messenger.message_handler',
'mime.mime_type_guesser',
'monolog.logger',
'proxy',
'routing.expression_language_provider',
@@ -73,6 +73,8 @@
use Symfony\Component\Messenger\Transport\Serialization\SerializerInterface;
use Symfony\Component\Messenger\Transport\TransportFactoryInterface;
use Symfony\Component\Messenger\Transport\TransportInterface;
use Symfony\Component\Mime\MimeTypeGuesserInterface;
use Symfony\Component\Mime\MimeTypes;
use Symfony\Component\PropertyAccess\PropertyAccessor;
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
@@ -310,6 +312,10 @@ public function load(array $configs, ContainerBuilder $container)
'Symfony\\Bundle\\FrameworkBundle\\Controller\\AbstractController',
]);
if (class_exists(MimeTypes::class)) {
$loader->load('mime_type.xml');
}
$container->registerForAutoconfiguration(Command::class)
->addTag('console.command');
$container->registerForAutoconfiguration(ResourceCheckerInterface::class)
@@ -374,6 +380,8 @@ public function load(array $configs, ContainerBuilder $container)
->addTag('messenger.message_handler');
$container->registerForAutoconfiguration(TransportFactoryInterface::class)
->addTag('messenger.transport_factory');
$container->registerForAutoconfiguration(MimeTypeGuesserInterface::class)
->addTag('mime.mime_type_guesser');
$container->registerForAutoconfiguration(LoggerAwareInterface::class)
->addMethodCall('setLogger', [new Reference('logger')]);
@@ -14,6 +14,7 @@
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddExpressionLanguageProvidersPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddMimeTypeGuesserPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
@@ -72,6 +73,11 @@ public function boot()
if ($trustedHosts = $this->container->getParameter('kernel.trusted_hosts')) {
Request::setTrustedHosts($trustedHosts);
}
if ($this->container->has('mime_types')) {
$mt = $this->container->get('mime_types');
$mt->setDefault($mt);
}
}
public function build(ContainerBuilder $container)
@@ -118,6 +124,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new ResettableServicePass());
$container->addCompilerPass(new TestServiceContainerWeakRefPass(), PassConfig::TYPE_BEFORE_REMOVING, -32);
$container->addCompilerPass(new TestServiceContainerRealRefPass(), PassConfig::TYPE_AFTER_REMOVING);
$container->addCompilerPass(new AddMimeTypeGuesserPass());
$this->addCompilerPassIfExists($container, MessengerPass::class);
if ($container->getParameter('kernel.debug')) {
@@ -0,0 +1,12 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<defaults public="false" />

<service id="mime_types" class="Symfony\Component\Mime\MimeTypes" public="true" />
</services>
</container>
@@ -42,6 +42,7 @@
</service>

<service id="serializer.normalizer.data_uri" class="Symfony\Component\Serializer\Normalizer\DataUriNormalizer">
<argument type="service" id="mime_types" on-invalid="null" />
<!-- Run before serializer.normalizer.object -->
<tag name="serializer.normalizer" priority="-920" />
</service>
@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddMimeTypeGuesserPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Mime\FileinfoMimeTypeGuesser;
use Symfony\Component\Mime\MimeTypes;
class AddMimeTypeGuesserPassTest extends TestCase
{
public function testTags()
{
$container = new ContainerBuilder();
$container->addCompilerPass(new AddMimeTypeGuesserPass());
$definition = new Definition(FileinfoMimeTypeGuesser::class);
$definition->addArgument('/path/to/magic/file');
$definition->addTag('mime.mime_type_guesser');
$container->setDefinition('some_mime_type_guesser', $definition->setPublic(true));
$container->register('mime_types', MimeTypes::class)->setPublic(true);
$container->compile();
$router = $container->getDefinition('mime_types');
$calls = $router->getMethodCalls();
$this->assertCount(1, $calls);
$this->assertEquals('registerGuesser', $calls[0][0]);
$this->assertEquals(new Reference('some_mime_type_guesser'), $calls[0][1][0]);
}
}
@@ -23,7 +23,7 @@
"symfony/contracts": "^1.0.2",
"symfony/dependency-injection": "^4.2",
"symfony/event-dispatcher": "^4.1",
"symfony/http-foundation": "^4.1.2",
"symfony/http-foundation": "^4.3",
"symfony/http-kernel": "^4.2",
"symfony/polyfill-mbstring": "~1.0",
"symfony/filesystem": "~3.4|~4.0",
@@ -43,10 +43,11 @@
"symfony/form": "^4.2",
"symfony/expression-language": "~3.4|~4.0",
"symfony/messenger": "^4.2",
"symfony/mime": "^4.3",
"symfony/process": "~3.4|~4.0",
"symfony/security-core": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
"symfony/serializer": "^4.2",
"symfony/serializer": "^4.3",
"symfony/stopwatch": "~3.4|~4.0",
"symfony/translation": "~4.2",
"symfony/templating": "~3.4|~4.0",
@@ -13,8 +13,7 @@
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
use Symfony\Component\Mime\MimeTypes;
/**
* A file in the file system.
@@ -50,33 +49,28 @@ public function __construct(string $path, bool $checkPath = true)
*
* @return string|null The guessed extension or null if it cannot be guessed
*
* @see ExtensionGuesser
* @see MimeTypes
* @see getMimeType()
*/
public function guessExtension()
{
$type = $this->getMimeType();
$guesser = ExtensionGuesser::getInstance();
return $guesser->guess($type);
return MimeTypes::getDefault()->getExtensions($this->getMimeType())[0] ?? null;
}
/**
* Returns the mime type of the file.
*
* The mime type is guessed using a MimeTypeGuesser instance, which uses finfo(),
* mime_content_type() and the system binary "file" (in this order), depending on
* which of those are available.
* The mime type is guessed using a MimeTypeGuesserInterface instance,
* which uses finfo_file() then the "file" system binary,
* depending on which of those are available.
*
* @return string|null The guessed mime type (e.g. "application/pdf")
*
* @see MimeTypeGuesser
* @see MimeTypes
*/
public function getMimeType()
{
$guesser = MimeTypeGuesser::getInstance();
return $guesser->guess($this->getPathname());
return MimeTypes::getDefault()->guessMimeType($this->getPathname());
}
/**
@@ -11,6 +11,10 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\Mime\MimeTypes;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', ExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED);
/**
* A singleton mime type to file extension guesser.
*
@@ -22,6 +26,8 @@
* $guesser->register(new MyCustomExtensionGuesser());
*
* The last registered guesser is preferred over previously registered ones.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
class ExtensionGuesser implements ExtensionGuesserInterface
{
@@ -11,8 +11,12 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\Mime\MimeTypes;
/**
* Guesses the file extension corresponding to a given mime type.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
interface ExtensionGuesserInterface
{
@@ -13,11 +13,16 @@
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\FileBinaryMimeTypeGuesser as NewFileBinaryMimeTypeGuesser;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileBinaryMimeTypeGuesser::class, NewFileBinaryMimeTypeGuesser::class), E_USER_DEPRECATED);
/**
* Guesses the mime type with the binary "file" (only available on *nix).
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link NewFileBinaryMimeTypeGuesser} instead
*/
class FileBinaryMimeTypeGuesser implements MimeTypeGuesserInterface
{
@@ -13,11 +13,16 @@
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\FileinfoMimeTypeGuesser as NewFileinfoMimeTypeGuesser;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', FileinfoMimeTypeGuesser::class, NewFileinfoMimeTypeGuesser::class), E_USER_DEPRECATED);
/**
* Guesses the mime type using the PECL extension FileInfo.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link NewFileinfoMimeTypeGuesser} instead
*/
class FileinfoMimeTypeGuesser implements MimeTypeGuesserInterface
{
@@ -11,8 +11,14 @@
namespace Symfony\Component\HttpFoundation\File\MimeType;
use Symfony\Component\Mime\MimeTypes;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeExtensionGuesser::class, MimeTypes::class), E_USER_DEPRECATED);
/**
* Provides a best-guess mapping of mime type to file extension.
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
class MimeTypeExtensionGuesser implements ExtensionGuesserInterface
{
@@ -13,6 +13,9 @@
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\MimeTypes;
@trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.3, use "%s" instead.', MimeTypeGuesser::class, MimeTypes::class), E_USER_DEPRECATED);
/**
* A singleton mime type guesser.
@@ -13,11 +13,14 @@
use Symfony\Component\HttpFoundation\File\Exception\AccessDeniedException;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
use Symfony\Component\Mime\MimeTypes;
/**
* Guesses the mime type of a file.
*
* @author Bernhard Schussek <bschussek@gmail.com>
*
* @deprecated since Symfony 4.3, use {@link MimeTypes} instead
*/
interface MimeTypeGuesserInterface
{
@@ -20,7 +20,7 @@
use Symfony\Component\HttpFoundation\File\Exception\NoFileException;
use Symfony\Component\HttpFoundation\File\Exception\NoTmpDirFileException;
use Symfony\Component\HttpFoundation\File\Exception\PartialFileException;
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
use Symfony\Component\Mime\MimeTypes;
/**
* A file uploaded through a form.
@@ -140,10 +140,7 @@ public function getClientMimeType()
*/
public function guessClientExtension()
{
$type = $this->getClientMimeType();
$guesser = ExtensionGuesser::getInstance();
return $guesser->guess($type);
return MimeTypes::getDefault()->getExtensions($this->getClientMimeType())[0] ?? null;
}
/**
Oops, something went wrong.

0 comments on commit db6784b

Please sign in to comment.
You can’t perform that action at this time.