Merge commit '0f55df8d31a7093f83c2ee4510a1d27bb9a087ac'

This commit is contained in:
Fred Tempez 2024-04-09 18:14:16 +02:00
commit 2027c5918f
5 changed files with 186 additions and 87 deletions

View File

@ -142,25 +142,38 @@ class JsonDb extends \Prowebcraft\Dot
*/ */
public function save() public function save()
{ {
$v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT); // Encode les données au format JSON avec les options spécifiées
// $v = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT); $encoded_data = json_encode($this->data, JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT | JSON_PRETTY_PRINT);
$l = strlen($v);
$t = 0; // Vérifie la longueur de la chaîne JSON encodée
if ($v === false) { $encoded_length = strlen($encoded_data);
error_log('Erreur d\'encodage JSON : ' . json_last_error_msg());
exit ('Erreur d\'encodage JSON : ' . json_last_error_msg()); // Initialise le compteur de tentatives
} $attempt = 0;
while ($t < 5) {
$w = file_put_contents($this->db, $v); // Multi user get a locker // Tente d'encoder les données en JSON et de les sauvegarder jusqu'à 5 fois en cas d'échec
if ($w == $l) { while ($attempt < 5) {
// 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
// Vérifie si l'écriture a réussi
if ($write_result === $encoded_length) {
// Sort de la boucle si l'écriture a réussi
break; break;
} }
$t++;
} // Incrémente le compteur de tentatives
if ($w !== $l) { $attempt++;
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.');
} }
// 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.');
// Affiche un message d'erreur et termine le script
exit('Erreur d\'écriture, les données n\'ont pas été sauvegardées.');
} }
}
} }

View File

