mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-06-25 16:19:19 +02:00
feat: FilePond production hardening — extension-based validation, server-side size limits (2GB), annexe validation, drop accept attributes, FilePond file styling
This commit is contained in:
@@ -34,12 +34,18 @@
|
||||
*/
|
||||
trait ThesisFileHandler
|
||||
{
|
||||
/** @var string[] Warnings collected during file processing (e.g. invalid type, too large). */
|
||||
private array $fileWarnings = [];
|
||||
|
||||
/** Maximum allowed file size for thesis files (bytes). */
|
||||
private const MAX_FILE_SIZE = 500 * 1024 * 1024; // 500 MB
|
||||
|
||||
/** Maximum allowed file size for PDF files specifically (bytes). */
|
||||
private const MAX_PDF_SIZE = 100 * 1024 * 1024; // 100 MB
|
||||
|
||||
/** Maximum allowed file size for video/audio files (bytes). */
|
||||
private const MAX_AV_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB
|
||||
|
||||
/** Cover image max size. */
|
||||
private const MAX_COVER_SIZE = 20 * 1024 * 1024; // 20 MB
|
||||
|
||||
@@ -68,6 +74,15 @@ trait ThesisFileHandler
|
||||
|
||||
// ── Public entry points (called by controllers) ──────────────────────────
|
||||
|
||||
/**
|
||||
* Get warnings collected during file processing (invalid types, too large, etc.).
|
||||
* @return string[]
|
||||
*/
|
||||
public function getFileWarnings(): array
|
||||
{
|
||||
return $this->fileWarnings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a cover image upload.
|
||||
*
|
||||
@@ -92,6 +107,7 @@ trait ThesisFileHandler
|
||||
if (!in_array($mimeType, $allowedMimes, true)
|
||||
|| !in_array($ext, $allowedExts, true)
|
||||
|| $upload['size'] > self::MAX_COVER_SIZE) {
|
||||
$this->fileWarnings[] = "Couverture « {$upload['name']} » ignorée : format ou taille non accepté.";
|
||||
error_log("ThesisFileHandler: invalid cover MIME $mimeType / $ext / {$upload['size']} bytes, skipping");
|
||||
return;
|
||||
}
|
||||
@@ -141,10 +157,12 @@ trait ThesisFileHandler
|
||||
$ext = strtolower(pathinfo($upload['name'], PATHINFO_EXTENSION));
|
||||
|
||||
if ($mimeType !== 'application/pdf' || $ext !== 'pdf') {
|
||||
$this->fileWarnings[] = "Note d'intention « {$upload['name']} » ignorée : seul le format PDF est accepté.";
|
||||
error_log("ThesisFileHandler: invalid note d'intention MIME $mimeType, skipping");
|
||||
return;
|
||||
}
|
||||
if ($upload['size'] > self::MAX_PDF_SIZE) {
|
||||
$this->fileWarnings[] = "Note d'intention « {$upload['name']} » ignorée : fichier trop volumineux (max 100 MB).";
|
||||
error_log("ThesisFileHandler: note d'intention too large ({$upload['size']} bytes), skipping");
|
||||
return;
|
||||
}
|
||||
@@ -223,19 +241,25 @@ trait ThesisFileHandler
|
||||
$mimeType = 'text/vtt';
|
||||
}
|
||||
if ($mimeType === 'application/octet-stream' && !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Fichier TFE « {$uploads['name'][$i]} » ignoré : format .$ext non accepté.";
|
||||
error_log("ThesisFileHandler: TFE extension not allowed {$uploads['name'][$i]} ($ext), skipping");
|
||||
continue;
|
||||
}
|
||||
if (!in_array($mimeType, self::ALLOWED_MIME_TYPES, true)
|
||||
&& !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Fichier TFE « {$uploads['name'][$i]} » ignoré : type non accepté ($mimeType).";
|
||||
error_log("ThesisFileHandler: invalid TFE type {$uploads['name'][$i]} ($mimeType / $ext), skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
$isPdf = ($mimeType === 'application/pdf' || $ext === 'pdf');
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : self::MAX_FILE_SIZE;
|
||||
$isAv = preg_match('/^(video|audio)\//', $mimeType) || in_array($ext, ['mp4','webm','ogv','mov','mp3','ogg','oga','wav','flac','aac','m4a']);
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : ($isAv ? self::MAX_AV_SIZE : self::MAX_FILE_SIZE);
|
||||
if ($uploads['size'][$i] > $sizeLimit) {
|
||||
error_log("ThesisFileHandler: TFE file too large {$uploads['name'][$i]} (" . round($uploads['size'][$i] / 1024 / 1024) . ' MB), skipping');
|
||||
$limitMb = round($sizeLimit / 1024 / 1024);
|
||||
$sizeMb = round($uploads['size'][$i] / 1024 / 1024);
|
||||
$this->fileWarnings[] = "Fichier TFE « {$uploads['name'][$i]} » ignoré : trop volumineux ($sizeMb MB, max $limitMb MB).";
|
||||
error_log("ThesisFileHandler: TFE file too large {$uploads['name'][$i]} (" . $sizeMb . ' MB), skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -364,19 +388,25 @@ trait ThesisFileHandler
|
||||
$mimeType = 'text/vtt';
|
||||
}
|
||||
if ($mimeType === 'application/octet-stream' && !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Fichier « {$uploads['name'][$i]} » ignoré : format .$ext non accepté.";
|
||||
error_log("ThesisFileHandler: queue file extension not allowed {$uploads['name'][$i]} ($ext), skipping");
|
||||
continue;
|
||||
}
|
||||
if (!in_array($mimeType, self::ALLOWED_MIME_TYPES, true)
|
||||
&& !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Fichier « {$uploads['name'][$i]} » ignoré : type non accepté ($mimeType).";
|
||||
error_log("ThesisFileHandler: invalid queue file type {$uploads['name'][$i]} ($mimeType / $ext), skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
$isPdf = ($mimeType === 'application/pdf' || $ext === 'pdf');
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : self::MAX_FILE_SIZE;
|
||||
$isAv = preg_match('/^(video|audio)\//', $mimeType) || in_array($ext, ['mp4','webm','ogv','mov','mp3','ogg','oga','wav','flac','aac','m4a']);
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : ($isAv ? self::MAX_AV_SIZE : self::MAX_FILE_SIZE);
|
||||
if ($uploads['size'][$i] > $sizeLimit) {
|
||||
error_log("ThesisFileHandler: queue file too large {$uploads['name'][$i]} (" . round($uploads['size'][$i] / 1024 / 1024) . ' MB), skipping');
|
||||
$limitMb = round($sizeLimit / 1024 / 1024);
|
||||
$sizeMb = round($uploads['size'][$i] / 1024 / 1024);
|
||||
$this->fileWarnings[] = "Fichier « {$uploads['name'][$i]} » ignoré : trop volumineux ($sizeMb MB, max $limitMb MB).";
|
||||
error_log("ThesisFileHandler: queue file too large {$uploads['name'][$i]} (" . $sizeMb . ' MB), skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -461,6 +491,28 @@ trait ThesisFileHandler
|
||||
if ($mimeType === 'text/plain' && $ext === 'vtt') {
|
||||
$mimeType = 'text/vtt';
|
||||
}
|
||||
if ($mimeType === 'application/octet-stream' && !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : format .$ext non accepté.";
|
||||
error_log("ThesisFileHandler: queue annexe extension not allowed {$uploads['name'][$i]} ($ext), skipping");
|
||||
continue;
|
||||
}
|
||||
if (!in_array($mimeType, self::ALLOWED_MIME_TYPES, true)
|
||||
&& !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : type non accepté ($mimeType).";
|
||||
error_log("ThesisFileHandler: invalid queue annexe type {$uploads['name'][$i]} ($mimeType / $ext), skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Annexes: PDF max 100 MB, everything else max 500 MB
|
||||
$isPdf = ($mimeType === 'application/pdf' || $ext === 'pdf');
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : self::MAX_FILE_SIZE;
|
||||
if ($uploads['size'][$i] > $sizeLimit) {
|
||||
$limitMb = round($sizeLimit / 1024 / 1024);
|
||||
$sizeMb = round($uploads['size'][$i] / 1024 / 1024);
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : trop volumineuse ($sizeMb MB, max $limitMb MB).";
|
||||
error_log("ThesisFileHandler: queue annexe too large {$uploads['name'][$i]} (" . $sizeMb . ' MB), skipping');
|
||||
continue;
|
||||
}
|
||||
|
||||
$padded = sprintf('%02d', $num);
|
||||
$targetName = $filePrefix . '_ANNEXE_' . $padded . '.' . $ext;
|
||||
@@ -530,19 +582,25 @@ trait ThesisFileHandler
|
||||
$mimeType = 'text/vtt';
|
||||
}
|
||||
if ($mimeType === 'application/octet-stream' && !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : format .$ext non accepté.";
|
||||
error_log("ThesisFileHandler: annexe extension not allowed {$uploads['name'][$i]} ($ext), skipping");
|
||||
continue;
|
||||
}
|
||||
if (!in_array($mimeType, self::ALLOWED_MIME_TYPES, true)
|
||||
&& !in_array($ext, self::ALLOWED_EXTENSIONS, true)) {
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : type non accepté ($mimeType).";
|
||||
error_log("ThesisFileHandler: invalid annexe type {$uploads['name'][$i]} ($mimeType / $ext), skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
$isPdf = ($mimeType === 'application/pdf' || $ext === 'pdf');
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : self::MAX_FILE_SIZE;
|
||||
$isAv = preg_match('/^(video|audio)\//', $mimeType) || in_array($ext, ['mp4','webm','ogv','mov','mp3','ogg','oga','wav','flac','aac','m4a']);
|
||||
$sizeLimit = $isPdf ? self::MAX_PDF_SIZE : ($isAv ? self::MAX_AV_SIZE : self::MAX_FILE_SIZE);
|
||||
if ($uploads['size'][$i] > $sizeLimit) {
|
||||
error_log("ThesisFileHandler: annexe too large {$uploads['name'][$i]} (" . round($uploads['size'][$i] / 1024 / 1024) . " MB), skipping");
|
||||
$limitMb = round($sizeLimit / 1024 / 1024);
|
||||
$sizeMb = round($uploads['size'][$i] / 1024 / 1024);
|
||||
$this->fileWarnings[] = "Annexe « {$uploads['name'][$i]} » ignorée : trop volumineuse ($sizeMb MB, max $limitMb MB).";
|
||||
error_log("ThesisFileHandler: annexe too large {$uploads['name'][$i]} (" . $sizeMb . " MB), skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user