This commit is contained in:
Fred Tempez 2024-09-28 13:24:55 +02:00
parent 8dc1adc28a
commit dc81614114
5 changed files with 101 additions and 77 deletions

View File

@ -156,21 +156,21 @@ class JsonDb extends \Prowebcraft\Dot
// Essaye d'écrire les données encodées dans le fichier de base de données // 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 $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);
// Vérifie si l'écriture a réussi // Vérifie si l'écriture a réussi
if ($write_result === $encoded_length) { if ($write_result === $encoded_length) {
// Sort de la boucle si l'écriture a réussi // Sort de la boucle si l'écriture a réussi
break; break;
} }
// Incrémente le compteur de tentatives // Incrémente le compteur de tentatives
$attempt++; $attempt++;
} }
// Vérifie si l'écriture a échoué même après plusieurs tentatives // Vérifie si l'écriture a échoué même après plusieurs tentatives
if ($write_result !== $encoded_length) { if ($write_result !== $encoded_length) {
// Enregistre un message d'erreur dans le journal des erreurs // 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 // Affiche un message d'erreur et termine le script
exit('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.');
} }

View File

@ -423,7 +423,7 @@ class core extends common
) )
) { ) {
// Stocke la dernière page vue et sa date de consultation // Stocke la dernière page vue et sa date de consultation
$this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'lastPageView', $this->getUrl(0)]); $this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'lastPageView', $this->getUrl(0)], false);
$this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'datePageView', time()]); $this->setData(['enrolment', common::$siteContent, $this->getUser('id'), 'datePageView', time()]);
// Stocke le rapport en CSV // Stocke le rapport en CSV
@ -541,7 +541,7 @@ class core extends common
$this->isConnected() === true $this->isConnected() === true
&& $this->getUser('id') && $this->getUser('id')
) { ) {
$this->setData(['user', $this->getUser('id'), 'accessUrl', $this->getUrl()]); $this->setData(['user', $this->getUser('id'), 'accessUrl', $this->getUrl()], false);
$this->setData(['user', $this->getUser('id'), 'accessTimer', time()]); $this->setData(['user', $this->getUser('id'), 'accessTimer', time()]);
} }
// Breadcrumb // Breadcrumb

View File

