116 lines
3.5 KiB
PHP
116 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Legacy;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Artwork;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
final class LegacyArtworkPhotoController extends Controller
|
|
{
|
|
private const BASE62_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
|
|
|
private const THUMB_SIZE_MAP = [
|
|
0 => 'xs',
|
|
1 => 'xs',
|
|
2 => 'xs',
|
|
3 => 'sm',
|
|
4 => 'sm',
|
|
5 => 'sm',
|
|
6 => 'md',
|
|
];
|
|
|
|
private static ?bool $hasLegacyIdColumn = null;
|
|
|
|
public function __invoke(string $encoded, string $size, string $extension): RedirectResponse
|
|
{
|
|
$artworkId = $this->decodeBase62($encoded);
|
|
$sizeCode = (int) $size;
|
|
|
|
abort_if($artworkId === null || $artworkId < 1, 404);
|
|
|
|
$artwork = $this->resolveArtwork($artworkId);
|
|
abort_unless($artwork !== null, 404);
|
|
|
|
$targetUrl = $sizeCode === 7
|
|
? $this->resolveOriginalUrl($artwork)
|
|
: $artwork->thumbUrl(self::THUMB_SIZE_MAP[$sizeCode] ?? 'md');
|
|
|
|
abort_if(empty($targetUrl), 404);
|
|
|
|
return redirect()->away($targetUrl, 301);
|
|
}
|
|
|
|
private function decodeBase62(string $value): ?int
|
|
{
|
|
if ($value === '') {
|
|
return null;
|
|
}
|
|
|
|
$alphabet = array_flip(str_split(self::BASE62_CHARS));
|
|
$decoded = 0;
|
|
|
|
foreach (str_split($value) as $character) {
|
|
if (! array_key_exists($character, $alphabet)) {
|
|
return null;
|
|
}
|
|
|
|
$decoded = ($decoded * 62) + $alphabet[$character];
|
|
}
|
|
|
|
return $decoded;
|
|
}
|
|
|
|
private function resolveArtwork(int $artworkId): ?Artwork
|
|
{
|
|
return Artwork::query()
|
|
->select(['id', 'hash', 'thumb_ext', 'file_ext', 'file_path', 'is_public', 'is_approved', 'published_at'])
|
|
->where(function (Builder $query) use ($artworkId): void {
|
|
$query->where('id', $artworkId);
|
|
|
|
if ($this->hasLegacyIdColumn()) {
|
|
$query->orWhere('legacy_id', $artworkId);
|
|
}
|
|
})
|
|
->where('is_public', true)
|
|
->where('is_approved', true)
|
|
->whereNotNull('published_at')
|
|
->first();
|
|
}
|
|
|
|
private function resolveOriginalUrl(Artwork $artwork): ?string
|
|
{
|
|
$cdn = rtrim((string) config('cdn.files_url', 'https://cdn.skinbase.org'), '/');
|
|
$filePath = trim((string) ($artwork->file_path ?? ''), '/');
|
|
|
|
if ($filePath !== '') {
|
|
return $cdn . '/' . $filePath;
|
|
}
|
|
|
|
$hash = strtolower((string) preg_replace('/[^a-f0-9]/i', '', (string) ($artwork->hash ?? '')));
|
|
$ext = ltrim((string) ($artwork->file_ext ?: $artwork->thumb_ext ?: 'webp'), '.');
|
|
|
|
if ($hash === '') {
|
|
return $artwork->thumbUrl('xl') ?? $artwork->thumbUrl('lg') ?? $artwork->thumbUrl('md');
|
|
}
|
|
|
|
$prefix = trim((string) config('uploads.object_storage.prefix', 'artworks'), '/');
|
|
$firstDir = substr($hash, 0, 2);
|
|
$secondDir = substr($hash, 2, 2);
|
|
|
|
return sprintf('%s/%s/original/%s/%s/%s.%s', $cdn, $prefix, $firstDir, $secondDir, $hash, $ext);
|
|
}
|
|
|
|
private function hasLegacyIdColumn(): bool
|
|
{
|
|
if (self::$hasLegacyIdColumn === null) {
|
|
self::$hasLegacyIdColumn = Schema::hasColumn('artworks', 'legacy_id');
|
|
}
|
|
|
|
return self::$hasLegacyIdColumn;
|
|
}
|
|
} |