diff --git a/core/class/jsondb/JsonDb.class.php b/core/class/jsondb/JsonDb.class.php index 29d932a3..cff3bf40 100644 --- a/core/class/jsondb/JsonDb.class.php +++ b/core/class/jsondb/JsonDb.class.php @@ -18,6 +18,12 @@ class JsonDb extends \Prowebcraft\Dot protected $db = ''; protected $data = null; protected $config = []; +// Tentative d'encodage après échec + const MAX_JSON_ENCODE_ATTEMPTS = 5; +// 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 = []) { @@ -121,17 +127,17 @@ class JsonDb extends \Prowebcraft\Dot } else { if ($this->config['backup']) { try { - //todo make backup of database copy($this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'], $this->config['dir'] . DIRECTORY_SEPARATOR . $this->config['name'] . '.backup'); } catch (\Exception $e) { - + error_log('Erreur de chargement : ' . $e); + exit('Erreur de chargement : ' . $e); } } } $this->data = json_decode(file_get_contents($this->db), true); - if (!$this->data === null && json_last_error() !== JSON_ERROR_NONE) { - throw new \InvalidArgumentException('Le fichier ' . $this->db - . ' contient des données invalides.'); + if (!$this->data === null) { + throw new \InvalidArgumentException('Database file ' . $this->db + . ' contains invalid json object. Please validate or remove file'); } } return $this->data; @@ -142,25 +148,53 @@ class JsonDb extends \Prowebcraft\Dot */ public function save() { - $v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT); - // $v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT); - $l = strlen($v); - $t = 0; - if ($v === false) { - error_log('Erreur d\'encodage JSON : ' . json_last_error_msg()); - exit ('Erreur d\'encodage JSON : ' . json_last_error_msg()); - } - while ($t < 5) { - $w = file_put_contents($this->db, $v); // Multi user get a locker - if ($w == $l) { - break; + $jsonOptions = JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_FORCE_OBJECT; + $jsonData = json_encode($this->data, $jsonOptions); + + $attempts = 0; + while ($attempts < self::MAX_JSON_ENCODE_ATTEMPTS) { + if ($jsonData !== false) { + break; // Sortir de la boucle si l'encodage réussit } - $t++; - } - if ($w !== $l) { - error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); - exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); + $attempts++; + error_log('Erreur d\'encodage JSON (tentative ' . $attempts . ') : ' . json_last_error_msg()); + $jsonData = json_encode($this->data, $jsonOptions); // Réessayer l'encodage + sleep(self::RETRY_DELAY_SECONDS); // Attendre avant de réessayer } + if ($jsonData === false) { + error_log('Impossible d\'encoder les données en format JSON.'); + return false; + } + + $lockFile = $this->db . '.lock'; + $lockHandle = fopen($lockFile, 'w'); + + if (flock($lockHandle, LOCK_EX)) { + $attempts = 0; + $bytesWritten = false; + while ($attempts < self::MAX_FILE_WRITE_ATTEMPTS && $bytesWritten === false) { + $bytesWritten = file_put_contents($this->db, $jsonData); + if ($bytesWritten === false) { + $attempts++; + error_log('Erreur d\'écriture (tentative ' . $attempts . ') : impossible de sauvegarder les données.'); + sleep(self::RETRY_DELAY_SECONDS); // Attendre avant de réessayer + } + } + flock($lockHandle, LOCK_UN); + fclose($lockHandle); + + if ($bytesWritten === false || $bytesWritten != strlen($jsonData)) { + error_log('Erreur d\'écriture, les données n\'ont pas été sauvegardées.'); + return false; + } + } else { + error_log('Impossible d\'obtenir un verrouillage sur le fichier de base de données.'); + fclose($lockHandle); + return false; + } + + return true; } + } \ No newline at end of file