@ -51,7 +51,7 @@ class common
const ACCESS_TIMER = 1800; const ACCESS_TIMER = 1800;
// Numéro de version // Numéro de version
const ZWII_VERSION = '1.12.00.15'; const ZWII_VERSION = '1.13.00';
// URL autoupdate // URL autoupdate
const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/'; const ZWII_UPDATE_URL = 'https://forge.chapril.org/ZwiiCMS-Team/campus-update/raw/branch/master/';
@ -511,43 +511,46 @@ class common
return is_object($success); return is_object($success);
} }
/** /**
* Sauvegarde des données * Sauvegarde des données
* @param array $keys Clé(s) des données * @param array $keys Clé(s) des données
*/ * @param bool $save Indique si le fichier doit être sauvegardé après modification (par défaut true)
public function setData($keys = []) * @return bool Succès de l'opération
{ */
// Pas d'enregistrement lorsqu'une notice est présente ou tableau transmis vide public function setData($keys = [], $save = true)
if ( {
!empty(self::$inputNotices) // Pas d'enregistrement lorsqu'une notice est présente ou tableau transmis vide
or empty($keys) if (
) { !empty(self::$inputNotices)
return false; or empty($keys)
} ) {
return false;
// Empêcher la sauvegarde d'une donnée nulle.
if (gettype($keys[count($keys) - 1]) === NULL) {
return false;
}
// Initialisation du retour en cas d'erreur de descripteur
$success = false;
// Construire la requête dans la base inf à 1 retourner toute la base
if (count($keys) >= 1) {
// Descripteur de la base
$db = $this->dataFiles[$keys[0]];
$query = $keys[0];
// Construire la requête
// Ne pas tenir compte du dernier élément qui une une value donc <
for ($i = 1; $i < count($keys) - 1; $i++) {
$query .= '.' . $keys[$i];
}
// Appliquer la modification, le dernier élément étant la donnée à sauvegarder
$success = is_object($db->set($query, $keys[count($keys) - 1], true));
}
return $success;
} }
// Empêcher la sauvegarde d'une donnée nulle.
if (gettype($keys[count($keys) - 1]) === NULL) {
return false;
}
// Initialisation du retour en cas d'erreur de descripteur
$success = false;
// Construire la requête dans la base inf à 1 retourner toute la base
if (count($keys) >= 1) {
// Descripteur de la base
$db = $this->dataFiles[$keys[0]];
$query = $keys[0];
// Construire la requête
// Ne pas tenir compte du dernier élément qui une une value donc <
for ($i = 1; $i < count($keys) - 1; $i++) {
$query .= '.' . $keys[$i];
}
// Appliquer la modification, le dernier élément étant la donnée à sauvegarder
$success = is_object($db->set($query, $keys[count($keys) - 1], $save));
}
return $success;
}
/** /**
* Accède aux données * Accède aux données
* @param array $keys Clé(s) des données * @param array $keys Clé(s) des données
@ -656,15 +659,32 @@ class common
public function initDB($module, $path = '') public function initDB($module, $path = '')
{ {
// Instanciation de la classe des entrées / sorties // Chemin complet vers le fichier JSON
// Constructeur JsonDB; $dir = empty($path) ? self::DATA_DIR : self::DATA_DIR . $path . '/';
$this->dataFiles[$module] = new \Prowebcraft\JsonDb([ $config = [
'name' => $module . '.json', 'name' => $module . '.json',
'dir' => empty($path) ? self::DATA_DIR : self::DATA_DIR . $path . '/', 'dir' => $dir,
'backup' => file_exists('site/data/.backup') 'backup' => file_exists('site/data/.backup'),
]); 'update' => false,
];
// Instanciation de l'objet et stockage dans dataFiles
$this->dataFiles[$module] = new \Prowebcraft\JsonDb($config);
} }
/**
* Cette fonction est liée à saveData
* @param mixed $module
* @return void
*/
public function saveDB($module): void
{
$db = $this->dataFiles[$module];
$db->save();
}
/** /**
* Initialisation des données sur un contenu ou la page d'accueil * Initialisation des données sur un contenu ou la page d'accueil

View File

@ -798,9 +798,11 @@ class course extends common
$this->getData(['user', $keyPost]) !== null $this->getData(['user', $keyPost]) !== null
&& $this->getData(['enrolment', $courseId, $keyPost]) === null && $this->getData(['enrolment', $courseId, $keyPost]) === null
) { ) {
$this->setData(['enrolment', $courseId, $keyPost, 'history', array()]); $this->setData(['enrolment', $courseId, $keyPost, 'history', array()], false);
} }
} }
// Sauvegarde la base manuellement
$this->saveDB('enrolment');
} }
// Liste des groupes et des profils // Liste des groupes et des profils
@ -1154,11 +1156,6 @@ class course extends common
? helper::baseUrl() . $this->getData(['enrolment', $courseId, $userId, 'lastPageView']) ? helper::baseUrl() . $this->getData(['enrolment', $courseId, $userId, 'lastPageView'])
: helper::baseUrl(); : helper::baseUrl();
/*
$essage = $this->getData(['enrolment', $courseId, $userId, 'datePageView'])
? $this->getData(['enrolment', $courseId, $userId, 'datePageView'])
: '';
*/
if ($this->getData(['course', $courseId, 'access']) === self::COURSE_ACCESS_DATE) { if ($this->getData(['course', $courseId, 'access']) === self::COURSE_ACCESS_DATE) {
$to = helper::dateUTF8('%d %B %Y', $this->getData(['course', $courseId, 'closingDate']), self::$i18nUI) . helper::translate(' à ') . helper::dateUTF8('%H:%M', $this->getData(['course', $courseId, 'closingDate']), self::$i18nUI); $to = helper::dateUTF8('%d %B %Y', $this->getData(['course', $courseId, 'closingDate']), self::$i18nUI) . helper::translate(' à ') . helper::dateUTF8('%H:%M', $this->getData(['course', $courseId, 'closingDate']), self::$i18nUI);
$message .= sprintf(helper::translate('Ce contenu ferme le %s'), $to); $message .= sprintf(helper::translate('Ce contenu ferme le %s'), $to);
@ -1390,7 +1387,7 @@ class course extends common
if (!empty($userValue['history'])) { if (!empty($userValue['history'])) {
$maxTime = max($userValue['history']); $maxTime = max($userValue['history']);
$lastPageId = array_search($maxTime, $userValue['history']); $lastPageId = array_search($maxTime, $userValue['history']);
$this->setData(['enrolment', $courseId, $userId, 'lastPageView', $lastPageId]); $this->setData(['enrolment', $courseId, $userId, 'lastPageView', $lastPageId], false);
$this->setData(['enrolment', $courseId, $userId, 'datePageView', $maxTime]); $this->setData(['enrolment', $courseId, $userId, 'datePageView', $maxTime]);
} }
} }

