diff --git a/core/core.services.yml b/core/core.services.yml index f5ed5db..ef31454 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1039,9 +1039,23 @@ services: file.mime_type.guesser: class: Drupal\Core\File\MimeType\MimeTypeGuesser tags: - - { name: service_collector, tag: mime_type_guesser, call: addGuesser } + - { name: service_collector, tag: mime_type_guesser_extension, call: addGuesser } + file.mime_type.guesser.content_based: + class: Drupal\Core\File\MimeType\MimeTypeGuesser + tags: + - { name: service_collector, tag: mime_type_guesser_content_based, call: addGuesser } file.mime_type.guesser.extension: class: Drupal\Core\File\MimeType\ExtensionMimeTypeGuesser arguments: ['@module_handler'] tags: - - { name: mime_type_guesser } + - { name: mime_type_guesser_extension } + - { name: mime_type_guesser_content_based, priority: 10 } + mime_type.guesser.finfo: + class: Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser + tags: + - { name: mime_type_guesser_content_based, priority: 30 } + mime_type.guesser.binary: + class: Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser + arguments: ['@module_handler'] + tags: + - { name: mime_type_guesser_content_based, priority: 20 } diff --git a/core/lib/Drupal/Core/Image/Image.php b/core/lib/Drupal/Core/Image/Image.php index e170991..727df9d 100644 --- a/core/lib/Drupal/Core/Image/Image.php +++ b/core/lib/Drupal/Core/Image/Image.php @@ -34,13 +34,6 @@ class Image implements ImageInterface { protected $toolkit; /** - * File size in bytes. - * - * @var int - */ - protected $fileSize; - - /** * Constructs a new Image object. * * @param \Drupal\Core\ImageToolkit\ImageToolkitInterface $toolkit @@ -55,9 +48,7 @@ public function __construct(ImageToolkitInterface $toolkit, $source = NULL) { if ($source) { $this->source = $source; // Defer image file validity check to the toolkit. - if ($this->getToolkit()->parseFile()) { - $this->fileSize = filesize($this->source); - } + $this->getToolkit()->parseFile(); } } @@ -85,13 +76,6 @@ public function getWidth() { /** * {@inheritdoc} */ - public function getFileSize() { - return $this->fileSize; - } - - /** - * {@inheritdoc} - */ public function getMimeType() { return $this->getToolkit()->getMimeType(); } @@ -130,7 +114,6 @@ public function save($destination = NULL) { if ($return = $this->getToolkit()->save($destination)) { // Clear the cached file size and refresh the image information. clearstatcache(TRUE, $destination); - $this->fileSize = filesize($destination); $this->source = $destination; // @todo Use File utility when https://drupal.org/node/2050759 is in. diff --git a/core/lib/Drupal/Core/Image/ImageInterface.php b/core/lib/Drupal/Core/Image/ImageInterface.php index 02db478..525b931 100644 --- a/core/lib/Drupal/Core/Image/ImageInterface.php +++ b/core/lib/Drupal/Core/Image/ImageInterface.php @@ -37,14 +37,6 @@ public function getHeight(); public function getWidth(); /** - * Returns the size of the image file. - * - * @return int|null - * The size of the file in bytes, or NULL if the image is invalid. - */ - public function getFileSize(); - - /** * Returns the MIME type of the image file. * * @return string diff --git a/core/modules/file/file.module b/core/modules/file/file.module index a516836..62e924e 100644 --- a/core/modules/file/file.module +++ b/core/modules/file/file.module @@ -462,7 +462,7 @@ function file_validate_image_resolution(FileInterface $file, $maximum_dimensions // Try to resize the image to fit the dimensions. if ($image->scale($width, $height)) { $image->save(); - $file->filesize = $image->getFileSize(); + $file->setSize(filesize($file->getFileUri())); drupal_set_message(t('The image was resized to fit within the maximum allowed dimensions of %dimensions pixels.', array('%dimensions' => $maximum_dimensions))); } else { diff --git a/core/modules/image/image.module b/core/modules/image/image.module index 913fb7f..df0b675 100644 --- a/core/modules/image/image.module +++ b/core/modules/image/image.module @@ -156,6 +156,13 @@ function image_theme() { * Implements hook_file_download(). * * Control the access to files underneath the styles directory. + * + * The ImageStyleDownloadController does not call this hook when it is about to + * create a derivative. Thus for files under the styles directory, this hook is + * only called when the derivative already exists. + * + * This hook allows access if the user has access to the original and denies + * access when the user has not access to the original. */ function image_file_download($uri) { $path = file_uri_target($uri); @@ -170,25 +177,23 @@ function image_file_download($uri) { // Then the remaining parts are the path to the image. $original_uri = file_uri_scheme($uri) . '://' . implode('/', $args); - // Check that the file exists and is an image. - $image = \Drupal::service('image.factory')->get($uri); - if ($image->isValid()) { - // Check the permissions of the original to grant access to this image. - $headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri)); - // Confirm there's at least one module granting access and none denying access. - if (!empty($headers) && !in_array(-1, $headers)) { - return array( - // Send headers describing the image's size, and MIME-type... - 'Content-Type' => $image->getMimeType(), - 'Content-Length' => $image->getFileSize(), - // By not explicitly setting them here, this uses normal Drupal - // Expires, Cache-Control and ETag headers to prevent proxy or - // browser caching of private images. - ); - } + // Check the permissions of the original to grant access to this image. + $headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri)); + // Confirm there's at least one module granting access and none denying access. + if (!empty($headers) && !in_array(-1, $headers)) { + return array( + // Send headers describing the image's size and MIME type. + 'Content-Type' => \Drupal::service('file.mime_type.guesser.content_based')->guess($uri), + 'Content-Length' => filesize($uri), + // By not explicitly setting cache related headers here, this uses + // normal Drupal Expires, Cache-Control and ETag headers to prevent + // proxy or browser caching of private images. + ); } return -1; } + // We don't want a say over files outside the styles directory. + return NULL; } /** diff --git a/core/modules/image/src/Controller/ImageStyleDownloadController.php b/core/modules/image/src/Controller/ImageStyleDownloadController.php index a18c677..6b5ef30 100644 --- a/core/modules/image/src/Controller/ImageStyleDownloadController.php +++ b/core/modules/image/src/Controller/ImageStyleDownloadController.php @@ -8,13 +8,13 @@ namespace Drupal\image\Controller; use Drupal\Component\Utility\Crypt; -use Drupal\Core\Image\ImageFactory; use Drupal\Core\Lock\LockBackendInterface; use Drupal\image\ImageStyleInterface; use Drupal\system\FileDownloadController; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -33,11 +33,11 @@ class ImageStyleDownloadController extends FileDownloadController { protected $lock; /** - * The image factory. + * The MIME type guesser. * - * @var \Drupal\Core\Image\ImageFactory + * @var \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface */ - protected $imageFactory; + protected $mimeTypeGuesser; /** * A logger instance. @@ -51,14 +51,14 @@ class ImageStyleDownloadController extends FileDownloadController { * * @param \Drupal\Core\Lock\LockBackendInterface $lock * The lock backend. - * @param \Drupal\Core\Image\ImageFactory $image_factory - * The image factory. + * @param \Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface $mimeTypeGuesser + * The MIME type guesser. * @param \Psr\Log\LoggerInterface $logger * A logger instance. */ - public function __construct(LockBackendInterface $lock, ImageFactory $image_factory, LoggerInterface $logger) { + public function __construct(LockBackendInterface $lock, MimeTypeGuesserInterface $mimeTypeGuesser, LoggerInterface $logger) { $this->lock = $lock; - $this->imageFactory = $image_factory; + $this->mimeTypeGuesser = $mimeTypeGuesser; $this->logger = $logger; } @@ -68,7 +68,7 @@ public function __construct(LockBackendInterface $lock, ImageFactory $image_fact public static function create(ContainerInterface $container) { return new static( $container->get('lock'), - $container->get('image.factory'), + $container->get('file.mime_type.guesser.content_based'), $container->get('logger.factory')->get('image') ); } @@ -155,13 +155,11 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st } if ($success) { - $image = $this->imageFactory->get($derivative_uri); - $uri = $image->getSource(); $headers += array( - 'Content-Type' => $image->getMimeType(), - 'Content-Length' => $image->getFileSize(), + 'Content-Type' => $this->mimeTypeGuesser->guess($derivative_uri), + 'Content-Length' => filesize($derivative_uri), ); - return new BinaryFileResponse($uri, 200, $headers); + return new BinaryFileResponse($derivative_uri, 200, $headers); } else { $this->logger->notice('Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php index 0579dbc..8d77622 100644 --- a/core/modules/image/src/Entity/ImageStyle.php +++ b/core/modules/image/src/Entity/ImageStyle.php @@ -196,7 +196,7 @@ public function buildUrl($path, $clean_urls = NULL) { // 'image.settings:suppress_itok_output' configuration to TRUE to achieve // that (if both are set, the security token will neither be emitted in the // image derivative URL nor checked for in - // \Drupal\image\ImageStyleInterface::deliver()). + // \Drupal\image\Controller\ImageStyleDownloadController::deliver()). $token_query = array(); if (!\Drupal::config('image.settings')->get('suppress_itok_output')) { // The passed $path variable can be either a relative path or a full URI. diff --git a/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php b/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php index b57ce9f..0f04199 100644 --- a/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php +++ b/core/modules/image/src/Tests/ImageStylesPathAndUrlTest.php @@ -173,9 +173,8 @@ function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = $this->assertResponse(200, 'Image was generated at the URL.'); $this->assertTrue(file_exists($generated_uri), 'Generated file does exist after we accessed it.'); $this->assertRaw(file_get_contents($generated_uri), 'URL returns expected file.'); - $image = $this->container->get('image.factory')->get($generated_uri); - $this->assertEqual($this->drupalGetHeader('Content-Type'), $image->getMimeType(), 'Expected Content-Type was reported.'); - $this->assertEqual($this->drupalGetHeader('Content-Length'), $image->getFileSize(), 'Expected Content-Length was reported.'); + $this->assertEqual($this->drupalGetHeader('Content-Type'), $this->container->get('file.mime_type.guesser.content_based')->guess($generated_uri), 'Expected Content-Type was reported.'); + $this->assertEqual($this->drupalGetHeader('Content-Length'), filesize($generated_uri), 'Expected Content-Length was reported.'); if ($scheme == 'private') { $this->assertEqual($this->drupalGetHeader('Expires'), 'Sun, 19 Nov 1978 05:00:00 GMT', 'Expires header was sent.'); $this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.'); diff --git a/core/tests/Drupal/Tests/Core/Image/ImageTest.php b/core/tests/Drupal/Tests/Core/Image/ImageTest.php index fa91f28..4ecaad2 100644 --- a/core/tests/Drupal/Tests/Core/Image/ImageTest.php +++ b/core/tests/Drupal/Tests/Core/Image/ImageTest.php @@ -162,14 +162,6 @@ public function testGetWidth() { } /** - * Tests \Drupal\Core\Image\Image::getFileSize - */ - public function testGetFileSize() { - $this->getTestImage(FALSE); - $this->assertEquals(3905, $this->image->getFileSize()); - } - - /** * Tests \Drupal\Core\Image\Image::getToolkit()->getType(). */ public function testGetType() {