Less home code more F3

This commit is contained in:
julien
2026-03-28 23:29:06 +01:00
parent f7480eafe7
commit 1c8c22e12c
12 changed files with 107 additions and 116 deletions

View File

@@ -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
{