Verified Commit 31f9e8a9 authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2786735 by recrit, eiriksm, ranjith_kumar_k_u, immaculatexavier,...

Issue #2786735 by recrit, eiriksm, ranjith_kumar_k_u, immaculatexavier, ravi.shankar, zaporylie, smustgrave, TrevorBradley, johnle, GaëlG, jefuri, alexpott, poker10: Image derivative generation does not work if effect "Convert" in use and file stored in private filesystem
parent f60bcea7
Loading
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
use Drupal\field\FieldConfigInterface;
use Drupal\field\FieldStorageConfigInterface;
use Drupal\file\FileInterface;
use Drupal\image\Controller\ImageStyleDownloadController;
use Drupal\image\Entity\ImageStyle;

/**
@@ -151,6 +152,18 @@ function image_file_download($uri) {
    // Check that the file exists and is an image.
    $image = \Drupal::service('image.factory')->get($uri);
    if ($image->isValid()) {
      // If the image style converted the extension, it has been added to the
      // original file, resulting in filenames like image.png.jpeg. So to find
      // the actual source image, we remove the extension and check if that
      // image exists.
      if (!file_exists($original_uri)) {
        $converted_original_uri = ImageStyleDownloadController::getUriWithoutConvertedExtension($original_uri);
        if ($converted_original_uri !== $original_uri && file_exists($converted_original_uri)) {
          // The converted file does exist, use it as the source.
          $original_uri = $converted_original_uri;
        }
      }

      // Check the permissions of the original to grant access to this image.
      $headers = \Drupal::moduleHandler()->invokeAll('file_download', [$original_uri]);
      // Confirm there's at least one module granting access and none denying access.
+47 −18
Original line number Diff line number Diff line
@@ -173,6 +173,24 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st

    $headers = [];

    // Don't try to generate file if source is missing.
    if ($image_uri !== $sample_image_uri && !$this->sourceImageExists($image_uri, $token_is_valid)) {
      // If the image style converted the extension, it has been added to the
      // original file, resulting in filenames like image.png.jpeg. So to find
      // the actual source image, we remove the extension and check if that
      // image exists.
      $converted_image_uri = static::getUriWithoutConvertedExtension($image_uri);
      if ($converted_image_uri !== $image_uri &&
          $this->sourceImageExists($converted_image_uri, $token_is_valid)) {
        // The converted file does exist, use it as the source.
        $image_uri = $converted_image_uri;
      }
      else {
        $this->logger->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', ['%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri]);
        return new Response($this->t('Error generating image, missing source file.'), 404);
      }
    }

    // If not using a public scheme, let other modules provide headers and
    // control access to the file.
    if (!$is_public) {
@@ -183,28 +201,12 @@ public function deliver(Request $request, $scheme, ImageStyleInterface $image_st
    }

    // If it is default sample.png, ignore scheme.
    // This value swap must be done after hook_file_download is called since
    // the hooks are expecting a URI, not a file path.
    if ($image_uri === $sample_image_uri) {
      $image_uri = $target;
    }

    // Don't try to generate file if source is missing.
    if (!$this->sourceImageExists($image_uri, $token_is_valid)) {
      // If the image style converted the extension, it has been added to the
      // original file, resulting in filenames like image.png.jpeg. So to find
      // the actual source image, we remove the extension and check if that
      // image exists.
      $path_info = pathinfo(StreamWrapperManager::getTarget($image_uri));
      $converted_image_uri = sprintf('%s://%s%s%s', $this->streamWrapperManager->getScheme($derivative_uri), $path_info['dirname'], DIRECTORY_SEPARATOR, $path_info['filename']);
      if (!$this->sourceImageExists($converted_image_uri, $token_is_valid)) {
        $this->logger->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', ['%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri]);
        return new Response($this->t('Error generating image, missing source file.'), 404);
      }
      else {
        // The converted file does exist, use it as the source.
        $image_uri = $converted_image_uri;
      }
    }

    // Don't start generating the image if the derivative already exists or if
    // generation is in progress in another thread.
    if (!file_exists($derivative_uri)) {
@@ -283,4 +285,31 @@ private function sourceImageExists(string $image_uri, bool $token_is_valid): boo
    return TRUE;
  }

  /**
   * Get the file URI without the extension from any conversion image style.
   *
   * If the image style converted the image, then an extension has been added
   * to the original file, resulting in filenames like image.png.jpeg.
   *
   * @param string $uri
   *   The file URI.
   *
   * @return string
   *   The file URI without the extension from any conversion image style.
   */
  public static function getUriWithoutConvertedExtension(string $uri): string {
    $original_uri = $uri;
    $path_info = pathinfo(StreamWrapperManager::getTarget($uri));
    // Only convert the URI when the filename still has an extension.
    if (!empty($path_info['filename']) && pathinfo($path_info['filename'], PATHINFO_EXTENSION)) {
      $original_uri = StreamWrapperManager::getScheme($uri) . '://';
      if (!empty($path_info['dirname']) && $path_info['dirname'] !== '.') {
        $original_uri .= $path_info['dirname'] . DIRECTORY_SEPARATOR;
      }
      $original_uri .= $path_info['filename'];
    }

    return $original_uri;
  }

}
+16 −0
Original line number Diff line number Diff line
@@ -122,6 +122,22 @@ public function testImageStyleUrlExtraSlash() {
    $this->doImageStyleUrlAndPathTests('public', TRUE, TRUE);
  }

  /**
   * Test an image style URL with a private file that also gets converted.
   */
  public function testImageStylePrivateWithConversion(): void {
    // Add the "convert" image style effect to our style.
    $this->style->addImageEffect([
      'uuid' => '',
      'id' => 'image_convert',
      'weight' => 1,
      'data' => [
        'extension' => 'jpeg',
      ],
    ]);
    $this->doImageStyleUrlAndPathTests('private');
  }

  /**
   * Tests that an invalid source image returns a 404.
   */