Verified Commit 23edd01f authored by Alex Pott's avatar Alex Pott
Browse files

Issue #2583041 by mondrake, fietserwin, claudiu.cristea, alexpott, catch: GD...

Issue #2583041 by mondrake, fietserwin, claudiu.cristea, alexpott, catch: GD toolkit & operations should catch \Throwable to fail gracefully in case of errors
parent 55a12077
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -127,8 +127,14 @@ public function apply($operation, array $arguments = []) {
      $this->logger->error("The selected image handling toolkit '@toolkit' can not process operation '@operation'.", ['@toolkit' => $this->getPluginId(), '@operation' => $operation]);
      return FALSE;
    }
    catch (\InvalidArgumentException $e) {
      $this->logger->warning($e->getMessage(), []);
    catch (\Throwable $t) {
      $this->logger->warning("The image toolkit '@toolkit' failed processing '@operation' for image '@image'. Reported error: @class - @message", [
        '@toolkit' => $this->getPluginId(),
        '@operation' => $operation,
        '@image' => $this->getSource(),
        '@class' => get_class($t),
        '@message' => $t->getMessage(),
      ]);
      return FALSE;
    }
  }
+3 −0
Original line number Diff line number Diff line
@@ -185,6 +185,9 @@ final public function apply(array $arguments) {
   *
   * @return bool
   *   TRUE if the operation was performed successfully, FALSE otherwise.
   *
   * @throws \RuntimeException
   *   If the operation can not be performed.
   */
  abstract protected function execute(array $arguments);

+69 −24
Original line number Diff line number Diff line
@@ -180,8 +180,33 @@ protected function load() {
      return FALSE;
    }

    // Invalidate the image object and return if there's no function to load the
    // image file.
    $function = 'imagecreatefrom' . image_type_to_extension($this->getType(), FALSE);
    if (function_exists($function) && $resource = $function($this->getSource())) {
    if (!function_exists($function)) {
      $this->logger->error("The image toolkit '@toolkit' can not process image '@image'.", [
        '@toolkit' => $this->getPluginId(),
        '@image' => $this->getSource(),
      ]);
      $this->preLoadInfo = NULL;
      return FALSE;
    }

    // Invalidate the image object and return if the load fails.
    try {
      $resource = $function($this->getSource());
    }
    catch (\Throwable $t) {
      $this->logger->error("The image toolkit '@toolkit' failed loading image '@image'. Reported error: @class - @message", [
        '@toolkit' => $this->getPluginId(),
        '@image' => $this->getSource(),
        '@class' => get_class($t),
        '@message' => $t->getMessage(),
      ]);
      $this->preLoadInfo = NULL;
      return FALSE;
    }

    $this->setResource($resource);
    if (imageistruecolor($resource)) {
      return TRUE;
@@ -204,8 +229,6 @@ protected function load() {
    }
    return (bool) $this->getResource();
  }
    return FALSE;
  }

  /**
   * {@inheritdoc}
@@ -236,16 +259,38 @@ public function save($destination) {
      return FALSE;
    }
    if ($this->getType() == IMAGETYPE_JPEG) {
      try {
        $success = $function($this->getResource(), $destination, $this->configFactory->get('system.image.gd')->get('jpeg_quality'));
      }
      catch (\Throwable $t) {
        $this->logger->error("The image toolkit '@toolkit' failed saving image '@image'. Reported error: @class - @message", [
          '@toolkit' => $this->getPluginId(),
          '@image' => $destination,
          '@class' => get_class($t),
          '@message' => $t->getMessage(),
        ]);
        $success = FALSE;
      }
    }
    else {
      // Image types that support alpha need to be saved accordingly.
      if (in_array($this->getType(), [IMAGETYPE_PNG, IMAGETYPE_WEBP], TRUE)) {
        imagealphablending($this->getResource(), FALSE);
        imagesavealpha($this->getResource(), TRUE);
      }
      try {
        $success = $function($this->getResource(), $destination);
      }
      catch (\Throwable $t) {
        $this->logger->error("The image toolkit '@toolkit' failed saving image '@image'. Reported error: @class - @message", [
          '@toolkit' => $this->getPluginId(),
          '@image' => $destination,
          '@class' => get_class($t),
          '@message' => $t->getMessage(),
        ]);
        $success = FALSE;
      }
    }
    // Move temporary local file to remote destination.
    if (isset($permanent_destination) && $success) {
      try {
+33 −0
Original line number Diff line number Diff line
@@ -452,6 +452,39 @@ public function testCreateNewFailures(): void {
    $this->assertTrue($image->isValid(), 'CreateNew with valid arguments validates the Image.');
  }

  /**
   * Tests creation of an image that will exceed the memory limit.
   */
  public function testInsufficientMemory(): void {
    // ini_get() may return -1 or null for memory_limit to indicate there is no
    // limit set. In that case, we need to skip this test.
    $size = ini_get('memory_limit');
    if (!$size || (int) $size === -1) {
      $this->markTestSkipped("There is no memory limit set in the PHP environment.");
    }

    $image = $this->imageFactory->get('core/tests/fixtures/files/image-test.png');

    $oldGdImage = $image->getToolkit()->getResource();
    $this->assertFalse($image->createNew(2000000, 2000000));
    $newGdImage = $image->getToolkit()->getResource();

    // Check that a new resource has not been created, and the old one is still
    // valid.
    $this->assertEquals($oldGdImage, $newGdImage);
  }

  /**
   * Tests resizing of an image that will exceed the memory available.
   */
  public function testInsufficientAvailableMemory(): void {
    $image = $this->imageFactory->get('core/tests/fixtures/files/image-test.png');

    $memory_in_use = memory_get_usage(TRUE);
    ini_set('memory_limit', $memory_in_use + 2048);
    $this->assertFalse($image->resize(200000, 200000));
  }

  /**
   * Tests for GIF images with transparency.
   */