@ -446,7 +446,7 @@ class common
} }
// Mise à jour des données core // Mise à jour des données core
include('core/include/update.inc.php'); include ('core/include/update.inc.php');
} }
@ -594,7 +594,7 @@ class common
public function setPage($page, $value, $path) public function setPage($page, $value, $path)
{ {
return file_put_contents(self::DATA_DIR . $path . '/content/' . $page . '.html', $value); return $this->secure_file_put_contents(self::DATA_DIR . $path . '/content/' . $page . '.html', $value);
} }
@ -610,6 +610,92 @@ class common
} }
/**
* Écrit les données dans un fichier avec plusieurs tentatives d'écriture et verrouillage
*
* @param string $filename Le nom du fichier
* @param string $data Les données à écrire dans le fichier
* @param int $flags Les drapeaux optionnels à passer à la fonction $this->secure_file_put_contents
* @return bool True si l'écriture a réussi, sinon false
*/
function secure_file_put_contents($filename, $data, $flags = 0)
{
// Vérifie si le fichier existe
if (!file_exists($filename)) {
// Crée le fichier s'il n'existe pas
$handle = fopen($filename, 'w');
fclose($handle);
}
// Initialise le compteur de tentatives
$attempts = 0;
// Vérifie la longueur des données
$data_length = strlen($data);
// Effectue jusqu'à 5 tentatives d'écriture
while ($attempts < 5) {
// Essaye d'écrire les données dans le fichier avec verrouillage exclusif
$write_result = $this->secure_file_put_contents($filename, $data, LOCK_EX | $flags);
// Vérifie si l'écriture a réussi
if ($write_result !== false && $write_result === $data_length) {
// Sort de la boucle si l'écriture a réussi
return true;
}
// Incrémente le compteur de tentatives
$attempts++;
}
// Échec de l'écriture après plusieurs tentatives
return false;
}
/**
* Écrit les données dans un fichier avec plusieurs tentatives d'écriture et verrouillage
*
* @param string $filename Le nom du fichier
* @param string $data Les données à écrire dans le fichier
* @param int $flags Les drapeaux optionnels à passer à la fonction $this->secure_file_put_contents
* @return bool True si l'écriture a réussi, sinon false
*/
function secure_file_put_contents($filename, $data, $flags = 0)
{
// Vérifie si le fichier existe
if (!file_exists($filename)) {
// Crée le fichier s'il n'existe pas
$handle = fopen($filename, 'w');
fclose($handle);
}
// Initialise le compteur de tentatives
$attempts = 0;
// Vérifie la longueur des données
$data_length = strlen($data);
// Effectue jusqu'à 5 tentatives d'écriture
while ($attempts < 5) {
// Essaye d'écrire les données dans le fichier avec verrouillage exclusif
$write_result = $this->secure_file_put_contents($filename, $data, LOCK_EX | $flags);
// Vérifie si l'écriture a réussi
if ($write_result !== false && $write_result === $data_length) {
// Sort de la boucle si l'écriture a réussi
return true;
}
// Incrémente le compteur de tentatives
$attempts++;
}
// Échec de l'écriture après plusieurs tentatives
return false;
}
public function initDB($module, $path) public function initDB($module, $path)
{ {
// Instanciation de la classe des entrées / sorties // Instanciation de la classe des entrées / sorties
@ -632,7 +718,7 @@ class common
{ {
// Tableau avec les données vierges // Tableau avec les données vierges
require_once('core/module/install/ressource/defaultdata.php'); require_once ('core/module/install/ressource/defaultdata.php');
// L'arborescence // L'arborescence
if (!file_exists(self::DATA_DIR . $path)) { if (!file_exists(self::DATA_DIR . $path)) {
@ -667,7 +753,7 @@ class common
public function saveConfig($module) public function saveConfig($module)
{ {
// Tableau avec les données vierges // Tableau avec les données vierges
require_once('core/module/install/ressource/defaultdata.php'); require_once ('core/module/install/ressource/defaultdata.php');
// Installation des données des autres modules cad theme profil font config, admin et core // Installation des données des autres modules cad theme profil font config, admin et core
$this->setData([$module, init::$defaultData[$module]]); $this->setData([$module, init::$defaultData[$module]]);
common::$coreNotices[] = $module; common::$coreNotices[] = $module;
@ -1434,7 +1520,7 @@ class common
// Affiche les espaces gérés par l'éditeur, les espaces où il participe et les espaces anonymes // Affiche les espaces gérés par l'éditeur, les espaces où il participe et les espaces anonymes
if ( if (
// le membre est inscrit // le membre est inscrit
( $this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])) ) ($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])))
// Il est l'auteur // Il est l'auteur
|| $this->getUser('id') === $this->getData(['course', $courseId, 'author']) || $this->getUser('id') === $this->getData(['course', $courseId, 'author'])
// Le cours est ouvert // Le cours est ouvert
@ -1448,7 +1534,7 @@ class common
foreach ($courses as $courseId => $value) { foreach ($courses as $courseId => $value) {
// Affiche les espaces du participant et les espaces anonymes // Affiche les espaces du participant et les espaces anonymes
if ( if (
($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])) ) ($this->getData(['enrolment', $courseId]) && array_key_exists($this->getUser('id'), $this->getData(['enrolment', $courseId])))
|| $this->getData(['course', $courseId, 'enrolment']) === self::COURSE_ENROLMENT_GUEST || $this->getData(['course', $courseId, 'enrolment']) === self::COURSE_ENROLMENT_GUEST
) { ) {
$filter[$courseId] = $courses[$courseId]; $filter[$courseId] = $courses[$courseId];

View File

@ -1597,17 +1597,17 @@ class course extends common
// Participants avec historiques // Participants avec historiques
$enrolment = $this->getData(['enrolment', $courseId]); $enrolment = $this->getData(['enrolment', $courseId]);
// Générer un fichier dans le dossier de l'espace // Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/enrolment.json', json_encode([$courseId => $enrolment], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $this->secure_file_put_contents(self::DATA_DIR . $courseId . '/enrolment.json', json_encode([$courseId => $enrolment], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Idem pour les données du cours // Idem pour les données du cours
$course = $this->getData(['course', $courseId]); $course = $this->getData(['course', $courseId]);
// Générer un fichier dans le dossier de l'espace // Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/course.json', json_encode([$courseId => $course], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $this->secure_file_put_contents(self::DATA_DIR . $courseId . '/course.json', json_encode([$courseId => $course], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Idem pour la catégorie // Idem pour la catégorie
$category = $this->getData(['category', $this->getData(['course', $courseId, 'category'])]); $category = $this->getData(['category', $this->getData(['course', $courseId, 'category'])]);
// Générer un fichier dans le dossier de l'espace // Générer un fichier dans le dossier de l'espace
file_put_contents(self::DATA_DIR . $courseId . '/category.json', json_encode([$this->getData(['course', $courseId, 'category']) => $category], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $this->secure_file_put_contents(self::DATA_DIR . $courseId . '/category.json', json_encode([$this->getData(['course', $courseId, 'category']) => $category], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
// Génère une archive ZIP // Génère une archive ZIP

View File

@ -387,7 +387,7 @@ class install extends common
'</IfModule>' . PHP_EOL . '</IfModule>' . PHP_EOL .
'# URL rewriting' . PHP_EOL; '# URL rewriting' . PHP_EOL;
$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent); $fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
$success = file_put_contents( $success = $this->secure_file_put_contents(
'.htaccess', '.htaccess',
$fileContent $fileContent
); );

View File

@ -99,7 +99,7 @@ class language extends common
is_array($descripteur['language'][$lang]) is_array($descripteur['language'][$lang])
) { ) {
if ($this->setData(['language', $lang, $descripteur['language'][$lang]])) { if ($this->setData(['language', $lang, $descripteur['language'][$lang]])) {
$success = file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($languageData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)); $success = $this->secure_file_put_contents(self::I18N_DIR . $lang . '.json', json_encode($languageData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
$success = is_int($success) ? true : false; $success = is_int($success) ? true : false;
} }
} }