diff --git a/core/class/jsondb/JsonDb.class.php b/core/class/jsondb/JsonDb.class.php index fa7fbc9..20fe2d4 100644 --- a/core/class/jsondb/JsonDb.class.php +++ b/core/class/jsondb/JsonDb.class.php @@ -18,6 +18,10 @@ class JsonDb extends \Prowebcraft\Dot protected $db = ''; protected $data = null; protected $config = []; + // Tentative d'écriture après échec + const MAX_FILE_WRITE_ATTEMPTS = 5; + // Délais entre deux tentaives + const RETRY_DELAY_SECONDS = 1; public function __construct($config = []) { @@ -129,9 +133,9 @@ class JsonDb extends \Prowebcraft\Dot } } $this->data = json_decode(file_get_contents($this->db), true); - if (!$this->data === null && json_last_error() !== JSON_ERROR_NONE) { + if (!$this->data === null) { throw new \InvalidArgumentException('Le fichier ' . $this->db - . ' contient des données invalides.'); + . ' contient des données invalides.'); } } return $this->data; @@ -143,6 +147,7 @@ class JsonDb extends \Prowebcraft\Dot public function save() { // Encode les données au format JSON avec les options spécifiées + //$encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT); $encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT); // Vérifie la longueur de la chaîne JSON encodée @@ -156,24 +161,29 @@ class JsonDb extends \Prowebcraft\Dot // Essaye d'écrire les données encodées dans le fichier de base de données $write_result = file_put_contents($this->db, $encoded_data, LOCK_EX); // Les utilisateurs multiples obtiennent un verrou - // $now = \DateTime::createFromFormat('U.u', microtime(true)); - // file_put_contents("tmplog.txt", '[JsonDb][' . $now->format('H:i:s.u') . ']--' . $this->db . "\r\n", FILE_APPEND); - + //$now = \DateTime::createFromFormat('U.u', microtime(true)); + //file_put_contents("tmplog.txt", '[JsonDb][' . $now->format('H:i:s.u') . ']--' . $this->db . "\r\n", FILE_APPEND); + // Vérifie si l'écriture a réussi if ($write_result === $encoded_length) { // Sort de la boucle si l'écriture a réussi break; } + // Incrémente le compteur de tentatives $attempt++; + + // Attente 1/4 de seconde + usleep(0.25); } + // Vérifie si l'écriture a échoué même après plusieurs tentatives if ($write_result !== $encoded_length) { // Enregistre un message d'erreur dans le journal des erreurs - error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); + error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); + // Affiche un message d'erreur et termine le script exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); } } - } \ No newline at end of file diff --git a/core/core.php b/core/core.php index 8fbde6c..aabc146 100644 --- a/core/core.php +++ b/core/core.php @@ -72,6 +72,9 @@ class common const COURSE_ENROLMENT_SELF_KEY = 2; // Ouvert à tous les membres disposant de la clé const COURSE_ENROLMENT_MANDATORY = 3; + // Taille et rotation des journaux + const LOG_MAXSIZE = 4 * 1024 * 1024; + const LOG_MAXARCHIVE = 5; public static $actions = []; public static $coreModuleIds = [ @@ -589,7 +592,7 @@ class common $query .= '.' . $keys[$i]; } // Appliquer la modification, le dernier élément étant la donnée à sauvegarder - $success = $db->set($query, $keys[count($keys) - 1], $save); + $success = $db->set($query, $keys[count($keys) - 1], $save); } return $success; } @@ -723,7 +726,7 @@ class common public function saveDB($module): void { $db = (object) $this->dataFiles[$module]; - $db->save(); + $db->save(); } @@ -1514,18 +1517,67 @@ class common } /** - * Journalisation + * Journalisation avec gestion de la taille maximale et compression */ public function saveLog($message = '') { - // Journalisation - $dataLog = helper::dateUTF8('%Y%m%d', time(), self::$i18nUI) . ';' . helper::dateUTF8('%H:%M', time(), self::$i18nUI) . ';'; + // Chemin du fichier journal + $logFile = self::DATA_DIR . 'journal.log'; + + // Vérifier la taille du fichier + if (file_exists($logFile) && filesize($logFile) > self::LOG_MAXSIZE) { + $this->rotateLogFile(); + } + + // Création de l'entrée de journal + $dataLog = helper::dateUTF8('%Y%m%d', time(), self::$i18nUI) . ';' . + helper::dateUTF8('%H:%M', time(), self::$i18nUI) . ';'; $dataLog .= helper::getIp($this->getData(['config', 'connect', 'anonymousIp'])) . ';'; $dataLog .= empty($this->getUser('id')) ? 'visitor;' : $this->getUser('id') . ';'; $dataLog .= $message ? $this->getUrl() . ';' . $message : $this->getUrl(); $dataLog .= PHP_EOL; + + // Écriture dans le fichier si la journalisation est activée if ($this->getData(['config', 'connect', 'log'])) { - file_put_contents(self::DATA_DIR . 'journal.log', $dataLog, FILE_APPEND); + file_put_contents($logFile, $dataLog, FILE_APPEND); + } + } + + /** + * Gère la rotation et la compression des fichiers journaux + */ + private function rotateLogFile() + { + $logFile = self::DATA_DIR . 'journal.log'; + + // Décaler tous les fichiers d'archive existants + for ($i = self::LOG_MAXARCHIVE - 1; $i > 0; $i--) { + $oldFile = self::DATA_DIR . 'journal-' . $i . '.log.gz'; + $newFile = self::DATA_DIR . 'journal-' . ($i + 1) . '.log.gz'; + + if (file_exists($oldFile)) { + if ($i == self::LOG_MAXARCHIVE - 1) { + unlink($oldFile); // Supprimer le plus ancien + } else { + rename($oldFile, $newFile); + } + } + } + + // Compresser le fichier journal actuel + if (file_exists($logFile)) { + $gz = gzopen(self::DATA_DIR . 'journal-1.log.gz', 'w9'); + $handle = fopen($logFile, 'r'); + + while (!feof($handle)) { + gzwrite($gz, fread($handle, 8192)); + } + + fclose($handle); + gzclose($gz); + + // Créer un nouveau fichier journal vide + file_put_contents($logFile, ''); } } @@ -1535,9 +1587,9 @@ class common * Retourne les contenus d'un utilisateur * @param string $userId identifiant * @param string $serStatus teacher ou student ou admin - * + * @return array * CETTE FONCTION EST UTILISEE PAR LAYOUT - * + * */ public function getCoursesByProfil() {