/** * {@inheritdoc} */ public function access(AccountInterface $account = NULL) { if (!parent::access($account)) { return FALSE; } if ($entity = $this->getEntityFromContext()) { return $this->imageFactory->get($entity->getFileUri())->isValid(); } return TRUE; }
/** * Tests using entity fields of the image field type. */ public function testImageItem() { // Create a test entity with the image field set. $entity = EntityTest::create(); $entity->image_test->target_id = $this->image->id(); $entity->image_test->alt = $alt = $this->randomMachineName(); $entity->image_test->title = $title = $this->randomMachineName(); $entity->name->value = $this->randomMachineName(); $entity->save(); $entity = entity_load('entity_test', $entity->id()); $this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.'); $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); $this->assertEqual($entity->image_test->target_id, $this->image->id()); $this->assertEqual($entity->image_test->alt, $alt); $this->assertEqual($entity->image_test->title, $title); $image = $this->imageFactory->get('public://example.jpg'); $this->assertEqual($entity->image_test->width, $image->getWidth()); $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); // Make sure the computed entity reflects updates to the referenced file. file_unmanaged_copy(\Drupal::root() . '/core/misc/druplicon.png', 'public://example-2.jpg'); $image2 = File::create(['uri' => 'public://example-2.jpg']); $image2->save(); $entity->image_test->target_id = $image2->id(); $entity->image_test->alt = $new_alt = $this->randomMachineName(); // The width and height is only updated when width is not set. $entity->image_test->width = NULL; $entity->save(); $this->assertEqual($entity->image_test->entity->id(), $image2->id()); $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); $image = $this->imageFactory->get('public://example-2.jpg'); $this->assertEqual($entity->image_test->width, $image->getWidth()); $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->alt, $new_alt); // Check that the image item can be set to the referenced file directly. $entity->image_test = $this->image; $this->assertEqual($entity->image_test->target_id, $this->image->id()); // Delete the image and try to save the entity again. $this->image->delete(); $entity = EntityTest::create(array('mame' => $this->randomMachineName())); $entity->save(); // Test image item properties. $expected = array('target_id', 'entity', 'alt', 'title', 'width', 'height'); $properties = $entity->getFieldDefinition('image_test')->getFieldStorageDefinition()->getPropertyDefinitions(); $this->assertEqual(array_keys($properties), $expected); // Test the generateSampleValue() method. $entity = EntityTest::create(); $entity->image_test->generateSampleItems(); $this->entityValidateAndSave($entity); $this->assertEqual($entity->image_test->entity->get('filemime')->value, 'image/jpeg'); }
/** * Tests using entity fields of the image field type. */ public function testImageItem() { // Create a test entity with the image field set. $entity = entity_create('entity_test'); $entity->image_test->target_id = $this->image->id(); $entity->image_test->alt = $alt = $this->randomMachineName(); $entity->image_test->title = $title = $this->randomMachineName(); $entity->name->value = $this->randomMachineName(); $entity->save(); $entity = entity_load('entity_test', $entity->id()); $this->assertTrue($entity->image_test instanceof FieldItemListInterface, 'Field implements interface.'); $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.'); $this->assertEqual($entity->image_test->target_id, $this->image->id()); $this->assertEqual($entity->image_test->alt, $alt); $this->assertEqual($entity->image_test->title, $title); $image = $this->imageFactory->get('public://example.jpg'); $this->assertEqual($entity->image_test->width, $image->getWidth()); $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->entity->id(), $this->image->id()); $this->assertEqual($entity->image_test->entity->uuid(), $this->image->uuid()); // Make sure the computed entity reflects updates to the referenced file. file_unmanaged_copy(DRUPAL_ROOT . '/core/misc/feed.png', 'public://example-2.jpg'); $image2 = entity_create('file', array('uri' => 'public://example-2.jpg')); $image2->save(); $entity->image_test->target_id = $image2->id(); $entity->image_test->alt = $new_alt = $this->randomMachineName(); // The width and height is only updated when width is not set. $entity->image_test->width = NULL; $entity->save(); $this->assertEqual($entity->image_test->entity->id(), $image2->id()); $this->assertEqual($entity->image_test->entity->getFileUri(), $image2->getFileUri()); $image = $this->imageFactory->get('public://example-2.jpg'); $this->assertEqual($entity->image_test->width, $image->getWidth()); $this->assertEqual($entity->image_test->height, $image->getHeight()); $this->assertEqual($entity->image_test->alt, $new_alt); // Check that the image item can be set to the referenced file directly. $entity->image_test = $this->image; $this->assertEqual($entity->image_test->target_id, $this->image->id()); // Delete the image and try to save the entity again. $this->image->delete(); $entity = entity_create('entity_test', array('mame' => $this->randomMachineName())); $entity->save(); // Test the generateSampleValue() method. $entity = entity_create('entity_test'); $entity->image_test->generateSampleItems(); $this->entityValidateAndSave($entity); }
/** * Tests usage of the image field formatters. */ function testImageFormatterTheme() { /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = $this->container->get('renderer'); // Create an image. $files = $this->drupalGetTestFiles('image'); $file = reset($files); $original_uri = file_unmanaged_copy($file->uri, 'public://', FILE_EXISTS_RENAME); // Create a style. $style = entity_create('image_style', array('name' => 'test', 'label' => 'Test')); $style->save(); $url = $style->buildUrl($original_uri); // Create a test entity with the image field set. $entity = entity_create('entity_test'); $entity->image_test->target_id = $this->image->id(); $entity->image_test->alt = NULL; $entity->image_test->uri = $original_uri; $image = $this->imageFactory->get('public://example.jpg'); $entity->save(); // Create the base element that we'll use in the tests below. $path = $this->randomMachineName(); $base_element = array('#theme' => 'image_formatter', '#image_style' => 'test', '#item' => $entity->image_test, '#url' => Url::fromUri('base:' . $path)); // Test using theme_image_formatter() with a NULL value for the alt option. $element = $base_element; $this->setRawContent($renderer->renderRoot($element)); $elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height]', array(':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight())); $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders with a NULL value for the alt option.'); // Test using theme_image_formatter() without an image title, alt text, or // link options. $element = $base_element; $element['#item']->alt = ''; $this->setRawContent($renderer->renderRoot($element)); $elements = $this->xpath('//a[@href=:path]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(':path' => base_path() . $path, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight())); $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders without title, alt, or path options.'); // Link the image to a fragment on the page, and not a full URL. $fragment = $this->randomMachineName(); $element = $base_element; $element['#url'] = Url::fromRoute('<none>', [], ['fragment' => $fragment]); $this->setRawContent($renderer->renderRoot($element)); $elements = $this->xpath('//a[@href=:fragment]/img[@class="image-style-test" and @src=:url and @width=:width and @height=:height and @alt=""]', array(':fragment' => '#' . $fragment, ':url' => $url, ':width' => $image->getWidth(), ':height' => $image->getHeight())); $this->assertEqual(count($elements), 1, 'theme_image_formatter() correctly renders a link fragment.'); }
/** * {@inheritdoc} */ public function applyEffect(ImageInterface $image) { $watermark_image = $this->imageFactory->get($this->configuration['watermark_image']); if (!$watermark_image->isValid()) { return FALSE; } list($x, $y) = explode('-', $this->configuration['placement']); $x_pos = image_filter_keyword($x, $image->getWidth(), $watermark_image->getWidth()); $y_pos = image_filter_keyword($y, $image->getHeight(), $watermark_image->getHeight()); return $image->apply('watermark', ['x_offset' => $x_pos + $this->configuration['x_offset'], 'y_offset' => $y_pos + $this->configuration['y_offset'], 'opacity' => $this->configuration['opacity'], 'watermark_image' => $watermark_image]); }
/** * Tests calling a missing image operation plugin. */ function testMissingOperation() { // Test that the image factory is set to use the GD toolkit. $this->assertEqual($this->imageFactory->getToolkitId(), 'gd', 'The image factory is set to use the \'gd\' image toolkit.'); // An image file that will be tested. $file = 'image-test.png'; // Load up a fresh image. $image = $this->imageFactory->get(drupal_get_path('module', 'simpletest') . '/files/' . $file); if (!$image->isValid()) { $this->fail(String::format('Could not load image %file.', array('%file' => $file))); } // Try perform a missing toolkit operation. $this->assertFalse($image->apply('missing_op', array()), 'Calling a missing image toolkit operation plugin fails.'); }
/** * Locate all images in a piece of text that need replacing. * * An array of settings that will be used to identify which images need * updating. Includes the following: * * - image_locations: An array of acceptable image locations. * of the following values: "remote". Remote image will be downloaded and * saved locally. This procedure is intensive as the images need to * be retrieved to have their dimensions checked. * * @param string $text * The text to be updated with the new img src tags. * * @return array $images * An list of images. */ private function getImages($text) { $dom = Html::load($text); $xpath = new \DOMXPath($dom); /** @var \DOMNode $node */ foreach ($xpath->query('//img') as $node) { $file = $this->entityRepository->loadEntityByUuid('file', $node->getAttribute('data-entity-uuid')); // If the image hasn't an uuid then don't try to resize it. if (is_null($file)) { continue; } $image = $this->imageFactory->get($node->getAttribute('src')); // Checking if the image needs to be resized. if ($image->getWidth() == $node->getAttribute('width') && $image->getHeight() == $node->getAttribute('height')) { continue; } $target = file_uri_target($file->getFileUri()); $dirname = dirname($target) != '.' ? dirname($target) . '/' : ''; $info = pathinfo($file->getFileUri()); $resize_file_path = 'public://resize/' . $dirname . $info['filename'] . '-' . $node->getAttribute('width') . 'x' . $node->getAttribute('height') . '.' . $info['extension']; // Checking if the image was already resized: if (file_exists($resize_file_path)) { $node->setAttribute('src', file_url_transform_relative(file_create_url($resize_file_path))); continue; } // Delete this when https://www.drupal.org/node/2211657#comment-11510213 // be fixed. $dirname = $this->fileSystem->dirname($resize_file_path); if (!file_exists($dirname)) { file_prepare_directory($dirname, FILE_CREATE_DIRECTORY); } // Checks if the resize filter exists if is not then create it. $copy = file_unmanaged_copy($file->getFileUri(), $resize_file_path, FILE_EXISTS_REPLACE); $copy_image = $this->imageFactory->get($copy); $copy_image->resize($node->getAttribute('width'), $node->getAttribute('height')); $copy_image->save(); $node->setAttribute('src', file_url_transform_relative(file_create_url($copy))); } return Html::serialize($dom); }
/** * Sets up an image with the custom toolkit. * * @return \Drupal\Core\Image\ImageInterface * The image object. */ protected function getImage() { $image = $this->imageFactory->get($this->file, 'test'); $this->assertTrue($image->isValid(), 'Image file was parsed.'); return $image; }
/** * Generates a derivative, given a style and image path. * * After generating an image, transfer it to the requesting agent. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * @param string $scheme * The file scheme, defaults to 'private'. * @param \Drupal\image\ImageStyleInterface $image_style * The image style to deliver. * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response * The transferred file as response or some error response. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Thrown when the user does not have access to the file. * @throws \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException * Thrown when the file is still being generated. */ public function deliver(Request $request, $scheme, ImageStyleInterface $image_style) { $target = $request->query->get('file'); $image_uri = $scheme . '://' . $target; // Check that the style is defined, the scheme is valid, and the image // derivative token is valid. Sites which require image derivatives to be // generated without a token can set the // 'image.settings:allow_insecure_derivatives' configuration to TRUE to // bypass the latter check, but this will increase the site's vulnerability // to denial-of-service attacks. To prevent this variable from leaving the // site vulnerable to the most serious attacks, a token is always required // when a derivative of a style is requested. // The $target variable for a derivative of a style has // styles/<style_name>/... as structure, so we check if the $target variable // starts with styles/. $valid = !empty($image_style) && file_stream_wrapper_valid_scheme($scheme); if (!$this->config('image.settings')->get('allow_insecure_derivatives') || strpos(ltrim($target, '\\/'), 'styles/') === 0) { $valid &= $request->query->get(IMAGE_DERIVATIVE_TOKEN) === $image_style->getPathToken($image_uri); } if (!$valid) { throw new AccessDeniedHttpException(); } $derivative_uri = $image_style->buildUri($image_uri); $headers = array(); // If using the private scheme, let other modules provide headers and // control access to the file. if ($scheme == 'private') { if (file_exists($derivative_uri)) { return parent::download($request, $scheme); } else { $headers = $this->moduleHandler()->invokeAll('file_download', array($image_uri)); if (in_array(-1, $headers) || empty($headers)) { throw new AccessDeniedHttpException(); } } } // Don't try to generate file if source is missing. if (!file_exists($image_uri)) { // 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($image_uri); $converted_image_uri = $path_info['dirname'] . DIRECTORY_SEPARATOR . $path_info['filename']; if (!file_exists($converted_image_uri)) { $this->logger->notice('Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%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. $lock_name = 'image_style_deliver:' . $image_style->id() . ':' . Crypt::hashBase64($image_uri); if (!file_exists($derivative_uri)) { $lock_acquired = $this->lock->acquire($lock_name); if (!$lock_acquired) { // Tell client to retry again in 3 seconds. Currently no browsers are // known to support Retry-After. throw new ServiceUnavailableHttpException(3, $this->t('Image generation in progress. Try again shortly.')); } } // Try to generate the image, unless another thread just did it while we // were acquiring the lock. $success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri); if (!empty($lock_acquired)) { $this->lock->release($lock_name); } if ($success) { $image = $this->imageFactory->get($derivative_uri); $uri = $image->getSource(); $headers += array('Content-Type' => $image->getMimeType(), 'Content-Length' => $image->getFileSize()); // \Drupal\Core\EventSubscriber\FinishResponseSubscriber::onRespond() // sets response as not cacheable if the Cache-Control header is not // already modified. We pass in FALSE for non-private schemes for the // $public parameter to make sure we don't change the headers. return new BinaryFileResponse($uri, 200, $headers, $scheme !== 'private'); } else { $this->logger->notice('Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); return new Response($this->t('Error generating image.'), 500); } }
/** * Generates a derivative, given a style and image path. * * After generating an image, transfer it to the requesting agent. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. * @param string $scheme * The file scheme, defaults to 'private'. * @param \Drupal\image\ImageStyleInterface $image_style * The image style to deliver. * * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException * Thrown when the user does not have access to the file. * @throws \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException * Thrown when the file is still being generated. * * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response * The transferred file as response or some error response. */ public function deliver(Request $request, $scheme, ImageStyleInterface $image_style) { $target = $request->query->get('file'); $image_uri = $scheme . '://' . $target; // Check that the style is defined, the scheme is valid, and the image // derivative token is valid. Sites which require image derivatives to be // generated without a token can set the // 'image.settings:allow_insecure_derivatives' configuration to TRUE to // bypass the latter check, but this will increase the site's vulnerability // to denial-of-service attacks. $valid = !empty($image_style) && file_stream_wrapper_valid_scheme($scheme); if (!$this->config('image.settings')->get('allow_insecure_derivatives')) { $valid &= $request->query->get(IMAGE_DERIVATIVE_TOKEN) === $image_style->getPathToken($image_uri); } if (!$valid) { throw new AccessDeniedHttpException(); } $derivative_uri = $image_style->buildUri($image_uri); $headers = array(); // If using the private scheme, let other modules provide headers and // control access to the file. if ($scheme == 'private') { if (file_exists($derivative_uri)) { return parent::download($request, $scheme); } else { $headers = $this->moduleHandler()->invokeAll('file_download', array($image_uri)); if (in_array(-1, $headers) || empty($headers)) { throw new AccessDeniedHttpException(); } } } // Don't try to generate file if source is missing. if (!file_exists($image_uri)) { watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $image_uri, '%derivative_path' => $derivative_uri)); return new Response($this->t('Error generating image, missing source file.'), 404); } // Don't start generating the image if the derivative already exists or if // generation is in progress in another thread. $lock_name = 'image_style_deliver:' . $image_style->id() . ':' . Crypt::hashBase64($image_uri); if (!file_exists($derivative_uri)) { $lock_acquired = $this->lock->acquire($lock_name); if (!$lock_acquired) { // Tell client to retry again in 3 seconds. Currently no browsers are // known to support Retry-After. throw new ServiceUnavailableHttpException(3, $this->t('Image generation in progress. Try again shortly.')); } } // Try to generate the image, unless another thread just did it while we // were acquiring the lock. $success = file_exists($derivative_uri) || $image_style->createDerivative($image_uri, $derivative_uri); if (!empty($lock_acquired)) { $this->lock->release($lock_name); } if ($success) { drupal_page_is_cacheable(FALSE); $image = $this->imageFactory->get($derivative_uri); $uri = $image->getSource(); $headers += array('Content-Type' => $image->getMimeType(), 'Content-Length' => $image->getFileSize()); return new BinaryFileResponse($uri, 200, $headers); } else { watchdog('image', 'Unable to generate the derived image located at %path.', array('%path' => $derivative_uri)); return new Response($this->t('Error generating image.'), 500); } }