Less home code more F3
This commit is contained in:
@@ -8,14 +8,18 @@ class Media extends DB\SQL\Mapper
|
||||
private const MAX_HEIGHT = 8000;
|
||||
private const MAX_PIXELS = 40_000_000;
|
||||
|
||||
public function __construct(DB\SQL $db)
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct($db, 'media');
|
||||
parent::__construct(Base::instance()->get('DB'), 'media');
|
||||
}
|
||||
|
||||
public static function bootstrap(DB\SQL $db): void
|
||||
{
|
||||
$db->exec('CREATE TABLE IF NOT EXISTS media (
|
||||
if ($db->schema('media', null, 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$db->exec('CREATE TABLE media (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
file_name TEXT NOT NULL UNIQUE,
|
||||
alt TEXT NOT NULL DEFAULT \'\',
|
||||
@@ -23,7 +27,7 @@ class Media extends DB\SQL\Mapper
|
||||
height INTEGER NOT NULL,
|
||||
created_at TEXT NOT NULL
|
||||
)');
|
||||
$db->exec('CREATE INDEX IF NOT EXISTS idx_media_created_at ON media(created_at DESC)');
|
||||
$db->exec('CREATE INDEX idx_media_created_at ON media(created_at DESC)');
|
||||
}
|
||||
|
||||
public function paginateLibrary(int $page = 1, int $perPage = 24): array
|
||||
@@ -89,19 +93,30 @@ class Media extends DB\SQL\Mapper
|
||||
public function upload(string $srcPath, string $originalName = ''): int
|
||||
{
|
||||
$target = null;
|
||||
$image = null;
|
||||
$committed = false; // Contrôle le nettoyage de $target dans finally.
|
||||
|
||||
try {
|
||||
$meta = self::inspectUpload($srcPath);
|
||||
$image = self::openImageResource($srcPath, $meta['mime']);
|
||||
|
||||
[$format, $extension] = self::targetFormat($meta['mime']);
|
||||
// F3 Image : load() utilise imagecreatefromstring + imagesavealpha.
|
||||
$img = new \Image();
|
||||
if (!$img->load(file_get_contents($srcPath))) {
|
||||
throw new RuntimeException('Fichier image invalide ou format source non supporté.');
|
||||
}
|
||||
|
||||
// PNG/WebP → PNG (préserve la transparence), JPG → JPG.
|
||||
$isJpeg = ($meta['mime'] === 'image/jpeg');
|
||||
$extension = $isJpeg ? 'jpg' : 'png';
|
||||
|
||||
// Nom aléatoire : empêche le path traversal et la devinabilité des URLs.
|
||||
$fileName = bin2hex(random_bytes(16)) . '.' . $extension;
|
||||
$target = app_public_media_dir() . '/' . $fileName;
|
||||
|
||||
self::writeImage($image, $target, $format);
|
||||
// dump() appelle image{format}($data, NULL, $quality).
|
||||
$binary = $isJpeg ? $img->dump('jpeg', 85) : $img->dump('png', 6);
|
||||
if ($binary === '' || file_put_contents($target, $binary) === false) {
|
||||
throw new RuntimeException('Impossible d\'enregistrer cette image.');
|
||||
}
|
||||
|
||||
$this->db->begin();
|
||||
try {
|
||||
@@ -123,9 +138,7 @@ class Media extends DB\SQL\Mapper
|
||||
} catch (Throwable $e) {
|
||||
throw $e instanceof RuntimeException ? $e : new RuntimeException('Impossible d\'enregistrer cette image.');
|
||||
} finally {
|
||||
if ($image instanceof GdImage) {
|
||||
imagedestroy($image);
|
||||
}
|
||||
// Le destructeur de F3 Image libère la ressource GD.
|
||||
if (is_file($srcPath)) {
|
||||
@unlink($srcPath);
|
||||
}
|
||||
@@ -202,51 +215,6 @@ class Media extends DB\SQL\Mapper
|
||||
];
|
||||
}
|
||||
|
||||
private static function openImageResource(string $srcPath, string $mime): GdImage
|
||||
{
|
||||
$image = match ($mime) {
|
||||
'image/jpeg' => @imagecreatefromjpeg($srcPath),
|
||||
'image/png' => @imagecreatefrompng($srcPath),
|
||||
'image/webp' => @imagecreatefromwebp($srcPath),
|
||||
default => false,
|
||||
};
|
||||
|
||||
if (!$image instanceof GdImage) {
|
||||
throw new RuntimeException('Fichier image invalide ou format source non supporté.');
|
||||
}
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
// PNG/WebP → PNG pour préserver la transparence de manière fiable.
|
||||
// JPG reste en JPG (pas de canal alpha).
|
||||
private static function targetFormat(string $mime): array
|
||||
{
|
||||
return match ($mime) {
|
||||
'image/jpeg' => ['jpeg', 'jpg'],
|
||||
'image/png', 'image/webp' => ['png', 'png'],
|
||||
default => throw new RuntimeException('Format non supporté. Utilise JPG, PNG ou WebP.'),
|
||||
};
|
||||
}
|
||||
|
||||
private static function writeImage(GdImage $image, string $target, string $format): void
|
||||
{
|
||||
if ($format === 'png') {
|
||||
if (!imageistruecolor($image)) {
|
||||
imagepalettetotruecolor($image);
|
||||
}
|
||||
imagealphablending($image, false);
|
||||
imagesavealpha($image, true);
|
||||
$written = @imagepng($image, $target, 6);
|
||||
} else {
|
||||
$written = @imagejpeg($image, $target, 85);
|
||||
}
|
||||
|
||||
if ($written !== true || !is_file($target)) {
|
||||
throw new RuntimeException('Impossible d\'enregistrer cette image.');
|
||||
}
|
||||
}
|
||||
|
||||
// Dérive un texte alternatif lisible depuis le nom de fichier d'origine.
|
||||
private static function altFromFilename(string $filename): string
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user