View File

@ -428,7 +428,8 @@ class user extends common
if ($this->getUser('group') < self::GROUP_ADMIN) { if ($this->getUser('group') < self::GROUP_ADMIN) {
if ($this->getInput('userEditNewPassword')) { if ($this->getInput('userEditNewPassword')) {
// L'ancien mot de passe est correct // L'ancien mot de passe est correct
if (password_verify(html_entity_decode($this->getInput('userEditOldPassword')), $this->getData(['user', $this->getUrl(2), 'password'])) if (
password_verify(html_entity_decode($this->getInput('userEditOldPassword')), $this->getData(['user', $this->getUrl(2), 'password']))
) { ) {
// La confirmation correspond au mot de passe // La confirmation correspond au mot de passe
if ($this->getInput('userEditNewPassword') === $this->getInput('userEditConfirmPassword')) { if ($this->getInput('userEditNewPassword') === $this->getInput('userEditConfirmPassword')) {
@ -1149,12 +1150,12 @@ class user extends common
// Exclure les espaces des cours // Exclure les espaces des cours
/* /*
foreach (array_keys($this->getData(['course'])) as $courseId) { foreach (array_keys($this->getData(['course'])) as $courseId) {
self::$sharePath = array_filter(self::$sharePath, function ($key) use ($courseId) { self::$sharePath = array_filter(self::$sharePath, function ($key) use ($courseId) {
return strpos($key, $courseId) === false; return strpos($key, $courseId) === false;
}); });
} }
*/ */
self::$sharePath = array_flip(self::$sharePath); self::$sharePath = array_flip(self::$sharePath);
self::$sharePath = array_merge(['none' => 'Aucun Accès'], self::$sharePath); self::$sharePath = array_merge(['none' => 'Aucun Accès'], self::$sharePath);
@ -1261,7 +1262,7 @@ class user extends common
'lastFail' => time(), 'lastFail' => time(),
'ip' => helper::getIp() 'ip' => helper::getIp()
] ]
]); ], false);
// Verrouillage des IP // Verrouillage des IP
$ipBlackList = helper::arrayColumn($this->getData(['blacklist']), 'ip'); $ipBlackList = helper::arrayColumn($this->getData(['blacklist']), 'ip');
if ( if (
@ -1290,8 +1291,8 @@ class user extends common
$this->getData(['user', $userId, 'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) < time() $this->getData(['user', $userId, 'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) < time()
and $this->getData(['user', $userId, 'connectFail']) === $this->getData(['config', 'connect', 'attempt']) and $this->getData(['user', $userId, 'connectFail']) === $this->getData(['config', 'connect', 'attempt'])
) { ) {
$this->setData(['user', $userId, 'connectFail', 0]); $this->setData(['user', $userId, 'connectFail', 0], false);
$this->setData(['user', $userId, 'connectTimeout', 0]); $this->setData(['user', $userId, 'connectTimeout', 0], false);
} }
// Check la présence des variables et contrôle du blocage du compte si valeurs dépassées // Check la présence des variables et contrôle du blocage du compte si valeurs dépassées
// Vérification du mot de passe et du groupe // Vérification du mot de passe et du groupe
@ -1303,12 +1304,12 @@ class user extends common
and $captcha === true and $captcha === true
) { ) {
// RAZ // RAZ
$this->setData(['user', $userId, 'connectFail', 0]); $this->setData(['user', $userId, 'connectFail', 0], false);
$this->setData(['user', $userId, 'connectTimeout', 0]); $this->setData(['user', $userId, 'connectTimeout', 0], false);
// Clé d'authenfication // Clé d'authenfication
$authKey = uniqid('', true) . bin2hex(random_bytes(8)); $authKey = uniqid('', true) . bin2hex(random_bytes(8));
$this->setData(['user', $userId, 'authKey', $authKey]); $this->setData(['user', $userId, 'authKey', $authKey], false);
// Validité du cookie // Validité du cookie
$expire = $this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN) === true ? strtotime("+1 year") : 0; $expire = $this->getInput('userLoginLongTime', helper::FILTER_BOOLEAN) === true ? strtotime("+1 year") : 0;
@ -1332,7 +1333,7 @@ class user extends common
} }
// Accès multiples avec le même compte // Accès multiples avec le même compte
$this->setData(['user', $userId, 'accessCsrf', $_SESSION['csrf']]); $this->setData(['user', $userId, 'accessCsrf', $_SESSION['csrf']], false);
// Valeurs en sortie lorsque le site est en maintenance et que l'utilisateur n'est pas administrateur // Valeurs en sortie lorsque le site est en maintenance et que l'utilisateur n'est pas administrateur
if ( if (
$this->getData(['config', 'maintenance']) $this->getData(['config', 'maintenance'])
@ -1366,11 +1367,11 @@ class user extends common
$logStatus = $captcha === true ? 'Erreur de mot de passe' : 'Erreur de captcha'; $logStatus = $captcha === true ? 'Erreur de mot de passe' : 'Erreur de captcha';
// Cas 1 le nombre de connexions est inférieur aux tentatives autorisées : incrément compteur d'échec // Cas 1 le nombre de connexions est inférieur aux tentatives autorisées : incrément compteur d'échec
if ($this->getData(['user', $userId, 'connectFail']) < $this->getData(['config', 'connect', 'attempt'])) { if ($this->getData(['user', $userId, 'connectFail']) < $this->getData(['config', 'connect', 'attempt'])) {
$this->setData(['user', $userId, 'connectFail', $this->getdata(['user', $userId, 'connectFail']) + 1]); $this->setData(['user', $userId, 'connectFail', $this->getdata(['user', $userId, 'connectFail']) + 1], false);
} }
// Cas 2 la limite du nombre de connexion est atteinte : placer le timer // Cas 2 la limite du nombre de connexion est atteinte : placer le timer
if ($this->getdata(['user', $userId, 'connectFail']) == $this->getData(['config', 'connect', 'attempt'])) { if ($this->getdata(['user', $userId, 'connectFail']) == $this->getData(['config', 'connect', 'attempt'])) {
$this->setData(['user', $userId, 'connectTimeout', time()]); $this->setData(['user', $userId, 'connectTimeout', time()], false);
} }
// Cas 3 le délai de bloquage court // Cas 3 le délai de bloquage court
if ($this->getData(['user', $userId, 'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) > time()) { if ($this->getData(['user', $userId, 'connectTimeout']) + $this->getData(['config', 'connect', 'timeout']) > time()) {
@ -1384,9 +1385,13 @@ class user extends common
} }
} }
} }
// Journalisation // Journalisation
$this->saveLog($logStatus); $this->saveLog($logStatus);
// Sauvegarde la base manuellement
$this->saveDB('user');
// Stockage des cookies // Stockage des cookies
if (!empty($_COOKIE['ZWII_USER_ID'])) { if (!empty($_COOKIE['ZWII_USER_ID'])) {
self::$userId = $_COOKIE['ZWII_USER_ID']; self::$userId = $_COOKIE['ZWII_USER_ID'];
@ -1461,12 +1466,14 @@ class user extends common
$newPassword = $this->getInput('userResetNewPassword', helper::FILTER_PASSWORD, true); $newPassword = $this->getInput('userResetNewPassword', helper::FILTER_PASSWORD, true);
} }
// Modifie le mot de passe // Modifie le mot de passe
$this->setData(['user', $this->getUrl(2), 'password', $newPassword]); $this->setData(['user', $this->getUrl(2), 'password', $newPassword], false);
// Réinitialise la date de la demande // Réinitialise la date de la demande
$this->setData(['user', $this->getUrl(2), 'forgot', 0]); $this->setData(['user', $this->getUrl(2), 'forgot', 0], false);
// Réinitialise le blocage // Réinitialise le blocage
$this->setData(['user', $this->getUrl(2), 'connectFail', 0]); $this->setData(['user', $this->getUrl(2), 'connectFail', 0], false);
$this->setData(['user', $this->getUrl(2), 'connectTimeout', 0]); $this->setData(['user', $this->getUrl(2), 'connectTimeout', 0], false);
// Sauvegarde la base manuellement
$this->saveDB('user');
// Valeurs en sortie // Valeurs en sortie
$this->addOutput([ $this->addOutput([
'notification' => helper::translate('Nouveau mot de passe enregistré'), 'notification' => helper::translate('Nouveau mot de passe enregistré'),
@ -1691,7 +1698,7 @@ class user extends common
$this->getData(['user', $keyPost]) !== null $this->getData(['user', $keyPost]) !== null
) { ) {
$this->setData(['user', $keyPost, 'tags', $newTags]); $this->setData(['user', $keyPost, 'tags', $newTags]);
$count += 1; $count += 1;
} }
} }
// Valeurs en sortie // Valeurs en sortie
@ -1702,7 +1709,7 @@ class user extends common
]); ]);
} }
// Liste des groupes et des profils // Liste des groupes et des profils
$usersGroups = $this->getData(['profil']); $usersGroups = $this->getData(['profil']);