mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-05-06 19:19:19 +02:00
Add SQLite database schema and documentation
Added complete database schema for Post-ERG thesis archive: - schema.sql with full relational database structure - README.md with schema documentation and usage examples - SETUP.md with comprehensive setup and maintenance guide - posterg_fiche-technique.md with technical specifications - Database_TFE_test.csv and .ods with example data Database features: - Normalized relational schema (3NF) - Support for multiple authors, supervisors, languages, formats, keywords - Publication workflow (submission → defense → jury review → publication) - Access control (Libre/Interne/Interdit) - File attachments tracking - Predefined reference tables for orientations, AP programs, finalities - Views for simplified querying - Automatic timestamps and cascade deletes
This commit is contained in:
@@ -5,6 +5,16 @@ ini_set('display_errors', 0);
|
||||
ini_set('log_errors', 1);
|
||||
ini_set('error_log', 'error.log');
|
||||
|
||||
// Start session for CSRF protection
|
||||
session_start();
|
||||
|
||||
// Verify CSRF token
|
||||
if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) ||
|
||||
!hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
|
||||
error_log("CSRF token validation failed");
|
||||
die("Erreur de sécurité : token invalide. Veuillez recharger le formulaire.");
|
||||
}
|
||||
|
||||
// Log the content of the $_FILES array
|
||||
error_log("FILES array: " . print_r($_FILES, true));
|
||||
|
||||
@@ -12,136 +22,211 @@ require_once 'vendor/autoload.php';
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Behat\Transliterator\Transliterator;
|
||||
|
||||
// Helper function to sanitize string input (replacement for deprecated FILTER_SANITIZE_STRING)
|
||||
function sanitize_string($input) {
|
||||
return htmlspecialchars(strip_tags(trim($input)), ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
// Helper function to validate required field
|
||||
function validate_required($value, $fieldName) {
|
||||
if (empty($value)) {
|
||||
throw new Exception("Le champ '$fieldName' est requis.");
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Define variables
|
||||
$yamlFolder = "data/yaml/";
|
||||
$yamlFolder = __DIR__ . "/data/yaml/";
|
||||
$date = date("Y-m-d");
|
||||
$errors = [];
|
||||
|
||||
// Sanitize input data
|
||||
$auteurice = filter_var($_POST["auteurice"], FILTER_SANITIZE_STRING);
|
||||
$annee = filter_var($_POST["année"], FILTER_SANITIZE_NUMBER_INT);
|
||||
$mail = filter_var($_POST["mail"], FILTER_SANITIZE_EMAIL);
|
||||
$titre = filter_var($_POST["titre"], FILTER_SANITIZE_STRING);
|
||||
$tag = filter_var($_POST["tag"], FILTER_SANITIZE_STRING);
|
||||
$promoteurice = filter_var($_POST["promoteurice"], FILTER_SANITIZE_STRING);
|
||||
$problematique = filter_var($_POST["problématique"], FILTER_SANITIZE_STRING);
|
||||
$description = filter_var($_POST["description"], FILTER_SANITIZE_STRING);
|
||||
$orientation = filter_var($_POST["orientation"], FILTER_SANITIZE_STRING);
|
||||
$ap = filter_var($_POST["ap"], FILTER_SANITIZE_STRING);
|
||||
$lien = filter_var($_POST["lien"], FILTER_SANITIZE_STRING);
|
||||
$couverture = $_FILES["couverture"];
|
||||
$files = $_FILES["files"];
|
||||
try {
|
||||
// Validate and sanitize input data with proper error handling
|
||||
$auteurice = validate_required(sanitize_string($_POST["auteurice"] ?? ''), "Nom/Prénom/Pseudo");
|
||||
|
||||
// Transformation du string de mot-clé en un array.
|
||||
$tagArray = explode(', ', $tag);
|
||||
|
||||
|
||||
$coverFolder = $memoireFolder . "data/cover/";
|
||||
if (!file_exists($coverFolder)) {
|
||||
mkdir($coverFolder, 0755, true);
|
||||
}
|
||||
|
||||
$couverturePath = "";
|
||||
if ($couverture["error"] === UPLOAD_ERR_OK) {
|
||||
$fileExtension = pathinfo($couverture["name"], PATHINFO_EXTENSION);
|
||||
$newCouvertureName = $auteurice . "_" . $annee . "_" . $uniqueId . "." . $fileExtension;
|
||||
$targetFile = $coverFolder . $newCouvertureName;
|
||||
if (move_uploaded_file($couverture["tmp_name"], $targetFile)) {
|
||||
chmod($targetFile, 0644);
|
||||
$couverturePath = $targetFile;
|
||||
} else {
|
||||
error_log("Failed to move uploaded couverture file: " . $couverture["name"]);
|
||||
$annee = filter_var($_POST["année"] ?? '', FILTER_VALIDATE_INT);
|
||||
if ($annee === false || $annee < 2000 || $annee > (int)date('Y') + 1) {
|
||||
throw new Exception("Année invalide. Veuillez entrer une année valide.");
|
||||
}
|
||||
}
|
||||
|
||||
$uploadedFiles = [];
|
||||
$mail = filter_var($_POST["mail"] ?? '', FILTER_VALIDATE_EMAIL);
|
||||
if ($mail === false && !empty($_POST["mail"])) {
|
||||
throw new Exception("Adresse email invalide.");
|
||||
}
|
||||
|
||||
// Create necessary directories
|
||||
$memoireFolder = "data/content/{$annee}/{$auteurice}/";
|
||||
if (!file_exists($yamlFolder)) {
|
||||
mkdir($yamlFolder, 0755, true);
|
||||
}
|
||||
if (!file_exists($memoireFolder)) {
|
||||
mkdir($memoireFolder, 0755, true);
|
||||
}
|
||||
$titre = validate_required(sanitize_string($_POST["titre"] ?? ''), "Titre du mémoire");
|
||||
$tag = sanitize_string($_POST["tag"] ?? '');
|
||||
$promoteurice = sanitize_string($_POST["promoteurice"] ?? '');
|
||||
$problematique = sanitize_string($_POST["problématique"] ?? '');
|
||||
$description = sanitize_string($_POST["description"] ?? '');
|
||||
|
||||
$targetDir = $memoireFolder;
|
||||
$orientation = validate_required(sanitize_string($_POST["orientation"] ?? ''), "Orientation");
|
||||
$ap = validate_required(sanitize_string($_POST["ap"] ?? ''), "Atelier Pratique");
|
||||
|
||||
// Generate unique file name
|
||||
$uniqueId = time() . "_" . rand(1000, 9999);
|
||||
$sanitizedAuteurice = Transliterator::transliterate($auteurice);
|
||||
$uniqueFileName = $sanitizedAuteurice . "_" . $date . "_" . $uniqueId;
|
||||
|
||||
// Define security constraints
|
||||
$allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf', 'video/mp4', 'application/zip'];
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf', 'mp4', 'zip'];
|
||||
$maxFileSize = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
// Process uploaded files
|
||||
if (is_array($files["name"])) {
|
||||
for ($i = 0; $i < count($files["name"]); $i++) {
|
||||
// Log the file being processed
|
||||
error_log("Processing file: " . $files["name"][$i]);
|
||||
// Check for file upload errors
|
||||
if ($files["error"][$i] !== UPLOAD_ERR_OK) {
|
||||
error_log("File upload error: " . $files["name"][$i]);
|
||||
continue;
|
||||
// Validate URL if provided
|
||||
$lien = $_POST["lien"] ?? '';
|
||||
if (!empty($lien)) {
|
||||
$lien = filter_var($lien, FILTER_VALIDATE_URL);
|
||||
if ($lien === false) {
|
||||
throw new Exception("Lien URL invalide.");
|
||||
}
|
||||
}
|
||||
|
||||
// Check MIME type and file extension
|
||||
$couverture = $_FILES["couverture"] ?? null;
|
||||
$files = $_FILES["files"] ?? null;
|
||||
|
||||
// Transformation du string de mot-clé en un array.
|
||||
$tagArray = !empty($tag) ? array_map('trim', explode(',', $tag)) : [];
|
||||
|
||||
// Generate unique identifiers FIRST (before using them)
|
||||
$uniqueId = time() . "_" . rand(1000, 9999);
|
||||
$sanitizedAuteurice = Transliterator::transliterate($auteurice);
|
||||
$uniqueFileName = $sanitizedAuteurice . "_" . $date . "_" . $uniqueId;
|
||||
|
||||
// Create necessary directories
|
||||
$memoireFolder = __DIR__ . "/data/content/{$annee}/{$auteurice}/";
|
||||
$coverFolder = __DIR__ . "/data/cover/";
|
||||
|
||||
if (!file_exists($yamlFolder)) {
|
||||
mkdir($yamlFolder, 0755, true);
|
||||
}
|
||||
if (!file_exists($memoireFolder)) {
|
||||
mkdir($memoireFolder, 0755, true);
|
||||
}
|
||||
if (!file_exists($coverFolder)) {
|
||||
mkdir($coverFolder, 0755, true);
|
||||
}
|
||||
|
||||
$targetDir = $memoireFolder;
|
||||
$uploadedFiles = [];
|
||||
$couverturePath = "";
|
||||
|
||||
// Define security constraints
|
||||
$allowedMimeTypes = ['image/jpeg', 'image/png', 'application/pdf', 'video/mp4', 'application/zip'];
|
||||
$allowedExtensions = ['jpg', 'jpeg', 'png', 'pdf', 'mp4', 'zip'];
|
||||
$maxFileSize = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
// Process cover image first
|
||||
if ($couverture && isset($couverture["error"]) && $couverture["error"] === UPLOAD_ERR_OK) {
|
||||
// Security: validate MIME type
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($files["tmp_name"][$i]);
|
||||
$fileExtension = pathinfo($files["name"][$i], PATHINFO_EXTENSION);
|
||||
$mimeType = $finfo->file($couverture["tmp_name"]);
|
||||
$fileExtension = strtolower(pathinfo($couverture["name"], PATHINFO_EXTENSION));
|
||||
|
||||
if (!in_array($mimeType, $allowedMimeTypes) || !in_array($fileExtension, $allowedExtensions)) {
|
||||
error_log("Invalid file type or extension: " . $files["name"][$i]);
|
||||
continue;
|
||||
}
|
||||
// Only allow image files for cover
|
||||
if (in_array($mimeType, ['image/jpeg', 'image/png']) &&
|
||||
in_array($fileExtension, ['jpg', 'jpeg', 'png'])) {
|
||||
|
||||
// Check file size
|
||||
if ($files["size"][$i] > $maxFileSize) {
|
||||
error_log("File is too large: " . $files["name"][$i]);
|
||||
continue;
|
||||
}
|
||||
// Move and set permissions for the uploaded file
|
||||
$targetFile = $targetDir . basename($files["name"][$i]);
|
||||
if (move_uploaded_file($files["tmp_name"][$i], $targetFile)) {
|
||||
// Log successful file move
|
||||
error_log("File successfully moved: " . $targetFile);
|
||||
chmod($targetFile, 0644);
|
||||
$uploadedFiles[] = $targetFile;
|
||||
// Security: Generate random filename to prevent overwrites and path traversal
|
||||
$randomName = bin2hex(random_bytes(16));
|
||||
$newCouvertureName = $randomName . "." . $fileExtension;
|
||||
$targetFile = $coverFolder . $newCouvertureName;
|
||||
|
||||
if (move_uploaded_file($couverture["tmp_name"], $targetFile)) {
|
||||
chmod($targetFile, 0644);
|
||||
$couverturePath = "data/cover/" . $newCouvertureName;
|
||||
error_log("Cover image uploaded: " . $newCouvertureName);
|
||||
} else {
|
||||
error_log("Failed to move uploaded couverture file: " . $couverture["name"]);
|
||||
}
|
||||
} else {
|
||||
error_log("Failed to move uploaded file: " . $files["name"][$i]);
|
||||
error_log("Invalid cover image type: " . $mimeType);
|
||||
}
|
||||
}
|
||||
|
||||
// Process uploaded files
|
||||
if ($files && is_array($files["name"])) {
|
||||
for ($i = 0; $i < count($files["name"]); $i++) {
|
||||
// Skip if no file was uploaded for this slot
|
||||
if ($files["error"][$i] === UPLOAD_ERR_NO_FILE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Log the file being processed
|
||||
error_log("Processing file: " . $files["name"][$i]);
|
||||
|
||||
// Check for file upload errors
|
||||
if ($files["error"][$i] !== UPLOAD_ERR_OK) {
|
||||
error_log("File upload error code " . $files["error"][$i] . ": " . $files["name"][$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check MIME type and file extension
|
||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||
$mimeType = $finfo->file($files["tmp_name"][$i]);
|
||||
$fileExtension = strtolower(pathinfo($files["name"][$i], PATHINFO_EXTENSION));
|
||||
|
||||
if (!in_array($mimeType, $allowedMimeTypes) || !in_array($fileExtension, $allowedExtensions)) {
|
||||
error_log("Invalid file type or extension: " . $files["name"][$i] . " (MIME: $mimeType, Ext: $fileExtension)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if ($files["size"][$i] > $maxFileSize) {
|
||||
error_log("File is too large: " . $files["name"][$i] . " (" . $files["size"][$i] . " bytes)");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Security: Generate random filename to prevent overwrites and path traversal
|
||||
$randomName = bin2hex(random_bytes(16));
|
||||
$safeFileName = $randomName . "." . $fileExtension;
|
||||
$targetFile = $targetDir . $safeFileName;
|
||||
|
||||
if (move_uploaded_file($files["tmp_name"][$i], $targetFile)) {
|
||||
// Log successful file move
|
||||
error_log("File successfully moved: " . $safeFileName);
|
||||
chmod($targetFile, 0644);
|
||||
$uploadedFiles[] = [
|
||||
'path' => "data/content/{$annee}/{$auteurice}/" . $safeFileName,
|
||||
'original_name' => basename($files["name"][$i]),
|
||||
'size' => $files["size"][$i]
|
||||
];
|
||||
} else {
|
||||
error_log("Failed to move uploaded file: " . $files["name"][$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Prepare form data for YAML
|
||||
$formData = [
|
||||
'auteurice' => $auteurice,
|
||||
'année' => $annee,
|
||||
'email' => $mail ?: '',
|
||||
'titre' => $titre,
|
||||
'tag' => $tagArray,
|
||||
'promoteurice' => $promoteurice,
|
||||
'problématique' => $problematique,
|
||||
'description' => $description, // Fixed: was $resume
|
||||
'orientation' => $orientation,
|
||||
'ap' => $ap,
|
||||
'lien' => $lien,
|
||||
'couverture' => $couverturePath,
|
||||
'files' => $uploadedFiles
|
||||
];
|
||||
|
||||
// Convert form data to YAML
|
||||
$yamlData = Yaml::dump($formData);
|
||||
|
||||
// Save YAML file
|
||||
$yamlFilePath = $yamlFolder . $uniqueFileName . ".yaml";
|
||||
if (file_put_contents($yamlFilePath, $yamlData) === false) {
|
||||
throw new Exception("Erreur lors de l'écriture du fichier YAML.");
|
||||
}
|
||||
|
||||
error_log("Form submission saved: " . $yamlFilePath);
|
||||
|
||||
// Clear CSRF token after successful submission
|
||||
unset($_SESSION['csrf_token']);
|
||||
|
||||
// Redirect to the thank you page
|
||||
header('Location: thanks.php?file=' . urlencode($yamlFilePath));
|
||||
exit();
|
||||
|
||||
} catch (Exception $e) {
|
||||
error_log("Form processing error: " . $e->getMessage());
|
||||
die("Erreur lors du traitement du formulaire : " . htmlspecialchars($e->getMessage()) .
|
||||
"<br><br><a href='index.php'>Retour au formulaire</a>");
|
||||
}
|
||||
|
||||
|
||||
// Prepare form data for YAML
|
||||
$formData = [
|
||||
'auteurice' => $auteurice,
|
||||
'année' => $annee,
|
||||
'email' => $mail,
|
||||
'titre' => $titre,
|
||||
'tag' => $tagArray,
|
||||
'promoteurice' => $promoteurice,
|
||||
'problématique' => $problematique,
|
||||
'description' => $resume,
|
||||
'orientation' => $orientation,
|
||||
'ap' => $ap,
|
||||
'lien' => $lien,
|
||||
'couverture' => $couverturePath,
|
||||
'files' => $uploadedFiles
|
||||
];
|
||||
|
||||
// Convert form data to YAML
|
||||
$yamlData = Yaml::dump($formData);
|
||||
|
||||
// Save YAML file
|
||||
$yamlFilePath = $yamlFolder . $uniqueFileName . ".yaml";
|
||||
file_put_contents($yamlFilePath, $yamlData);
|
||||
|
||||
// Redirect to the thank you page
|
||||
header('Location: thanks.php?file=' . urlencode($yamlFilePath));
|
||||
|
||||
?>
|
||||
Reference in New Issue
Block a user