required code from last commit

This commit is contained in:
Luke Towers 2020-08-08 20:18:11 -06:00
parent 263ae871b7
commit 6926908dad
2 changed files with 142 additions and 40 deletions

View File

@ -2,8 +2,10 @@
use App;
use Url;
use Crypt;
use Cache;
use Event;
use Config;
use Storage;
use SystemException;
use October\Rain\Database\Attach\File as FileModel;
@ -130,7 +132,7 @@ class ImageResizer
* Prepare the resizer instance
*
* @param mixed $image Supported values below:
* ['disk' => string, 'path' => string],
* ['disk' => Illuminate\Filesystem\FilesystemAdapter, 'path' => string],
* instance of October\Rain\Database\Attach\File,
* string containing URL or path accessible to the application's filesystem manager
* @param integer|bool|null $width Desired width of the resized image
@ -155,7 +157,7 @@ class ImageResizer
public static function fromIdentifier(string $identifier)
{
// Attempt to retrieve the resizer configuration and remove the data from the cache after retrieval
$config = Cache::pull(static::CACHE_PREFIX . $identifier, null);
$config = Cache::get(static::CACHE_PREFIX . $identifier, null); // @TODO: replace with pull()
// Validate that the desired config was able to be loaded
if (empty($config)) {
@ -165,6 +167,39 @@ class ImageResizer
return new static($config['image'], $config['width'], $config['height'], $config['options']);
}
/**
* Get the default options for the resizer
*
* @return array
*/
public function getDefaultOptions()
{
// Default options for the built in resizing processor
$defaultOptions = [
'mode' => 'auto',
'offset' => [0, 0],
'sharpen' => 0,
'interlace' => false,
'quality' => 90,
'extension' => pathinfo($this->image['path'], PATHINFO_EXTENSION),
];
/**
* @event system.resizer.getDefaultOptions
* Provides an opportunity to modify the default options used when generating image resize requests
*
* Example usage:
*
* Event::listen('system.resizer.getDefaultOptions', function ((array) &$defaultOptions)) {
* $defaultOptions['background'] = '#f2f2f2';
* });
*
*/
Event::fire('system.resizer.getDefaultOptions', [&$defaultOptions]);
return $defaultOptions;
}
/**
* Get the available sources for processing image resize requests from
*
@ -222,6 +257,17 @@ class ImageResizer
}
public function getConfig()
{
return [
'image' => $this->image,
'width' => $this->width,
'height' => $this->height,
'options' => $this->options,
];
}
/**
* Gets the identifier for provided resizing configuration
* This method validates, authorizes, and prepares the resizing request for execution by the resizer
@ -233,24 +279,17 @@ class ImageResizer
*/
public function getIdentifier()
{
if ($this->identifer) {
if ($this->identifier) {
return $this->identifier;
}
// Prepare the configuration
$config = [
'image' => $this->image,
'width' => $this->width,
'height' => $this->height,
'options' => $this->options,
];
// Generate the identifier
$this->identifier = hash_hmac('sha1', json_encode($config), App::make('encrypter')->getKey());
$this->identifier = hash_hmac('sha1', $this->getResizedUrl(), Crypt::getKey());
// If the image hasn't been resized yet, then store the config data for the resizer to use
if (!$this->isResized()) {
Cache::put(static::CACHE_PREFIX . $this->identifier, $config);
// @TODO: remove the cache timeout when testing in Laravel 6, L5.5 didn't support rememberForever in put
Cache::put(static::CACHE_PREFIX . $this->identifier, $this->getConfig(), now()->addMinutes(10));
}
return $this->identifier;
@ -260,28 +299,39 @@ class ImageResizer
* Normalize the provided input into information that the resizer can work with
*
* @param mixed $image Supported values below:
* ['disk' => string, 'path' => string],
* ['disk' => Illuminate\Filesystem\FilesystemAdapter, 'path' => string],
* instance of October\Rain\Database\Attach\File,
* string containing URL or path accessible to the application's filesystem manager
* @throws SystemException If the image was unable to be identified
* @return array Array containing the disk, path, and selected source name ['disk' => string, 'path' => string, 'source' => string]
* @return array Array containing the disk, path, and extension ['disk' => Illuminate\Filesystem\FilesystemAdapter, 'path' => string]
*/
public static function normalizeImage($image)
{
$disk = null;
$path = null;
$selectedSource = null;
// Process an array
if (is_array($image) && !empty($image['disk']) && !empty($image['path'])) {
$disk = $image['disk'];
$path = $image['path'];
// Verify that the source file exists
if (empty(pathinfo($path, PATHINFO_EXTENSION)) || !$disk->exists($path)) {
$disk = null;
$path = null;
}
// Process a FileModel
} elseif ($image instanceof FileModel) {
$disk = $image->getDisk();
$path = $image->getDiskPath();
// Verify that the source file exists
if (empty(pathinfo($path, PATHINFO_EXTENSION)) || !$disk->exists($path)) {
$disk = null;
$path = null;
}
// Process a string
} elseif (is_string($image)) {
// Parse the provided image path into a filesystem ready relative path
@ -312,8 +362,7 @@ class ImageResizer
$disk = Storage::disk($details['disk']);
// Verify that the file exists before exiting the identification process
if ($disk->exists($path)) {
$selectedSource = $source;
if (!empty(pathinfo($path, PATHINFO_EXTENSION)) && $disk->exists($path)) {
break;
} else {
$disk = null;
@ -324,14 +373,16 @@ class ImageResizer
}
}
if (!$disk || !$path || !$selectedSource) {
throw new SystemException("Unable to process the provided image: " . e(var_export($image)));
if (!$disk || !$path) {
if (is_object($image)) {
$image = get_class($image);
}
throw new SystemException("Unable to process the provided image: " . e(var_export($image, true)));
}
return [
'disk' => $disk,
'path' => $path,
'source' => $selectedSource,
];
}
@ -345,14 +396,14 @@ class ImageResizer
public function isResized()
{
// @Todo: need to centralize the target disk path / url generation logic
$targetPath = implode('/', array_slice(str_split($identifier, 10), 0, 4)) . '/' . pathinfo($image['path'], PATHINFO_FILENAME) . "_resized_{$data['width']}_{$data['height']}.{$data['options']['extension']}";
$targetPath = '/' . $this->getResizedName();
// @todo: Check if resized path exists on the target disk
}
public function resize($image, $width = null, $height = null, $options = [])
public function resize()
{
$identifier = static::getIdentifier($image, $width, $height, $options);
// @TODO: Resize the image
}
/**
@ -363,6 +414,17 @@ class ImageResizer
return pathinfo($this->image['path'], PATHINFO_FILENAME) . "_resized.{$this->options['extension']}";
}
/**
* Get the path of the resized image
*/
public function getResizedPath()
{
// Generate the unique file identifier for the resized image
$fileIdentifier = hash_hmac('sha1', serialize($this->getConfig()), Crypt::getKey());
return implode('/', array_slice(str_split($fileIdentifier, 10), 0, 4)) . '/';
}
/**
* Get the URL to the system resizer route for this instance's configuration
*
@ -371,22 +433,24 @@ class ImageResizer
public function getResizerUrl()
{
$identifier = $this->getIdentifier();
$resizedName = $this->getResizedName();
$source = $this->image['source'];
$resizedUrl = urlencode($this->getResizedUrl());
return Url::to("/resizer/$identifier/$source/$name");
return Url::to("/resizer/{$identifier}?t=$resizedUrl");
}
/**
* Get the URL to the resized image
*
* @param string $identifier The 40 character unique identifier for the image
* @param string $source The name of the source the image is being resized from
* @param string $name The filename of the resized image
* @return string
*/
public static function getResizedUrl(string $identifier, string $source, string $name)
public function getResizedUrl()
{
$resizedDisk = Storage::disk(Config::get('cms.resized.disk', 'local'));
return $resizedDisk->url(Config::get('cms.resized.folder', 'resized') . '/' . $this->getResizedPath() . $this->getResizedName());
$sources = static::getAvailableSources();
if (empty($sources[$source])) {
@ -407,10 +471,41 @@ class ImageResizer
return $url;
}
/**
* Check if the provided identifier looks like a valid identifier
*
* @param string $id
* @return bool
*/
public static function isValidIdentifier($id)
{
return is_string($id) && ctype_alnum($id) && strlen($id) === 40;
}
/**
* Check the provided encoded URL to verify its signature and return the decoded URL
*
* @param string $identifier
* @param string $encodedUrl
* @return string|null Returns null if the provided value was invalid
*/
public static function getValidResizedUrl($identifier, $encodedUrl)
{
$url = null;
$decodedUrl = urldecode($encodedUrl);
// The identifier should be the signed version of the decoded URL
if (static::isValidIdentifier($identifier) && $identifier === hash_hmac('sha1', $decodedUrl, Crypt::getKey())) {
$url = $decodedUrl;
}
return $url;
}
public function getUrl()
{
if ($this->isResized()) {
return static::getResizedUrl($this->identifier, $this->image['source'], $this->getResizedName());
return $this->getResizedUrl();
} else {
return $this->getResizerUrl();
}
@ -429,7 +524,7 @@ class ImageResizer
* @throws SystemException If the provided input was unable to be processed
* @return string
*/
public static function getFilterUrl()
public static function getFilterUrl($image, $width = null, $height = null, $options = [])
{
// Attempt to process the provided image
try {
@ -441,7 +536,7 @@ class ImageResizer
} elseif ($image instanceof FileModel) {
return $image->getPath();
} else {
throw new SystemException("Unable to process the provided image: " . e(var_export($image)));
throw $ex;
}
}

View File

@ -46,21 +46,28 @@ class SystemController extends ControllerBase
* and returns a redirect to the resized image
*
* @param string $identifier The identifier used to retrieve the image configuration
* @param string $source The name of the source the image is being resized from
* @param string $name The filename of the resized image
* @return RedirectResponse
*/
public function resize(string $identifier, string $source, string $name)
public function resizer(string $identifier)
{
// The URL-encoded URL to the resized image has to be passed as a GET variable
// because of Laravel rawurldecode's the requested URL before passing it to the routing engine
// @see https://github.com/laravel/framework/pull/4338
$encodedUrl = input('t');
$resizedUrl = ImageResizer::getValidResizedUrl($identifier, $encodedUrl);
if (empty($resizedUrl)) {
return response('Invalid identifier or redirect URL', 400);
}
// Attempt to process the resize
try {
$resizer = ImageResizer::fromIdentifier($identifier);
$resizer->resize();
} catch (SystemException $ex) {
// If the resizing failed it was most likely because the config had already been
// pulled from the cache so just continue to redirect the user to the final file anyways
// If the resizing failed it was most likely because it is in progress or has already finished
}
return redirect()->to(ImageResizer::getResizedUrl($identifier, $source, $name));
return redirect()->to($resizedUrl);
}
}