use Intervention\Image\Exception\NotSupportedException;
use Intervention\Image\Image as InterventionImage;
use Intervention\Image\ImageManager;
-use League\Flysystem\Util;
+use League\Flysystem\WhitespacePathNormalizer;
use Psr\SimpleCache\InvalidArgumentException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\StreamedResponse;
{
protected ImageManager $imageTool;
protected Cache $cache;
- protected $storageUrl;
protected FilesystemManager $fileSystem;
- protected static $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ protected static array $supportedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
public function __construct(ImageManager $imageTool, FilesystemManager $fileSystem, Cache $cache)
{
*/
protected function adjustPathForStorageDisk(string $path, string $imageType = ''): string
{
- $path = Util::normalizePath(str_replace('uploads/images/', '', $path));
+ $path = (new WhitespacePathNormalizer())->normalizePath(str_replace('uploads/images/', '', $path));
if ($this->usingSecureImages($imageType)) {
return $path;
protected function getStorageDiskName(string $imageType): string
{
$storageType = config('filesystems.images');
+ $localSecureInUse = ($storageType === 'local_secure' || $storageType === 'local_secure_restricted');
// Ensure system images (App logo) are uploaded to a public space
- if ($imageType === 'system' && $storageType === 'local_secure') {
- $storageType = 'local';
+ if ($imageType === 'system' && $localSecureInUse) {
+ return 'local';
}
// Rename local_secure options to get our image specific storage driver which
// is scoped to the relevant image directories.
- if ($storageType === 'local_secure' || $storageType === 'local_secure_restricted') {
- $storageType = 'local_secure_images';
+ if ($localSecureInUse) {
+ return 'local_secure_images';
}
return $storageType;
return $image;
}
+ public function replaceExistingFromUpload(string $path, string $type, UploadedFile $file): void
+ {
+ $imageData = file_get_contents($file->getRealPath());
+ $storage = $this->getStorageDisk($type);
+ $adjustedPath = $this->adjustPathForStorageDisk($path, $type);
+ $storage->put($adjustedPath, $imageData);
+ }
+
/**
* Save image data for the given path in the public space, if possible,
* for the provided storage mechanism.
* @throws Exception
* @throws InvalidArgumentException
*/
- public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false): string
+ public function getThumbnail(Image $image, ?int $width, ?int $height, bool $keepRatio = false, bool $forceCreate = false): string
{
// Do not resize GIF images where we're not cropping
if ($keepRatio && $this->isGif($image)) {
// Return path if in cache
$cachedThumbPath = $this->cache->get($thumbCacheKey);
- if ($cachedThumbPath) {
+ if ($cachedThumbPath && !$forceCreate) {
return $this->getPublicUrl($cachedThumbPath);
}
// If thumbnail has already been generated, serve that and cache path
$storage = $this->getStorageDisk($image->type);
- if ($storage->exists($this->adjustPathForStorageDisk($thumbFilePath, $image->type))) {
+ if (!$forceCreate && $storage->exists($this->adjustPathForStorageDisk($thumbFilePath, $image->type))) {
$this->cache->put($thumbCacheKey, $thumbFilePath, 60 * 60 * 72);
return $this->getPublicUrl($thumbFilePath);
{
try {
$thumb = $this->imageTool->make($imageData);
- } catch (ErrorException|NotSupportedException $e) {
+ } catch (ErrorException | NotSupportedException $e) {
throw new ImageUploadException(trans('errors.cannot_create_thumbs'));
}
Image::query()->whereIn('type', $types)
->chunk(1000, function ($images) use ($checkRevisions, &$deletedPaths, $dryRun) {
+ /** @var Image $image */
foreach ($images as $image) {
$searchQuery = '%' . basename($image->path) . '%';
$inPage = DB::table('pages')
// Check the image file exists
&& $disk->exists($imagePath)
// Check the file is likely an image file
- && strpos($disk->getMimetype($imagePath), 'image/') === 0;
+ && strpos($disk->mimeType($imagePath), 'image/') === 0;
}
/**
}
// Strip thumbnail element from path if existing
- $originalPathSplit = array_filter(explode('/', $path), function(string $part) {
+ $originalPathSplit = array_filter(explode('/', $path), function (string $part) {
$resizedDir = (strpos($part, 'thumbs-') === 0 || strpos($part, 'scaled-') === 0);
$missingExtension = strpos($part, '.') === false;
+
return !($resizedDir && $missingExtension);
});
*/
private function getPublicUrl(string $filePath): string
{
- if (is_null($this->storageUrl)) {
- $storageUrl = config('filesystems.url');
-
- // Get the standard public s3 url if s3 is set as storage type
- // Uses the nice, short URL if bucket name has no periods in otherwise the longer
- // region-based url will be used to prevent http issues.
- if ($storageUrl == false && config('filesystems.images') === 's3') {
- $storageDetails = config('filesystems.disks.s3');
- if (strpos($storageDetails['bucket'], '.') === false) {
- $storageUrl = 'https://' . $storageDetails['bucket'] . '.s3.amazonaws.com';
- } else {
- $storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
- }
+ $storageUrl = config('filesystems.url');
+
+ // Get the standard public s3 url if s3 is set as storage type
+ // Uses the nice, short URL if bucket name has no periods in otherwise the longer
+ // region-based url will be used to prevent http issues.
+ if (!$storageUrl && config('filesystems.images') === 's3') {
+ $storageDetails = config('filesystems.disks.s3');
+ if (strpos($storageDetails['bucket'], '.') === false) {
+ $storageUrl = 'https://' . $storageDetails['bucket'] . '.s3.amazonaws.com';
+ } else {
+ $storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
}
-
- $this->storageUrl = $storageUrl;
}
- $basePath = ($this->storageUrl == false) ? url('/') : $this->storageUrl;
+ $basePath = $storageUrl ?: url('/');
return rtrim($basePath, '/') . $filePath;
}