Issue #2027423 by claudiu.cristea, tim.plunkett, andypost: Make image style system flexible.
parent
176fbe7c71
commit
27f8cd4cd6
|
@ -608,7 +608,7 @@ function theme_image_style_effects($variables) {
|
|||
*
|
||||
* @param $variables
|
||||
* An associative array containing:
|
||||
* - style: The image style array being previewed.
|
||||
* - style: \Drupal\image\ImageStyleInterface image style being previewed.
|
||||
*
|
||||
* @ingroup themeable
|
||||
*/
|
||||
|
@ -634,9 +634,9 @@ function theme_image_style_preview($variables) {
|
|||
$original_attributes['style'] = 'width: ' . $original_width . 'px; height: ' . $original_height . 'px;';
|
||||
|
||||
// Set up preview file information.
|
||||
$preview_file = image_style_path($style->id(), $original_path);
|
||||
$preview_file = $style->buildUri($original_path);
|
||||
if (!file_exists($preview_file)) {
|
||||
image_style_create_derivative($style, $original_path, $preview_file);
|
||||
$style->createDerivative($original_path, $preview_file);
|
||||
}
|
||||
$preview_image = image_get_info($preview_file);
|
||||
if ($preview_image['width'] > $preview_image['height']) {
|
||||
|
|
|
@ -74,8 +74,8 @@ function hook_image_effect_info_alter(&$effects) {
|
|||
* be cleared using this hook. This hook is called whenever a style is updated,
|
||||
* deleted, or any effect associated with the style is update or deleted.
|
||||
*
|
||||
* @param Drupal\image\Plugin\Core\Entity\ImageStyle $style
|
||||
* The image style array that is being flushed.
|
||||
* @param \Drupal\image\ImageStyleInterface $style
|
||||
* The image style object that is being flushed.
|
||||
*/
|
||||
function hook_image_style_flush($style) {
|
||||
// Empty cached data that contains information about the style.
|
||||
|
|
|
@ -9,13 +9,9 @@ use Drupal\Core\Entity\EntityInterface;
|
|||
use Drupal\Core\Language\Language;
|
||||
use Drupal\field\Plugin\Core\Entity\Field;
|
||||
use Drupal\field\Plugin\Core\Entity\FieldInstance;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Component\Uuid\Uuid;
|
||||
use Drupal\file\Plugin\Core\Entity\File;
|
||||
use Drupal\image\ImageStyleInterface;
|
||||
use Drupal\image\Plugin\Core\Entity\ImageStyle;
|
||||
use Drupal\field\FieldInterface;
|
||||
use Drupal\field\FieldInstanceInterface;
|
||||
|
@ -357,10 +353,7 @@ function image_file_predelete(File $file) {
|
|||
function image_path_flush($path) {
|
||||
$styles = entity_load_multiple('image_style');
|
||||
foreach ($styles as $style) {
|
||||
$image_path = image_style_path($style->id(), $path);
|
||||
if (file_exists($image_path)) {
|
||||
file_unmanaged_delete($image_path);
|
||||
}
|
||||
$style->flush($path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,304 +396,23 @@ function image_style_options($include_empty = TRUE) {
|
|||
*
|
||||
* After generating an image, transfer it to the requesting agent.
|
||||
*
|
||||
* @param $style
|
||||
* The image style
|
||||
* @param \Drupal\image\ImageStyleInterface $style
|
||||
* The image style.
|
||||
* @param string $scheme
|
||||
* The scheme name of the original image file stream wrapper ('public',
|
||||
* 'private', 'temporary', etc.).
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* The image to be delivered.
|
||||
*
|
||||
* @todo Remove this wrapper in https://drupal.org/node/1987712.
|
||||
*/
|
||||
function image_style_deliver($style, $scheme) {
|
||||
function image_style_deliver(ImageStyleInterface $style, $scheme) {
|
||||
$args = func_get_args();
|
||||
array_shift($args);
|
||||
array_shift($args);
|
||||
// Remove $style and $scheme from the arguments.
|
||||
unset($args[0], $args[1]);
|
||||
$target = implode('/', $args);
|
||||
|
||||
// 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($style) && file_stream_wrapper_valid_scheme($scheme);
|
||||
if (!config('image.settings')->get('allow_insecure_derivatives')) {
|
||||
$image_derivative_token = Drupal::request()->query->get(IMAGE_DERIVATIVE_TOKEN);
|
||||
$valid = $valid && isset($image_derivative_token) && $image_derivative_token === image_style_path_token($style->name, $scheme . '://' . $target);
|
||||
}
|
||||
if (!$valid) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
$image_uri = $scheme . '://' . $target;
|
||||
$derivative_uri = image_style_path($style->id(), $image_uri);
|
||||
|
||||
// If using the private scheme, let other modules provide headers and
|
||||
// control access to the file.
|
||||
if ($scheme == 'private') {
|
||||
if (file_exists($derivative_uri)) {
|
||||
file_download($scheme, file_uri_target($derivative_uri));
|
||||
}
|
||||
else {
|
||||
$headers = module_invoke_all('file_download', $image_uri);
|
||||
if (in_array(-1, $headers) || empty($headers)) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
if (count($headers)) {
|
||||
foreach ($headers as $name => $value) {
|
||||
drupal_add_http_header($name, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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(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:' . $style->id() . ':' . Crypt::hashBase64($image_uri);
|
||||
if (!file_exists($derivative_uri)) {
|
||||
$lock_acquired = 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, 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_create_derivative($style, $image_uri, $derivative_uri);
|
||||
|
||||
if (!empty($lock_acquired)) {
|
||||
lock()->release($lock_name);
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$image = image_load($derivative_uri);
|
||||
$uri = $image->source;
|
||||
$headers = array(
|
||||
'Content-Type' => $image->info['mime_type'],
|
||||
'Content-Length' => $image->info['file_size'],
|
||||
);
|
||||
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(t('Error generating image.'), 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new image derivative based on an image style.
|
||||
*
|
||||
* Generates an image derivative by creating the destination folder (if it does
|
||||
* not already exist), applying all image effects defined in $style->effects,
|
||||
* and saving a cached version of the resulting image.
|
||||
*
|
||||
* @param $style
|
||||
* An image style array.
|
||||
* @param $source
|
||||
* Path of the source file.
|
||||
* @param $destination
|
||||
* Path or URI of the destination file.
|
||||
*
|
||||
* @return
|
||||
* TRUE if an image derivative was generated, or FALSE if the image derivative
|
||||
* could not be generated.
|
||||
*
|
||||
* @see image_style_load()
|
||||
*/
|
||||
function image_style_create_derivative($style, $source, $destination) {
|
||||
// Get the folder for the final location of this style.
|
||||
$directory = drupal_dirname($destination);
|
||||
|
||||
// Build the destination folder tree if it doesn't already exist.
|
||||
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
watchdog('image', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!$image = image_load($source)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!empty($style->effects)) {
|
||||
foreach ($style->effects as $effect) {
|
||||
image_effect_apply($image, $effect);
|
||||
}
|
||||
}
|
||||
|
||||
if (!image_save($image, $destination)) {
|
||||
if (file_exists($destination)) {
|
||||
watchdog('image', 'Cached image file %destination already exists. There may be an issue with your rewrite configuration.', array('%destination' => $destination), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the dimensions of the styled image.
|
||||
*
|
||||
* Applies all of an image style's effects to $dimensions.
|
||||
*
|
||||
* @param $style_name
|
||||
* The name of the style to be applied.
|
||||
* @param $dimensions
|
||||
* Dimensions to be modified - an array with components width and height, in
|
||||
* pixels.
|
||||
*/
|
||||
function image_style_transform_dimensions($style_name, array &$dimensions) {
|
||||
module_load_include('inc', 'image', 'image.effects');
|
||||
$style = entity_load('image_style', $style_name);
|
||||
|
||||
if (!empty($style->effects)) {
|
||||
foreach ($style->effects as $effect) {
|
||||
if (isset($effect['dimensions passthrough'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($effect['dimensions callback'])) {
|
||||
$effect['dimensions callback']($dimensions, $effect['data']);
|
||||
}
|
||||
else {
|
||||
$dimensions['width'] = $dimensions['height'] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes cached media for a style.
|
||||
*
|
||||
* @param $style
|
||||
* An image style array.
|
||||
*/
|
||||
function image_style_flush($style) {
|
||||
// Delete the style directory in each registered wrapper.
|
||||
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
|
||||
foreach ($wrappers as $wrapper => $wrapper_data) {
|
||||
file_unmanaged_delete_recursive($wrapper . '://styles/' . $style->id());
|
||||
}
|
||||
|
||||
// Let other modules update as necessary on flush.
|
||||
module_invoke_all('image_style_flush', $style);
|
||||
|
||||
// Clear field caches so that formatters may be added for this style.
|
||||
field_info_cache_clear();
|
||||
drupal_theme_rebuild();
|
||||
|
||||
// Clear page caches when flushing.
|
||||
if (module_exists('block')) {
|
||||
cache('block')->deleteAll();
|
||||
}
|
||||
cache('page')->deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL for an image derivative given a style and image path.
|
||||
*
|
||||
* @param $style_name
|
||||
* The name of the style to be used with this image.
|
||||
* @param $path
|
||||
* The path to the image.
|
||||
* @param $clean_urls
|
||||
* (optional) Whether clean URLs are in use.
|
||||
* @return
|
||||
* The absolute URL where a style image can be downloaded, suitable for use
|
||||
* in an <img> tag. Requesting the URL will cause the image to be created.
|
||||
* @see image_style_deliver()
|
||||
*/
|
||||
function image_style_url($style_name, $path, $clean_urls = NULL) {
|
||||
$uri = image_style_path($style_name, $path);
|
||||
// The token query is added even if the
|
||||
// 'image.settings:allow_insecure_derivatives' configuration is TRUE, so that
|
||||
// the emitted links remain valid if it is changed back to the default FALSE.
|
||||
// However, sites which need to prevent the token query from being emitted at
|
||||
// all can additionally set the '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
|
||||
// image_style_deliver()).
|
||||
$token_query = array();
|
||||
if (!config('image.settings')->get('suppress_itok_output')) {
|
||||
$token_query = array(IMAGE_DERIVATIVE_TOKEN => image_style_path_token($style_name, file_stream_wrapper_uri_normalize($path)));
|
||||
}
|
||||
|
||||
if ($clean_urls === NULL) {
|
||||
// Assume clean URLs unless the request tells us otherwise.
|
||||
$clean_urls = TRUE;
|
||||
try {
|
||||
$request = Drupal::request();
|
||||
$clean_urls = $request->attributes->get('clean_urls');
|
||||
}
|
||||
catch (ServiceNotFoundException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
// If not using clean URLs, the image derivative callback is only available
|
||||
// with the script path. If the file does not exist, use url() to ensure
|
||||
// that it is included. Once the file exists it's fine to fall back to the
|
||||
// actual file path, this avoids bootstrapping PHP once the files are built.
|
||||
if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) {
|
||||
$directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath();
|
||||
return url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query));
|
||||
}
|
||||
|
||||
$file_url = file_create_url($uri);
|
||||
// Append the query string with the token, if necessary.
|
||||
if ($token_query) {
|
||||
$file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . drupal_http_build_query($token_query);
|
||||
}
|
||||
|
||||
return $file_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a token to protect an image style derivative.
|
||||
*
|
||||
* This prevents unauthorized generation of an image style derivative,
|
||||
* which can be costly both in CPU time and disk space.
|
||||
*
|
||||
* @param string $style_name
|
||||
* The name of the image style.
|
||||
* @param string $uri
|
||||
* The URI of the image for this style, for example as returned by
|
||||
* image_style_path().
|
||||
*
|
||||
* @return string
|
||||
* An eight-character token which can be used to protect image style
|
||||
* derivatives against denial-of-service attacks.
|
||||
*/
|
||||
function image_style_path_token($style_name, $uri) {
|
||||
// Return the first eight characters.
|
||||
return substr(Crypt::hmacBase64($style_name . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URI of an image when using a style.
|
||||
*
|
||||
* The path returned by this function may not exist. The default generation
|
||||
* method only creates images when they are requested by a user's browser.
|
||||
*
|
||||
* @param $style_name
|
||||
* The name of the style to be used with this image.
|
||||
* @param $uri
|
||||
* The URI or path to the image.
|
||||
* @return
|
||||
* The URI to an image style image.
|
||||
* @see image_style_url()
|
||||
*/
|
||||
function image_style_path($style_name, $uri) {
|
||||
$scheme = file_uri_scheme($uri);
|
||||
if ($scheme) {
|
||||
$path = file_uri_target($uri);
|
||||
}
|
||||
else {
|
||||
$path = $uri;
|
||||
$scheme = file_default_scheme();
|
||||
}
|
||||
return $scheme . '://styles/' . $style_name . '/' . $scheme . '/' . $path;
|
||||
return $style->deliver($scheme, $target);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -835,10 +547,6 @@ function image_effect_save($style, &$effect) {
|
|||
}
|
||||
$style->effects[$effect['ieid']] = $effect;
|
||||
$style->save();
|
||||
|
||||
// Flush all derivatives that exist for this style, so they are regenerated
|
||||
// with the new or updated effect.
|
||||
image_style_flush($style);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -852,7 +560,6 @@ function image_effect_save($style, &$effect) {
|
|||
function image_effect_delete($style, $effect) {
|
||||
unset($style->effects[$effect['ieid']]);
|
||||
$style->save();
|
||||
image_style_flush($style);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -892,13 +599,17 @@ function image_effect_apply($image, $effect) {
|
|||
* @ingroup themeable
|
||||
*/
|
||||
function theme_image_style($variables) {
|
||||
// @todo Image style loading will be moved outside theme in
|
||||
// https://drupal.org/node/2029649
|
||||
$style = entity_load('image_style', $variables['style_name']);
|
||||
|
||||
// Determine the dimensions of the styled image.
|
||||
$dimensions = array(
|
||||
'width' => $variables['width'],
|
||||
'height' => $variables['height'],
|
||||
);
|
||||
|
||||
image_style_transform_dimensions($variables['style_name'], $dimensions);
|
||||
$style->transformDimensions($dimensions);
|
||||
|
||||
// Add in the image style name as an HTML class.
|
||||
$variables['attributes']['class'][] = 'image-style-' . drupal_html_class($variables['style_name']);
|
||||
|
@ -908,7 +619,7 @@ function theme_image_style($variables) {
|
|||
'#width' => $dimensions['width'],
|
||||
'#height' => $dimensions['height'],
|
||||
'#attributes' => $variables['attributes'],
|
||||
'#uri' => image_style_url($variables['style_name'], $variables['uri']),
|
||||
'#uri' => $style->buildUrl($variables['uri']),
|
||||
);
|
||||
|
||||
if (isset($variables['alt'])) {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\image\Plugin\Core\Entity\ImageStyleInterface.
|
||||
* Contains \Drupal\image\ImageStyleInterface.
|
||||
*/
|
||||
|
||||
namespace Drupal\image;
|
||||
|
@ -14,4 +14,99 @@ use Drupal\Core\Config\Entity\ConfigEntityInterface;
|
|||
*/
|
||||
interface ImageStyleInterface extends ConfigEntityInterface {
|
||||
|
||||
/**
|
||||
* Delivers an image derivative.
|
||||
*
|
||||
* Transfers a generated image derivative to the requesting agent. Modules may
|
||||
* implement this method to set different serve different image derivatives
|
||||
* from different stream wrappers or to customize different permissions on
|
||||
* each image style.
|
||||
*
|
||||
* @param string $scheme
|
||||
* The scheme name of the original image file stream wrapper ('public',
|
||||
* 'private', 'temporary', etc.).
|
||||
* @param string $target
|
||||
* The target part of the uri.
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response
|
||||
* The image to be delivered.
|
||||
*
|
||||
* @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
|
||||
* \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException
|
||||
*
|
||||
* @todo Move to controller after https://drupal.org/node/1987712.
|
||||
*/
|
||||
public function deliver($scheme, $target);
|
||||
|
||||
/**
|
||||
* Returns the URI of this image when using this style.
|
||||
*
|
||||
* The path returned by this function may not exist. The default generation
|
||||
* method only creates images when they are requested by a user's browser.
|
||||
* Modules may implement this method to decide where to place derivatives.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI or path to the original image.
|
||||
*
|
||||
* @return string
|
||||
* The URI to the image derivative for this style.
|
||||
*/
|
||||
public function buildUri($uri);
|
||||
|
||||
/**
|
||||
* Returns the URL of this image derivative for an original image path or URI.
|
||||
*
|
||||
* @param string $path
|
||||
* The path or URI to the original image.
|
||||
* @param mixed $clean_urls
|
||||
* (optional) Whether clean URLs are in use.
|
||||
*
|
||||
* @return string
|
||||
* The absolute URL where a style image can be downloaded, suitable for use
|
||||
* in an <img> tag. Requesting the URL will cause the image to be created.
|
||||
*
|
||||
* @see \Drupal\image\ImageStyleInterface::deliver()
|
||||
*/
|
||||
public function buildUrl($path, $clean_urls = NULL);
|
||||
|
||||
/**
|
||||
* Flushes cached media for this style.
|
||||
*
|
||||
* @param string $path
|
||||
* (optional) The original image path or URI. If it's supplied, only this
|
||||
* image derivative will be flushed.
|
||||
*/
|
||||
public function flush($path = NULL);
|
||||
|
||||
/**
|
||||
* Creates a new image derivative based on this image style.
|
||||
*
|
||||
* Generates an image derivative applying all image effects and saving the
|
||||
* resulting image.
|
||||
*
|
||||
* @param string $original_uri
|
||||
* Original image file URI.
|
||||
* @param string $derivative_uri
|
||||
* Derivative image file URI.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if an image derivative was generated, or FALSE if the image
|
||||
* derivative could not be generated.
|
||||
*/
|
||||
public function createDerivative($original_uri, $derivative_uri);
|
||||
|
||||
/**
|
||||
* Determines the dimensions of this image style.
|
||||
*
|
||||
* Stores the dimensions of this image style into $dimensions associative
|
||||
* array. Implementations have to provide at least values to next keys:
|
||||
* - width: Integer with the derivative image width.
|
||||
* - height: Integer with the derivative image height.
|
||||
*
|
||||
* @param array $dimensions
|
||||
* Associative array passed by reference. Implementations have to store the
|
||||
* resulting width and height, in pixels.
|
||||
*/
|
||||
public function transformDimensions(array &$dimensions);
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,13 @@ use Drupal\Core\Entity\Annotation\EntityType;
|
|||
use Drupal\Core\Annotation\Translation;
|
||||
use Drupal\Core\Entity\EntityStorageControllerInterface;
|
||||
use Drupal\image\ImageStyleInterface;
|
||||
use Drupal\Component\Utility\Crypt;
|
||||
use Drupal\Component\Utility\Url;
|
||||
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpFoundation\BinaryFileResponse;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
|
||||
|
||||
/**
|
||||
* Defines an image style configuration entity.
|
||||
|
@ -68,7 +75,7 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
|
|||
/**
|
||||
* The array of image effects for this image style.
|
||||
*
|
||||
* @var string
|
||||
* @var array
|
||||
*/
|
||||
public $effects;
|
||||
|
||||
|
@ -83,11 +90,17 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
|
|||
* {@inheritdoc}
|
||||
*/
|
||||
public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
|
||||
if ($update && !empty($this->original) && $this->id() !== $this->original->id()) {
|
||||
// The old image style name needs flushing after a rename.
|
||||
image_style_flush($this->original);
|
||||
// Update field instance settings if necessary.
|
||||
static::replaceImageStyle($this);
|
||||
if ($update) {
|
||||
if (!empty($this->original) && $this->id() !== $this->original->id()) {
|
||||
// The old image style name needs flushing after a rename.
|
||||
$this->original->flush();
|
||||
// Update field instance settings if necessary.
|
||||
static::replaceImageStyle($this);
|
||||
}
|
||||
else {
|
||||
// Flush image style when updating without changing the name.
|
||||
$this->flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,7 +110,7 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
|
|||
public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
|
||||
foreach ($entities as $style) {
|
||||
// Flush cached media for the deleted style.
|
||||
image_style_flush($style);
|
||||
$style->flush();
|
||||
// Check whether field instance settings need to be updated.
|
||||
// In case no replacement style was specified, all image fields that are
|
||||
// using the deleted style are left in a broken state.
|
||||
|
@ -112,10 +125,10 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
|
|||
/**
|
||||
* Update field instance settings if the image style name is changed.
|
||||
*
|
||||
* @param \Drupal\image\Plugin\Core\Entity\ImageStyle $style
|
||||
* @param \Drupal\image\ImageStyleInterface $style
|
||||
* The image style.
|
||||
*/
|
||||
protected static function replaceImageStyle(ImageStyle $style) {
|
||||
protected static function replaceImageStyle(ImageStyleInterface $style) {
|
||||
if ($style->id() != $style->getOriginalID()) {
|
||||
$instances = field_read_instances();
|
||||
// Loop through all fields searching for image fields.
|
||||
|
@ -148,4 +161,252 @@ class ImageStyle extends ConfigEntityBase implements ImageStyleInterface {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deliver($scheme, $target) {
|
||||
$original_uri = $scheme . '://' . $target;
|
||||
|
||||
// Check that 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 = file_stream_wrapper_valid_scheme($scheme);
|
||||
if (!\Drupal::config('image.settings')->get('allow_insecure_derivatives')) {
|
||||
$image_derivative_token = \Drupal::request()->query->get(IMAGE_DERIVATIVE_TOKEN);
|
||||
$valid &= isset($image_derivative_token) && $image_derivative_token === $this->getPathToken($original_uri);
|
||||
}
|
||||
if (!$valid) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
$derivative_uri = $this->buildUri($original_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)) {
|
||||
file_download($scheme, file_uri_target($derivative_uri));
|
||||
}
|
||||
else {
|
||||
$headers = \Drupal::moduleHandler()->invokeAll('file_download', array($original_uri));
|
||||
if (in_array(-1, $headers) || empty($headers)) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't try to generate file if source is missing.
|
||||
if (!file_exists($original_uri)) {
|
||||
watchdog('image', 'Source image at %source_image_path not found while trying to generate derivative image at %derivative_path.', array('%source_image_path' => $original_uri, '%derivative_path' => $derivative_uri));
|
||||
return new Response(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:' . $this->id() . ':' . Crypt::hashBase64($original_uri);
|
||||
if (!file_exists($derivative_uri)) {
|
||||
$lock_acquired = \Drupal::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, 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) || $this->createDerivative($original_uri, $derivative_uri);
|
||||
|
||||
if (!empty($lock_acquired)) {
|
||||
\Drupal::lock()->release($lock_name);
|
||||
}
|
||||
|
||||
if ($success) {
|
||||
$image = image_load($derivative_uri);
|
||||
$uri = $image->source;
|
||||
$headers += array(
|
||||
'Content-Type' => $image->info['mime_type'],
|
||||
'Content-Length' => $image->info['file_size'],
|
||||
);
|
||||
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(t('Error generating image.'), 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildUri($uri) {
|
||||
$scheme = file_uri_scheme($uri);
|
||||
if ($scheme) {
|
||||
$path = file_uri_target($uri);
|
||||
}
|
||||
else {
|
||||
$path = $uri;
|
||||
$scheme = file_default_scheme();
|
||||
}
|
||||
return $scheme . '://styles/' . $this->id() . '/' . $scheme . '/' . $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildUrl($path, $clean_urls = NULL) {
|
||||
$uri = $this->buildUri($path);
|
||||
// The token query is added even if the
|
||||
// 'image.settings:allow_insecure_derivatives' configuration is TRUE, so
|
||||
// that the emitted links remain valid if it is changed back to the default
|
||||
// FALSE. However, sites which need to prevent the token query from being
|
||||
// emitted at all can additionally set the
|
||||
// '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()).
|
||||
$token_query = array();
|
||||
if (!\Drupal::config('image.settings')->get('suppress_itok_output')) {
|
||||
$token_query = array(IMAGE_DERIVATIVE_TOKEN => $this->getPathToken(file_stream_wrapper_uri_normalize($path)));
|
||||
}
|
||||
|
||||
if ($clean_urls === NULL) {
|
||||
// Assume clean URLs unless the request tells us otherwise.
|
||||
$clean_urls = TRUE;
|
||||
try {
|
||||
$request = \Drupal::request();
|
||||
$clean_urls = $request->attributes->get('clean_urls');
|
||||
}
|
||||
catch (ServiceNotFoundException $e) {
|
||||
}
|
||||
}
|
||||
|
||||
// If not using clean URLs, the image derivative callback is only available
|
||||
// with the script path. If the file does not exist, use url() to ensure
|
||||
// that it is included. Once the file exists it's fine to fall back to the
|
||||
// actual file path, this avoids bootstrapping PHP once the files are built.
|
||||
if ($clean_urls === FALSE && file_uri_scheme($uri) == 'public' && !file_exists($uri)) {
|
||||
$directory_path = file_stream_wrapper_get_instance_by_uri($uri)->getDirectoryPath();
|
||||
return url($directory_path . '/' . file_uri_target($uri), array('absolute' => TRUE, 'query' => $token_query));
|
||||
}
|
||||
|
||||
$file_url = file_create_url($uri);
|
||||
// Append the query string with the token, if necessary.
|
||||
if ($token_query) {
|
||||
$file_url .= (strpos($file_url, '?') !== FALSE ? '&' : '?') . Url::buildQuery($token_query);
|
||||
}
|
||||
|
||||
return $file_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function flush($path = NULL) {
|
||||
// A specific image path has been provided. Flush only that derivative.
|
||||
if (isset($path)) {
|
||||
$derivative_uri = $this->buildUri($path);
|
||||
if (file_exists($derivative_uri)) {
|
||||
file_unmanaged_delete($derivative_uri);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the style directory in each registered wrapper.
|
||||
$wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_WRITE_VISIBLE);
|
||||
foreach ($wrappers as $wrapper => $wrapper_data) {
|
||||
file_unmanaged_delete_recursive($wrapper . '://styles/' . $this->id());
|
||||
}
|
||||
|
||||
// Let other modules update as necessary on flush.
|
||||
\Drupal::moduleHandler()->invokeAll('image_style_flush', array($this));
|
||||
|
||||
// Clear field caches so that formatters may be added for this style.
|
||||
field_info_cache_clear();
|
||||
drupal_theme_rebuild();
|
||||
|
||||
// Clear page caches when flushing.
|
||||
if (\Drupal::moduleHandler()->moduleExists('block')) {
|
||||
cache('block')->deleteAll();
|
||||
}
|
||||
cache('page')->deleteAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function createDerivative($original_uri, $derivative_uri) {
|
||||
// Get the folder for the final location of this style.
|
||||
$directory = drupal_dirname($derivative_uri);
|
||||
|
||||
// Build the destination folder tree if it doesn't already exist.
|
||||
if (!file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS)) {
|
||||
watchdog('image', 'Failed to create style directory: %directory', array('%directory' => $directory), WATCHDOG_ERROR);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!$image = image_load($original_uri)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!empty($this->effects)) {
|
||||
foreach ($this->effects as $effect) {
|
||||
image_effect_apply($image, $effect);
|
||||
}
|
||||
}
|
||||
|
||||
if (!image_save($image, $derivative_uri)) {
|
||||
if (file_exists($derivative_uri)) {
|
||||
watchdog('image', 'Cached image file %destination already exists. There may be an issue with your rewrite configuration.', array('%destination' => $derivative_uri), WATCHDOG_ERROR);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function transformDimensions(array &$dimensions) {
|
||||
module_load_include('inc', 'image', 'image.effects');
|
||||
|
||||
if (!empty($this->effects)) {
|
||||
foreach ($this->effects as $effect) {
|
||||
if (isset($effect['dimensions passthrough'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($effect['dimensions callback'])) {
|
||||
$effect['dimensions callback']($dimensions, $effect['data']);
|
||||
}
|
||||
else {
|
||||
$dimensions['width'] = $dimensions['height'] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a token to protect an image style derivative.
|
||||
*
|
||||
* This prevents unauthorized generation of an image style derivative,
|
||||
* which can be costly both in CPU time and disk space.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI of the image for this style, for example as returned by
|
||||
* \Drupal\image\ImageStyleInterface::buildUri().
|
||||
*
|
||||
* @return string
|
||||
* An eight-character token which can be used to protect image style
|
||||
* derivatives against denial-of-service attacks.
|
||||
*/
|
||||
protected function getPathToken($uri) {
|
||||
// Return the first eight characters.
|
||||
return substr(Crypt::hmacBase64($this->id() . ':' . $uri, drupal_get_private_key() . drupal_get_hash_salt()), 0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,8 +39,9 @@ class FileMoveTest extends ToolkitTestBase {
|
|||
// Create derivative image.
|
||||
$styles = entity_load_multiple('image_style');
|
||||
$style = image_style_load(key($styles));
|
||||
$derivative_uri = image_style_path($style->id(), $file->getFileUri());
|
||||
image_style_create_derivative($style, $file->getFileUri(), $derivative_uri);
|
||||
$original_uri = $file->getFileUri();
|
||||
$derivative_uri = $style->buildUri($original_uri);
|
||||
$style->createDerivative($original_uri, $derivative_uri);
|
||||
|
||||
// Check if derivative image exists.
|
||||
$this->assertTrue(file_exists($derivative_uri), 'Make sure derivative image is generated successfully.');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\image\Tests;
|
||||
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\image\ImageStyleInterface;
|
||||
|
||||
/**
|
||||
* Tests creation, deletion, and editing of image styles and effects.
|
||||
|
@ -25,7 +25,7 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
/**
|
||||
* Given an image style, generate an image.
|
||||
*/
|
||||
function createSampleImage($style) {
|
||||
function createSampleImage(ImageStyleInterface $style) {
|
||||
static $file_path;
|
||||
|
||||
// First, we need to make sure we have an image in our testing
|
||||
|
@ -36,13 +36,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$file_path = file_unmanaged_copy($file->uri);
|
||||
}
|
||||
|
||||
return image_style_url($style->id(), $file_path) ? $file_path : FALSE;
|
||||
return $style->buildUrl($file_path) ? $file_path : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count the number of images currently create for a style.
|
||||
*/
|
||||
function getImageCount($style) {
|
||||
function getImageCount(ImageStyleInterface $style) {
|
||||
return count(file_scan_directory('public://styles/' . $style->id(), '/.*/'));
|
||||
}
|
||||
|
||||
|
@ -271,9 +271,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
|
||||
$node = node_load($nid);
|
||||
|
||||
// Get node field original image URI.
|
||||
$fid = $node->get($field_name)->target_id;
|
||||
$original_uri = file_load($fid)->getFileUri();
|
||||
|
||||
// Test that image is displayed using newly created style.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
|
||||
$this->assertRaw($style->buildUrl($original_uri), format_string('Image displayed using style @style.', array('@style' => $style_name)));
|
||||
|
||||
// Rename the style and make sure the image field is updated.
|
||||
$new_style_name = strtolower($this->randomName(10));
|
||||
|
@ -285,7 +289,10 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$this->drupalPost($style_path . $style_name, $edit, t('Update style'));
|
||||
$this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(image_style_url($new_style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.');
|
||||
|
||||
// Reload the image style using the new name.
|
||||
$style = entity_load('image_style', $new_style_name);
|
||||
$this->assertRaw($style->buildUrl($original_uri), 'Image displayed using style replacement style.');
|
||||
|
||||
// Delete the style and choose a replacement style.
|
||||
$edit = array(
|
||||
|
@ -295,8 +302,9 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$message = t('Style %name was deleted.', array('%name' => $new_style_label));
|
||||
$this->assertRaw($message);
|
||||
|
||||
$replacement_style = entity_load('image_style', 'thumbnail');
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(image_style_url('thumbnail', file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.');
|
||||
$this->assertRaw($replacement_style->buildUrl($original_uri), 'Image displayed using style replacement style.');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -360,9 +368,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$nid = $this->uploadNodeImage($test_image, $field_name, 'article');
|
||||
$node = node_load($nid);
|
||||
|
||||
// Get node field original image URI.
|
||||
$fid = $node->get($field_name)->target_id;
|
||||
$original_uri = file_load($fid)->getFileUri();
|
||||
|
||||
// Test that image is displayed using newly created style.
|
||||
$this->drupalGet('node/' . $nid);
|
||||
$this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
|
||||
$this->assertRaw($style->buildUrl($original_uri), format_string('Image displayed using style @style.', array('@style' => $style_name)));
|
||||
|
||||
// Copy config to staging, and delete the image style.
|
||||
$staging = $this->container->get('config.storage.staging');
|
||||
|
@ -374,4 +386,5 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
|
|||
$this->assertFalse(entity_load('image_style', $style_name), 'Style deleted after config import.');
|
||||
$this->assertEqual($this->getImageCount($style), 0, 'Image style was flushed after being deleted by config import.');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ class ImageDimensionsTest extends WebTestBase {
|
|||
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
|
||||
$style->save();
|
||||
$generated_uri = 'public://styles/test/public/'. drupal_basename($original_uri);
|
||||
$url = image_style_url('test', $original_uri);
|
||||
$url = $style->buildUrl($original_uri);
|
||||
|
||||
$variables = array(
|
||||
'style_name' => 'test',
|
||||
|
|
|
@ -112,7 +112,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase {
|
|||
|
||||
// Ensure the derivative image is generated so we do not have to deal with
|
||||
// image style callback paths.
|
||||
$this->drupalGet(image_style_url('thumbnail', $image_uri));
|
||||
$this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri));
|
||||
$image_info['uri'] = $image_uri;
|
||||
$image_info['width'] = 100;
|
||||
$image_info['height'] = 50;
|
||||
|
@ -124,7 +124,7 @@ class ImageFieldDisplayTest extends ImageFieldTestBase {
|
|||
if ($scheme == 'private') {
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet(image_style_url('thumbnail', $image_uri));
|
||||
$this->drupalGet(entity_load('image_style', 'thumbnail')->buildUrl($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ use Drupal\simpletest\WebTestBase;
|
|||
*
|
||||
* image.effects.inc:
|
||||
* image_style_generate()
|
||||
* image_style_create_derivative()
|
||||
* \Drupal\image\ImageStyleInterface::createDerivative()
|
||||
*
|
||||
* image.module:
|
||||
* image_style_options()
|
||||
* image_style_flush()
|
||||
* \Drupal\image\ImageStyleInterface::flush()
|
||||
* image_effect_definition_load()
|
||||
* image_effect_load()
|
||||
* image_effect_save()
|
||||
|
|
|
@ -34,8 +34,8 @@ class ImageStyleFlushTest extends ImageFieldTestBase {
|
|||
// Make sure we have an image in our wrapper testing file directory.
|
||||
$source_uri = file_unmanaged_copy($file->uri, $wrapper . '://');
|
||||
// Build the derivative image.
|
||||
$derivative_uri = image_style_path($style->id(), $source_uri);
|
||||
$derivative = image_style_create_derivative($style, $source_uri, $derivative_uri);
|
||||
$derivative_uri = $style->buildUri($source_uri);
|
||||
$derivative = $style->createDerivative($source_uri, $derivative_uri);
|
||||
|
||||
return $derivative ? $derivative_uri : FALSE;
|
||||
}
|
||||
|
|
|
@ -22,9 +22,10 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
*/
|
||||
public static $modules = array('image', 'image_module_test');
|
||||
|
||||
protected $style_name;
|
||||
protected $image_info;
|
||||
protected $image_filepath;
|
||||
/**
|
||||
* @var \Drupal\image\ImageStyleInterface
|
||||
*/
|
||||
protected $style;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
|
@ -37,58 +38,57 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->style_name = 'style_foo';
|
||||
$style = entity_create('image_style', array('name' => $this->style_name, 'label' => $this->randomString()));
|
||||
$style->save();
|
||||
$this->style = entity_create('image_style', array('name' => 'style_foo', 'label' => $this->randomString()));
|
||||
$this->style->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image_style_path().
|
||||
* Tests \Drupal\image\ImageStyleInterface::buildUri().
|
||||
*/
|
||||
function testImageStylePath() {
|
||||
$scheme = 'public';
|
||||
$actual = image_style_path($this->style_name, "$scheme://foo/bar.gif");
|
||||
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
|
||||
$actual = $this->style->buildUri("$scheme://foo/bar.gif");
|
||||
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
|
||||
$this->assertEqual($actual, $expected, 'Got the path for a file URI.');
|
||||
|
||||
$actual = image_style_path($this->style_name, 'foo/bar.gif');
|
||||
$expected = "$scheme://styles/" . $this->style_name . "/$scheme/foo/bar.gif";
|
||||
$actual = $this->style->buildUri('foo/bar.gif');
|
||||
$expected = "$scheme://styles/" . $this->style->id() . "/$scheme/foo/bar.gif";
|
||||
$this->assertEqual($actual, $expected, 'Got the path for a relative file path.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image_style_url() with a file using the "public://" scheme.
|
||||
* Tests an image style URL using the "public://" scheme.
|
||||
*/
|
||||
function testImageStyleUrlAndPathPublic() {
|
||||
$this->_testImageStyleUrlAndPath('public');
|
||||
$this->doImageStyleUrlAndPathTests('public');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image_style_url() with a file using the "private://" scheme.
|
||||
* Tests an image style URL using the "private://" scheme.
|
||||
*/
|
||||
function testImageStyleUrlAndPathPrivate() {
|
||||
$this->_testImageStyleUrlAndPath('private');
|
||||
$this->doImageStyleUrlAndPathTests('private');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image_style_url() with the "public://" scheme and unclean URLs.
|
||||
* Tests an image style URL with the "public://" scheme and unclean URLs.
|
||||
*/
|
||||
function testImageStylUrlAndPathPublicUnclean() {
|
||||
$this->_testImageStyleUrlAndPath('public', FALSE);
|
||||
function testImageStyleUrlAndPathPublicUnclean() {
|
||||
$this->doImageStyleUrlAndPathTests('public', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test image_style_url() with the "private://" schema and unclean URLs.
|
||||
* Tests an image style URL with the "private://" schema and unclean URLs.
|
||||
*/
|
||||
function testImageStyleUrlAndPathPrivateUnclean() {
|
||||
$this->_testImageStyleUrlAndPath('private', FALSE);
|
||||
$this->doImageStyleUrlAndPathTests('private', FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image_style_url() with a file URL that has an extra slash in it.
|
||||
* Tests an image style URL with a file URL that has an extra slash in it.
|
||||
*/
|
||||
function testImageStyleUrlExtraSlash() {
|
||||
$this->_testImageStyleUrlAndPath('public', TRUE, TRUE);
|
||||
$this->doImageStyleUrlAndPathTests('public', TRUE, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,30 +96,29 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
*/
|
||||
function testImageStyleUrlForMissingSourceImage() {
|
||||
$non_existent_uri = 'public://foo.png';
|
||||
$generated_url = image_style_url($this->style_name, $non_existent_uri);
|
||||
$generated_url = $this->style->buildUrl($non_existent_uri);
|
||||
$this->drupalGet($generated_url);
|
||||
$this->assertResponse(404, 'Accessing an image style URL with a source image that does not exist provides a 404 error response.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests image_style_url().
|
||||
* Tests building an image style URL.
|
||||
*/
|
||||
function _testImageStyleUrlAndPath($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
|
||||
$request = $this->prepareRequestForGenerator($clean_url);
|
||||
function doImageStyleUrlAndPathTests($scheme, $clean_url = TRUE, $extra_slash = FALSE) {
|
||||
$this->prepareRequestForGenerator($clean_url);
|
||||
|
||||
// Make the default scheme neither "public" nor "private" to verify the
|
||||
// functions work for other than the default scheme.
|
||||
config('system.file')->set('default_scheme', 'temporary')->save();
|
||||
|
||||
// Create the directories for the styles.
|
||||
$directory = $scheme . '://styles/' . $this->style_name;
|
||||
$directory = $scheme . '://styles/' . $this->style->id();
|
||||
$status = file_prepare_directory($directory, FILE_CREATE_DIRECTORY);
|
||||
$this->assertNotIdentical(FALSE, $status, 'Created the directory for the generated images for the test style.');
|
||||
|
||||
// Create a working copy of the file.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = array_shift($files);
|
||||
$image_info = image_get_info($file->uri);
|
||||
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
// Let the image_module_test module know about this file, so it can claim
|
||||
// ownership in hook_file_download().
|
||||
|
@ -127,9 +126,9 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
$this->assertNotIdentical(FALSE, $original_uri, 'Created the generated image file.');
|
||||
|
||||
// Get the URL of a file that has not been generated and try to create it.
|
||||
$generated_uri = image_style_path($this->style_name, $original_uri);
|
||||
$generated_uri = $this->style->buildUri($original_uri);
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$generate_url = image_style_url($this->style_name, $original_uri, $clean_url);
|
||||
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
|
||||
|
||||
// Ensure that the tests still pass when the file is generated by accessing
|
||||
// a poorly constructed (but still valid) file URL that has an extra slash
|
||||
|
@ -137,7 +136,7 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
if ($extra_slash) {
|
||||
$modified_uri = str_replace('://', ':///', $original_uri);
|
||||
$this->assertNotEqual($original_uri, $modified_uri, 'An extra slash was added to the generated file URI.');
|
||||
$generate_url = image_style_url($this->style_name, $modified_uri, $clean_url);
|
||||
$generate_url = $this->style->buildUrl($modified_uri, $clean_url);
|
||||
}
|
||||
if (!$clean_url) {
|
||||
$this->assertTrue(strpos($generate_url, 'index.php/') !== FALSE, 'When using non-clean URLS, the system path contains the script name.');
|
||||
|
@ -162,8 +161,8 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
$this->assertNotEqual(strpos($this->drupalGetHeader('Cache-Control'), 'no-cache'), FALSE, 'Cache-Control header contains \'no-cache\' to prevent caching.');
|
||||
$this->assertEqual($this->drupalGetHeader('X-Image-Owned-By'), 'image_module_test', 'Expected custom header has been added.');
|
||||
|
||||
// Make sure that a second request to the already existing derivate works
|
||||
// too.
|
||||
// Make sure that a second request to the already existing derivative
|
||||
// works too.
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(200, 'Image was generated at the URL.');
|
||||
|
||||
|
@ -177,9 +176,9 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
// make sure that access is denied.
|
||||
$file_noaccess = array_shift($files);
|
||||
$original_uri_noaccess = file_unmanaged_copy($file_noaccess->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
$generated_uri_noaccess = $scheme . '://styles/' . $this->style_name . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
|
||||
$generated_uri_noaccess = $scheme . '://styles/' . $this->style->id() . '/' . $scheme . '/'. drupal_basename($original_uri_noaccess);
|
||||
$this->assertFalse(file_exists($generated_uri_noaccess), 'Generated file does not exist.');
|
||||
$generate_url_noaccess = image_style_url($this->style_name, $original_uri_noaccess);
|
||||
$generate_url_noaccess = $this->style->buildUrl($original_uri_noaccess);
|
||||
|
||||
$this->drupalGet($generate_url_noaccess);
|
||||
$this->assertResponse(403, 'Confirmed that access is denied for the private image style.');
|
||||
|
@ -206,7 +205,6 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
// Create another working copy of the file.
|
||||
$files = $this->drupalGetTestFiles('image');
|
||||
$file = array_shift($files);
|
||||
$image_info = image_get_info($file->uri);
|
||||
$original_uri = file_unmanaged_copy($file->uri, $scheme . '://', FILE_EXISTS_RENAME);
|
||||
// Let the image_module_test module know about this file, so it can claim
|
||||
// ownership in hook_file_download().
|
||||
|
@ -216,12 +214,12 @@ class ImageStylesPathAndUrlTest extends WebTestBase {
|
|||
// has not been created and try to create it. Check that the security token
|
||||
// is not present in the URL but that the image is still accessible.
|
||||
config('image.settings')->set('suppress_itok_output', TRUE)->save();
|
||||
$generated_uri = image_style_path($this->style_name, $original_uri);
|
||||
$generated_uri = $this->style->buildUri($original_uri);
|
||||
$this->assertFalse(file_exists($generated_uri), 'Generated file does not exist.');
|
||||
$generate_url = image_style_url($this->style_name, $original_uri, $clean_url);
|
||||
$generate_url = $this->style->buildUrl($original_uri, $clean_url);
|
||||
$this->assertIdentical(strpos($generate_url, IMAGE_DERIVATIVE_TOKEN . '='), FALSE, 'The security token does not appear in the image style URL.');
|
||||
$this->drupalGet($generate_url);
|
||||
$this->assertResponse(200, 'Image was accessible at the URL with a missing token.');
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class ImageThemeFunctionTest extends WebTestBase {
|
|||
// Create a style.
|
||||
$style = entity_create('image_style', array('name' => 'test', 'label' => 'Test'));
|
||||
$style->save();
|
||||
$url = image_style_url('test', $original_uri);
|
||||
$url = $style->buildUrl($original_uri);
|
||||
|
||||
// Test using theme_image_formatter() without an image title, alt text, or
|
||||
// link options.
|
||||
|
@ -84,7 +84,7 @@ class ImageThemeFunctionTest extends WebTestBase {
|
|||
// Create a style.
|
||||
$style = entity_create('image_style', array('name' => 'image_test', 'label' => 'Test'));
|
||||
$style->save();
|
||||
$url = image_style_url('image_test', $original_uri);
|
||||
$url = $style->buildUrl($original_uri);
|
||||
|
||||
$path = $this->randomName();
|
||||
$element = array(
|
||||
|
|
|
@ -182,7 +182,8 @@ class PictureFieldDisplayTest extends ImageFieldTestBase {
|
|||
$display->setComponent($field_name, $display_options)
|
||||
->save();
|
||||
|
||||
$this->drupalGet(image_style_url('large', $image_uri));
|
||||
$large_style = entity_load('image_style', 'large');
|
||||
$this->drupalGet($large_style->buildUrl($image_uri));
|
||||
$image_info['uri'] = $image_uri;
|
||||
$image_info['width'] = 480;
|
||||
$image_info['height'] = 240;
|
||||
|
@ -194,7 +195,7 @@ class PictureFieldDisplayTest extends ImageFieldTestBase {
|
|||
if ($scheme == 'private') {
|
||||
// Log out and try to access the file.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet(image_style_url('large', $image_uri));
|
||||
$this->drupalGet($large_style->buildUrl($image_uri));
|
||||
$this->assertResponse('403', 'Access denied to image style thumbnail as anonymous user.');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ function theme_picture($variables) {
|
|||
|
||||
// Fallback image, output as source with media query.
|
||||
$sources[] = array(
|
||||
'src' => image_style_url($variables['style_name'], $variables['uri']),
|
||||
'src' => entity_load('image_style', $variables['style_name'])->buildUrl($variables['uri']),
|
||||
'dimensions' => picture_get_image_dimensions($variables),
|
||||
);
|
||||
|
||||
|
@ -244,7 +244,7 @@ function theme_picture($variables) {
|
|||
// Only one image, use src.
|
||||
if (count($new_sources) == 1) {
|
||||
$sources[] = array(
|
||||
'src' => image_style_url($new_sources[0]['style_name'], $new_sources[0]['uri']),
|
||||
'src' => entity_load('image_style', $new_sources[0]['style_name'])->buildUrl($new_sources[0]['uri']),
|
||||
'dimensions' => picture_get_image_dimensions($new_sources[0]),
|
||||
'media' => $breakpoint->mediaQuery,
|
||||
);
|
||||
|
@ -253,7 +253,7 @@ function theme_picture($variables) {
|
|||
// Multiple images, use srcset.
|
||||
$srcset = array();
|
||||
foreach ($new_sources as $new_source) {
|
||||
$srcset[] = image_style_url($new_source['style_name'], $new_source['uri']) . ' ' . $new_source['#multiplier'];
|
||||
$srcset[] = entity_load('image_style', $new_source['style_name'])->buildUrl($new_source['uri']) . ' ' . $new_source['#multiplier'];
|
||||
}
|
||||
$sources[] = array(
|
||||
'srcset' => implode(', ', $srcset),
|
||||
|
@ -338,7 +338,7 @@ function picture_get_image_dimensions($variables) {
|
|||
'height' => $variables['height'],
|
||||
);
|
||||
|
||||
image_style_transform_dimensions($variables['style_name'], $dimensions);
|
||||
entity_load('image_style', $variables['style_name'])->transformDimensions($dimensions);
|
||||
|
||||
return $dimensions;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ class ImageFieldAttributesTest extends ImageFieldTestBase {
|
|||
|
||||
// Construct the node and image URIs for testing.
|
||||
$node_uri = url('node/' . $this->node->id(), array('absolute' => TRUE));
|
||||
$image_uri = image_style_url('medium', $this->file->getFileUri());
|
||||
$image_uri = entity_load('image_style', 'medium')->buildUrl($this->file->getFileUri());
|
||||
|
||||
// Test relations from node to image.
|
||||
$expected_value = array(
|
||||
|
|
|
@ -85,7 +85,7 @@ class StandardProfileTest extends WebTestBase {
|
|||
// Set URIs.
|
||||
// Image.
|
||||
$image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('target_id')->getValue());
|
||||
$this->imageUri = image_style_url('large', $image_file->getFileUri());
|
||||
$this->imageUri = entity_load('image_style', 'large')->buildUrl($image_file->getFileUri());
|
||||
// Term.
|
||||
$term_uri_info = $this->term->uri();
|
||||
$this->termUri = url($term_uri_info['path'], array('absolute' => TRUE));
|
||||
|
@ -164,7 +164,7 @@ class StandardProfileTest extends WebTestBase {
|
|||
// @todo Once the image points to the original instead of the processed
|
||||
// image, move this to testArticleProperties().
|
||||
$image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('target_id')->getValue());
|
||||
$image_uri = image_style_url('medium', $image_file->getFileUri());
|
||||
$image_uri = entity_load('image_style', 'medium')->buildUrl($image_file->getFileUri());
|
||||
$expected_value = array(
|
||||
'type' => 'uri',
|
||||
'value' => $image_uri,
|
||||
|
|
|
@ -344,7 +344,7 @@ function rdf_preprocess_field(&$variables) {
|
|||
// this field has a URI.
|
||||
if (isset($item['entity']->uri)) {
|
||||
if (!empty($element[$delta]['#image_style'])) {
|
||||
$variables['item_attributes'][$delta]['resource'] = image_style_url($element[$delta]['#image_style'], $item['entity']->getFileUri());
|
||||
$variables['item_attributes'][$delta]['resource'] = entity_load('image_style', $element[$delta]['#image_style'])->buildUrl($item['entity']->getFileUri());
|
||||
}
|
||||
else {
|
||||
$variables['item_attributes'][$delta]['resource'] = file_create_url($item['entity']->getFileUri());
|
||||
|
|
Loading…
Reference in New Issue