2025-01-15 15:44:23 +01:00
|
|
|
<?php
|
|
|
|
// Charger la configuration avant tout
|
|
|
|
require_once __DIR__ . '/config.php';
|
|
|
|
|
|
|
|
// Démarrer la session
|
|
|
|
session_name(SESSION_NAME);
|
|
|
|
session_start();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Classe principale de Cyla
|
|
|
|
*/
|
|
|
|
class Cyla {
|
|
|
|
/**
|
|
|
|
* Vérifie si un utilisateur est connecté
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function isLoggedIn() {
|
|
|
|
return isset($_SESSION['user']) && isset($_SESSION['last_activity']) &&
|
|
|
|
(time() - $_SESSION['last_activity']) < SESSION_LIFETIME;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Met à jour le timestamp de dernière activité
|
|
|
|
*/
|
|
|
|
public static function updateActivity() {
|
|
|
|
$_SESSION['last_activity'] = time();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Authentifie un utilisateur
|
|
|
|
* @param string $username Nom d'utilisateur
|
|
|
|
* @param string $password Mot de passe
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function authenticate($username, $password) {
|
|
|
|
global $ADMIN_USERS;
|
|
|
|
|
|
|
|
if (!isset($ADMIN_USERS[$username])) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user = $ADMIN_USERS[$username];
|
|
|
|
$hashed = hash(HASH_ALGO, $password . $user['salt']);
|
|
|
|
|
|
|
|
if ($hashed === $user['password']) {
|
|
|
|
$_SESSION['user'] = $username;
|
|
|
|
self::updateActivity();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Déconnecte l'utilisateur
|
|
|
|
*/
|
|
|
|
public static function logout() {
|
|
|
|
session_destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Génère un nom de fichier unique
|
|
|
|
* @param string $originalName Nom original du fichier
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function generateUniqueFilename($originalName) {
|
|
|
|
$extension = pathinfo($originalName, PATHINFO_EXTENSION);
|
|
|
|
return uniqid() . '_' . time() . '.' . $extension;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Vérifie si un fichier peut être uploadé
|
|
|
|
* @param array $file Informations du fichier ($_FILES)
|
|
|
|
* @return array ['valid' => bool, 'error' => string|null]
|
|
|
|
*/
|
|
|
|
public static function validateUpload($file) {
|
|
|
|
$result = ['valid' => true, 'error' => null];
|
|
|
|
|
|
|
|
// Vérifier les erreurs d'upload PHP
|
|
|
|
if ($file['error'] !== UPLOAD_ERR_OK) {
|
|
|
|
$result['valid'] = false;
|
|
|
|
$result['error'] = 'Erreur lors de l\'upload';
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vérifier la taille
|
|
|
|
if ($file['size'] > MAX_FILE_SIZE) {
|
|
|
|
$result['valid'] = false;
|
|
|
|
$result['error'] = 'Le fichier dépasse la taille maximale autorisée';
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vérifier l'extension
|
|
|
|
$extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
|
|
|
if (!isAllowedExtension($extension)) {
|
|
|
|
$result['valid'] = false;
|
|
|
|
$result['error'] = 'Extension de fichier non autorisée';
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sécurise les sorties HTML
|
|
|
|
* @param string $text Texte à sécuriser
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function escape($text) {
|
|
|
|
return htmlspecialchars($text, ENT_QUOTES, 'UTF-8');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Génère un token CSRF
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public static function generateCSRFToken() {
|
|
|
|
if (!isset($_SESSION['csrf_token'])) {
|
|
|
|
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
|
|
|
|
}
|
|
|
|
return $_SESSION['csrf_token'];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Vérifie un token CSRF
|
|
|
|
* @param string $token Token à vérifier
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function verifyCSRFToken($token) {
|
|
|
|
return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-01-15 18:02:24 +01:00
|
|
|
* Liste les fichiers uploadés avec pagination
|
|
|
|
* @param int $page Numéro de la page (commence à 1)
|
|
|
|
* @param int $perPage Nombre d'éléments par page
|
|
|
|
* @return array ['files' => array, 'total' => int, 'totalPages' => int]
|
2025-01-15 15:44:23 +01:00
|
|
|
*/
|
2025-01-15 18:02:24 +01:00
|
|
|
public static function listFiles($page = 1, $perPage = 20) {
|
2025-01-15 15:44:23 +01:00
|
|
|
$files = [];
|
2025-01-15 18:02:24 +01:00
|
|
|
$allFiles = glob(UPLOAD_DIR . '*');
|
|
|
|
|
|
|
|
// Trier les fichiers par date de modification (plus récent en premier)
|
|
|
|
usort($allFiles, function($a, $b) {
|
|
|
|
return filemtime($b) - filemtime($a);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Calculer la pagination
|
|
|
|
$total = count($allFiles);
|
|
|
|
$totalPages = ceil($total / $perPage);
|
|
|
|
$page = max(1, min($page, $totalPages)); // Garantir que la page est dans les limites
|
|
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
|
|
|
|
// Récupérer uniquement les fichiers de la page courante
|
|
|
|
$pageFiles = array_slice($allFiles, $offset, $perPage);
|
|
|
|
|
|
|
|
foreach ($pageFiles as $file) {
|
2025-01-15 15:44:23 +01:00
|
|
|
$info = pathinfo($file);
|
|
|
|
$files[] = [
|
|
|
|
'name' => basename($file),
|
|
|
|
'size' => filesize($file),
|
|
|
|
'extension' => strtolower($info['extension']),
|
|
|
|
'uploaded' => filemtime($file),
|
|
|
|
'preview_type' => getPreviewType($info['extension'])
|
|
|
|
];
|
|
|
|
}
|
2025-01-15 18:02:24 +01:00
|
|
|
|
|
|
|
return [
|
|
|
|
'files' => $files,
|
|
|
|
'total' => $total,
|
|
|
|
'totalPages' => $totalPages,
|
|
|
|
'currentPage' => $page,
|
|
|
|
'perPage' => $perPage
|
|
|
|
];
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Supprime un fichier
|
|
|
|
* @param string $filename Nom du fichier à supprimer
|
|
|
|
* @return array ['success' => bool, 'error' => string|null]
|
|
|
|
*/
|
|
|
|
public static function deleteFile($filename) {
|
|
|
|
$filepath = UPLOAD_DIR . $filename;
|
|
|
|
|
|
|
|
// Vérifier que le fichier existe et est dans le dossier d'upload
|
|
|
|
if (!file_exists($filepath) || !is_file($filepath)) {
|
|
|
|
return ['success' => false, 'error' => 'Fichier introuvable'];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vérifier que le fichier est bien dans le dossier d'upload
|
|
|
|
$realpath = realpath($filepath);
|
|
|
|
$uploadDir = realpath(UPLOAD_DIR);
|
|
|
|
if (strpos($realpath, $uploadDir) !== 0) {
|
|
|
|
return ['success' => false, 'error' => 'Chemin de fichier non autorisé'];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Supprimer le fichier
|
|
|
|
if (unlink($filepath)) {
|
|
|
|
return ['success' => true];
|
|
|
|
} else {
|
|
|
|
return ['success' => false, 'error' => 'Erreur lors de la suppression du fichier'];
|
|
|
|
}
|
2025-01-15 15:44:23 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vérifier et mettre à jour l'activité si l'utilisateur est connecté
|
|
|
|
if (Cyla::isLoggedIn()) {
|
|
|
|
Cyla::updateActivity();
|
|
|
|
}
|