summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Pott2014-06-08 22:27:02 (GMT)
committerAlex Pott2014-06-08 22:27:02 (GMT)
commit17977129e0cd885d9c3a31ef06eae31455a2bf73 (patch)
treeffdf456dc7db56a1e2fe887f8039b5088b319d9d
parent9b821cd3fe3b87dabae95d6f431319946feea35e (diff)
Issue #1921558 by ParisLiakos, xjm, Dave Reid: Convert file_get_mimetype() to use Symfony MimeTypeGuessers.
-rw-r--r--core/core.services.yml9
-rw-r--r--core/includes/file.inc13
-rw-r--r--core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php (renamed from core/includes/file.mimetypes.inc)110
-rw-r--r--core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php92
-rw-r--r--core/lib/Drupal/Core/StreamWrapper/LocalStream.php32
-rw-r--r--core/lib/Drupal/Core/StreamWrapper/StreamWrapperInterface.php16
-rw-r--r--core/modules/system/src/Tests/File/MimeTypeTest.php11
7 files changed, 193 insertions, 90 deletions
diff --git a/core/core.services.yml b/core/core.services.yml
index a8d9d23..8bd4ccb 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -825,3 +825,12 @@ services:
element_info:
class: Drupal\Core\Render\ElementInfo
arguments: ['@module_handler']
+ file.mime_type.guesser:
+ class: Drupal\Core\File\MimeType\MimeTypeGuesser
+ tags:
+ - { name: service_collector, tag: mime_type_guesser, call: addGuesser }
+ file.mime_type.guesser.extension:
+ class: Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser
+ arguments: ['@module_handler']
+ tags:
+ - { name: mime_type_guesser }
diff --git a/core/includes/file.inc b/core/includes/file.inc
index 02bd107..18c2820 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -6,7 +6,6 @@
*/
use Drupal\Component\Utility\UrlHelper;
-use Drupal\Core\StreamWrapper\LocalStream;
use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Component\Utility\Bytes;
use Drupal\Component\Utility\String;
@@ -1300,17 +1299,11 @@ function file_upload_max_size() {
* The internet media type registered for the extension or
* application/octet-stream for unknown extensions.
*
- * @see file_default_mimetype_mapping()
+ * @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
+ * Use \Drupal::service('file.mime_type.guesser')->guess($uri).
*/
function file_get_mimetype($uri, $mapping = NULL) {
- if ($wrapper = file_stream_wrapper_get_instance_by_uri($uri)) {
- return $wrapper->getMimeType($uri, $mapping);
- }
- else {
- // getMimeType() is not implementation specific, so we can directly
- // call it without an instance.
- return LocalStream::getMimeType($uri, $mapping);
- }
+ return \Drupal::service('file.mime_type.guesser')->guess($uri);
}
/**
diff --git a/core/includes/file.mimetypes.inc b/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php
index b6bd404..53712ca 100644
--- a/core/includes/file.mimetypes.inc
+++ b/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php
@@ -2,39 +2,26 @@
/**
* @file
- * Provides mimetype mappings.
+ * Contains \Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser
*/
-/**
- * Return an array of MIME extension mappings.
- *
- * Returns the mapping after modules have altered the default mapping.
- *
- * @return
- * Array of mimetypes correlated to the extensions that relate to them.
- *
- * @see file_get_mimetype()
- */
-function file_mimetype_mapping() {
- $mapping = &drupal_static(__FUNCTION__);
- if (!isset($mapping)) {
- $mapping = file_default_mimetype_mapping();
- // Allow modules to alter the default mapping.
- \Drupal::moduleHandler()->alter('file_mimetype_mapping', $mapping);
- }
- return $mapping;
-}
+namespace Drupal\Core\File\MimeType;
+
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
/**
- * Default MIME extension mapping.
- *
- * @return
- * Array of mimetypes correlated to the extensions that relate to them.
- *
- * @see file_get_mimetype()
+ * Makes possible to guess the MIME type of a file using its extension.
*/
-function file_default_mimetype_mapping() {
- return array(
+class ExtensionMimeTypeGuesser implements MimeTypeGuesserInterface {
+
+ /**
+ * Default MIME extension mapping.
+ *
+ * @var array
+ * Array of mimetypes correlated to the extensions that relate to them.
+ */
+ protected $defaultMapping = array(
'mimetypes' => array(
0 => 'application/andrew-inset',
1 => 'application/atom',
@@ -876,4 +863,71 @@ function file_default_mimetype_mapping() {
'vtt' => 358,
),
);
+
+ /**
+ * The MIME types mapping array after going through the module handler.
+ *
+ * @var array
+ */
+ protected $mapping;
+
+ /**
+ * The module handler.
+ *
+ * @var \Drupal\Core\Extension\ModuleHandlerInterface
+ */
+ protected $moduleHandler;
+
+ /**
+ * Constructs a new ExtensionMimeTypeGuesser.
+ *
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
+ */
+ public function __construct(ModuleHandlerInterface $module_handler) {
+ $this->moduleHandler = $module_handler;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function guess($path) {
+ if ($this->mapping === NULL) {
+ $mapping = $this->defaultMapping;
+ // Allow modules to alter the default mapping.
+ $this->moduleHandler->alter('file_mimetype_mapping', $mapping);
+ $this->mapping = $mapping;
+ }
+
+ $extension = '';
+ $file_parts = explode('.', drupal_basename($path));
+
+ // Remove the first part: a full filename should not match an extension.
+ array_shift($file_parts);
+
+ // Iterate over the file parts, trying to find a match.
+ // For my.awesome.image.jpeg, we try:
+ // - jpeg
+ // - image.jpeg, and
+ // - awesome.image.jpeg
+ while ($additional_part = array_pop($file_parts)) {
+ $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
+ if (isset($this->mapping['extensions'][$extension])) {
+ return $this->mapping['mimetypes'][$this->mapping['extensions'][$extension]];
+ }
+ }
+
+ return 'application/octet-stream';
+ }
+
+ /**
+ * Sets the mimetypes/extension mapping to use when guessing mimetype.
+ *
+ * @param array|null $mapping
+ * Passing a NULL mapping will cause guess() to use self::$defaultMapping.
+ */
+ public function setMapping(array $mapping = NULL) {
+ $this->mapping = $mapping;
+ }
+
}
diff --git a/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php
new file mode 100644
index 0000000..d0d51ae
--- /dev/null
+++ b/core/lib/Drupal/Core/File/MimeType/MimeTypeGuesser.php
@@ -0,0 +1,92 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\File\MimeType\MimeTypeGuesser.
+ */
+
+namespace Drupal\Core\File\MimeType;
+
+use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
+
+/**
+ * Defines a MIME type guesser that also supports stream wrapper paths.
+ */
+class MimeTypeGuesser implements MimeTypeGuesserInterface {
+
+ /**
+ * An array of arrays of registered guessers keyed by priority.
+ *
+ * @var array
+ */
+ protected $guessers = array();
+
+ /**
+ * Holds the array of guessers sorted by priority.
+ *
+ * If this is NULL a rebuild will be triggered.
+ *
+ * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface[]
+ *
+ * @see \Drupal\Core\File\MimeType\MimeTypeGuesser::addGuesser()
+ * @see \Drupal\Core\File\MimeType\MimeTypeGuesser::sortGuessers()
+ */
+ protected $sortedGuessers = NULL;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function guess($path) {
+ if ($wrapper = file_stream_wrapper_get_instance_by_uri($path)) {
+ // Get the real path from the stream wrapper.
+ $path = $wrapper->realpath();
+ }
+
+ if ($this->sortedGuessers === NULL) {
+ // Sort is not trigerred yet.
+ $this->sortedGuessers = $this->sortGuessers();
+ }
+
+ foreach ($this->sortedGuessers as $guesser) {
+ $mime_type = $guesser->guess($path);
+ if ($mime_type !== NULL) {
+ return $mime_type;
+ }
+ }
+ }
+
+ /**
+ * Appends a MIME type guesser to the guessers chain.
+ *
+ * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $guesser
+ * The guesser to be appended.
+ * @param int $priority
+ * The priority of the guesser being added.
+ *
+ * @return self
+ * The called object.
+ */
+ public function addGuesser(MimeTypeGuesserInterface $guesser, $priority = 0) {
+ $this->guessers[$priority][] = $guesser;
+ // Mark sorted guessers for rebuild.
+ $this->sortedGuessers = NULL;
+ return $this;
+ }
+
+ /**
+ * Sorts guessers according to priority.
+ *
+ * @return \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface[]
+ * A sorted array of MIME type guesser objects.
+ */
+ protected function sortGuessers() {
+ $sorted = array();
+ krsort($this->guessers);
+
+ foreach ($this->guessers as $guesser) {
+ $sorted = array_merge($sorted, $guesser);
+ }
+ return $sorted;
+ }
+
+}
diff --git a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
index 86d0e63..937953f 100644
--- a/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
+++ b/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
@@ -94,38 +94,6 @@ abstract class LocalStream implements StreamWrapperInterface {
}
/**
- * Implements Drupal\Core\StreamWrapper\StreamWrapperInterface::getMimeType().
- */
- static function getMimeType($uri, $mapping = NULL) {
- if (!isset($mapping)) {
- // The default file map, defined in file.mimetypes.inc is quite big.
- // We only load it when necessary.
- include_once DRUPAL_ROOT . '/core/includes/file.mimetypes.inc';
- $mapping = file_mimetype_mapping();
- }
-
- $extension = '';
- $file_parts = explode('.', drupal_basename($uri));
-
- // Remove the first part: a full filename should not match an extension.
- array_shift($file_parts);
-
- // Iterate over the file parts, trying to find a match.
- // For my.awesome.image.jpeg, we try:
- // - jpeg
- // - image.jpeg, and
- // - awesome.image.jpeg
- while ($additional_part = array_pop($file_parts)) {
- $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
- if (isset($mapping['extensions'][$extension])) {
- return $mapping['mimetypes'][$mapping['extensions'][$extension]];
- }
- }
-
- return 'application/octet-stream';
- }
-
- /**
* Implements Drupal\Core\StreamWrapper\StreamWrapperInterface::realpath().
*/
function realpath() {
diff --git a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperInterface.php b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperInterface.php
index 11ad30d..3f9f5d4 100644
--- a/core/lib/Drupal/Core/StreamWrapper/StreamWrapperInterface.php
+++ b/core/lib/Drupal/Core/StreamWrapper/StreamWrapperInterface.php
@@ -62,22 +62,6 @@ interface StreamWrapperInterface extends PhpStreamWrapperInterface {
public function getExternalUrl();
/**
- * Returns the MIME type of the resource.
- *
- * @param string $uri
- * The URI, path, or filename.
- * @param array $mapping
- * An optional map of extensions to their mimetypes, in the form:
- * - 'mimetypes': a list of mimetypes, keyed by an identifier,
- * - 'extensions': the mapping itself, an associative array in which
- * the key is the extension and the value is the mimetype identifier.
- *
- * @return string
- * Returns a string containing the MIME type of the resource.
- */
- public static function getMimeType($uri, $mapping = NULL);
-
- /**
* Returns canonical, absolute path of the resource.
*
* Implementation placeholder. PHP's realpath() does not support stream
diff --git a/core/modules/system/src/Tests/File/MimeTypeTest.php b/core/modules/system/src/Tests/File/MimeTypeTest.php
index e9c388d..85d7e7f 100644
--- a/core/modules/system/src/Tests/File/MimeTypeTest.php
+++ b/core/modules/system/src/Tests/File/MimeTypeTest.php
@@ -50,18 +50,19 @@ class MimeTypeTest extends FileTestBase {
'test.ogg' => 'audio/ogg',
);
+ $guesser = $this->container->get('file.mime_type.guesser');
// Test using default mappings.
foreach ($test_case as $input => $expected) {
// Test stream [URI].
- $output = file_get_mimetype($prefix . $input);
+ $output = $guesser->guess($prefix . $input);
$this->assertIdentical($output, $expected, format_string('Mimetype for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
// Test normal path equivalent
- $output = file_get_mimetype($input);
+ $output = $guesser->guess($input);
$this->assertIdentical($output, $expected, format_string('Mimetype (using default mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
}
- // Now test passing in the map.
+ // Now test the extension gusser by passing in a custom mapping.
$mapping = array(
'mimetypes' => array(
0 => 'application/java-archive',
@@ -88,9 +89,11 @@ class MimeTypeTest extends FileTestBase {
'foo.doc' => 'application/octet-stream',
'test.ogg' => 'application/octet-stream',
);
+ $extension_guesser = $this->container->get('file.mime_type.guesser.extension');
+ $extension_guesser->setMapping($mapping);
foreach ($test_case as $input => $expected) {
- $output = file_get_mimetype($input, $mapping);
+ $output = $extension_guesser->guess($input);
$this->assertIdentical($output, $expected, format_string('Mimetype (using passed-in mappings) for %input is %output (expected: %expected).', array('%input' => $input, '%output' => $output, '%expected' => $expected)));
}
}