From 6a48509e7b01e4a4dbab90e665a9df864ea4c059 Mon Sep 17 00:00:00 2001 From: Thomas Ingles Date: Wed, 7 Feb 2024 16:55:32 +0100 Subject: [PATCH 1/3] plxUtils : refacto strCheck + nouvelle sanitizeHtml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvelle logique pour $tags : `true` == interdit ou liste des admis Les guillemts `"` sont convertis et de nouveau authorisées ds CDATA L'option CDATA est protègé par plxUtils::cdataCheck Previent les attaques XSS JS possible avec le dernier param à `true` Corrige : lien Donnais (description de catégorie, Flux RSS, etc...) tien plxMotor->addCommentaire On autorise les balises HTML :


Où l'on supprime tous les scripts
et ne garde que les attributs src, class et href sans javascript.
On supprime aussi style car imaginons un petit malin faire :

pour les textes sans balise, d'où le remplacement de p par div ds theme/defaut/commentaires Idée : un éditeur HTML leger pour les commentaires. --- core/lib/class.plx.admin.php | 38 ++++++------ core/lib/class.plx.motor.php | 4 +- core/lib/class.plx.utils.php | 108 ++++++++++++++++++++++++++++----- themes/defaut/commentaires.php | 2 +- 4 files changed, 115 insertions(+), 37 deletions(-) diff --git a/core/lib/class.plx.admin.php b/core/lib/class.plx.admin.php index 1650d3519..411095b2d 100644 --- a/core/lib/class.plx.admin.php +++ b/core/lib/class.plx.admin.php @@ -284,11 +284,11 @@ public function editConfiguration($plxConfig, $content) { # est inutile : valeur numerique, champs uniquement avec caractères alphanumérique $content = plxUtils::strCheck($v); } elseif(in_array($k, array('description', 'feed_footer'))) { - # On tolère quelques balises par défaut : , , , , , + # On tolère les balises HTML $content = plxUtils::strCheck($v, true); } else { - # Aucune balise HTML tolérée - $content = plxUtils::strCheck($v, true, null); + # Aucune balise HTML tolérée + $content = plxUtils::strCheck($v, true, true); } ?> @@ -971,12 +971,12 @@ public function editCategories($content, $action=false) { - - - - - - + + + + + + plxPlugins->callHook('plxAdminEditCategoriesXml')); @@ -1112,7 +1112,7 @@ public function editStatiques($content, $action=false) { - + @@ -1291,15 +1291,15 @@ public function editArticle($content, &$id) { <?= plxUtils::strCheck(trim($content['title']), true) ?> - ]]> - ]]> - - - - - - - + + + + + + + + + - ]]> + - +

', true) ?>
 	
  $length ? substr($str, 0, $length) . $add_text : $str;
@@ -900,28 +900,37 @@ public static function strCut($str='', $length=25, $type='', $add_text='...') {
 	}
 
 	/**
-	 * Méthode qui retourne une chaine de caractères formatée en fonction du charset
+	 * Méthode qui retourne une chaine de caractères formatée en fonction du charset ou encapsulé avec CDATA
+	 * Possibilité de la nettoyer de toutes ou certaines balises HTML
 	 *
-	 * @param	str		chaine de caractères
-	 * @param	cdata	encapsule str dans  si true et str non nulle
-	 * @param	tags	balises HTML autorisées dans  ou null
-	 * @return	string	chaine de caractères tenant compte du charset
+	 * @param	str		string			Chaine de caractères à formater OU à encapsulé
+	 * @param	cdata	bool			Encapsule str avec  si true
+	 * @param	tags	bool||string	true : aucune Balises HTML || '', false : Toutes autorisées ou Liste* des autorisées '
...' *(array PHP>=7.4) + * @param clear bool true : scripts interdit et attributs nettoyés (nettoyage du html) + Effet de bords : valide et ferme les balises non fermées + * @return string Chaine vide ou chaine encapsulé par CDATA ou Chaine de caractères tenant compte du charset **/ - public static function strCheck($str, $cdata=false, $tags='
') { + public static function strCheck($str, $cdata=false, $tags='', $clear=false) { $str = trim($str); - if ($str === '') { + if(empty($str)) { return ''; } - - if ($cdata) { - # caractère " interdit. Remplacer par " si besoin à la saisie - return ''; + # Important : Appellé avant pour bien effacer toutes les balises soient supprimées avec strip_tags + # et que leurs JS deviennent des noeuds textes impossible a nettoyés car non detectés. + # Elles sont supprimées avant et strip_tags n'aura point à les traiter car inexistantes. + # Si appellé après strip_tags : => JS =>

JS

+ if($clear) { # Scripts et autres attributs interdits : previent les attaques XSS + $str = plxUtils::sanitizeHtml($str); + } + if($tags) { # Balises HTML interdites (true) / Autorisées (liste) + $str = strip_tags($str, is_bool($tags)? '': $tags); + } + if($cdata) { + return ''; } - # ENT_COMPAT : Convertit les guillemets doubles, et ignore les guillemets simples. - # les caractères suivants seont convertis en entités HTML : & > < " - return htmlspecialchars($str, ENT_COMPAT | ENT_HTML5, PLX_CHARSET); + return htmlspecialchars($str, ENT_QUOTES, PLX_CHARSET); } /** @@ -1655,4 +1664,73 @@ public static function sanitizePhpTags(String $content) { public static function sanitizePhp(String $content) { return preg_replace('#\b(fsockopen|proc_open|system|exec|chroot|shell_exec|socket\w*)\b\([^)]*?\)\s*;#', '/* $1() not allowed here */;' . PHP_EOL, $content); } + + + /** + * Nettoie du HTML ET Supprime les balises 'script' (par defaut) et ceux 'inline' pour prévenir des attaques XSS + * @param String|Array $content Texte ou tableau a nettoyer + * @param Array $noNodes Balises a supprimés :defaut: array('script'); :idée+: 'img',style','link','meta' + * @param Array $okAttrs Attributs a gardés :defaut: array('src','href','class'); :idée+: 'style' + * @return String|Array Variable nettoyée + * @author Thomas I. @sudwebdesign & info du web + * @note : Départ inspiré de https://mradeveloper.com/blog/remove-javascript-from-html-with-php (mais oublié '
') + * @todo : No goto? : traversé le DOM par la fin : boucle for inversée + recursive + * @voir : https://www.php.net/manual/fr/domdocument.loadhtml.php#125361 + **/ + public static function sanitizeHtml($content, $noNodes=array('script'), $okAttrs=array('src','href','class')) { + if(empty($content)) return $content; + elseif(is_bool($content)) return $content; + # Initialise les variables + if(is_array($content)) { + $inputArray = $content; + $returnType = 'array'; + } else { + $inputArray = array(trim($content)); + $returnType = 'string'; + } + $sanitizedInput = array(); + $flags = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOBLANKS | LIBXML_NONET; + # Nettoyage + foreach($inputArray as $input) { + if(!empty($input) and is_string($input)){ + # De https://www.php.net/manual/fr/function.strip-tags.php#119909 + $xml = new DOMDocument('1.0', PLX_CHARSET); + # Suppression des avertissements + libxml_use_internal_errors(true); + # Petit hack pour un bon encodage : voir : https://www.php.net/manual/fr/domdocument.loadhtml.php#95251 + if($xml->loadHTML('' . $input . '', $flags)){ + $xml->encoding = PLX_CHARSET; # Insert propre du charset + RELOAD: # Fix récursif low cost : Voir : https://www.php.net/manual/fr/class.domnamednodemap.php#94078 + foreach($xml->getElementsByTagName('*') as $tag){ # todo : pour faire bien, utiliser une boucle inversée + # Supprime un noeud interdit (script &+) + if(in_array($tag->nodeName, $noNodes)) { + $tag->parentNode->removeChild($tag); + goto RELOAD; # Nvl ordre du DOM, on recommence + } + elseif($tag->attributes->getNamedItem('href') + and stripos($tag->attributes->getNamedItem('href')->value, 'javascript') !== false) { + $tag->removeAttribute('href'); # Suppr inline js + } + + RELOADATTR: # Suppr attributs interdits + foreach($tag->attributes as $attr){ + if(!in_array(strtolower($attr->name), $okAttrs)){ + $tag->removeAttribute($attr->name); + goto RELOADATTR;# Nvl ordre du DOM, on retraverse les attributs + } + } + } + } + # Sauve le HTML nettoyé et bien encodé :voir: https://www.php.net/manual/fr/domdocument.savexml.php#88525 + $input = $xml->saveHTML($xml->documentElement); # sans l'entête xml et le html encapsulant + unset($xml); + } + $sanitizedInput[] = $input; + } + + if($returnType == 'string') { + return $sanitizedInput[0]; + } + return $sanitizedInput; + } } diff --git a/themes/defaut/commentaires.php b/themes/defaut/commentaires.php index e38e183ca..e7cf48669 100644 --- a/themes/defaut/commentaires.php +++ b/themes/defaut/commentaires.php @@ -21,7 +21,7 @@ lang('SAID'); ?> :
-

comContent(); ?>

+
comContent(); ?>
Date: Wed, 7 Feb 2024 17:09:16 +0100 Subject: [PATCH 2/3] Fix : plxMotor : newcommentaire double checks & checkSite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CheckSite change la variable par référence --- core/lib/class.plx.motor.php | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/core/lib/class.plx.motor.php b/core/lib/class.plx.motor.php index 8658517c8..11948c94c 100644 --- a/core/lib/class.plx.motor.php +++ b/core/lib/class.plx.motor.php @@ -1081,12 +1081,10 @@ public function newCommentaire($artId, $content) { $comment = [ 'type' => 'normal', - 'author' => plxUtils::strCheck(trim(!empty($content['name']) ? $content['name'] : $content['login'])), - 'content' => plxUtils::strCheck(trim($content['content'])), - # On vérifie le mail - 'mail' => (!empty($content['mail']) and plxUtils::checkMail(trim($content['mail']))) ? trim($content['mail']) : '', - # On vérifie le site - 'site' => (!empty($content['site']) and plxUtils::checkSite(trim($content['site']))) ? trim($content['site']) : '', + 'author' => trim(!empty($content['name']) ? $content['name'] : $content['login']), + 'content' => trim($content['content']), + 'mail' => trim($content['mail']), + 'site' => trim($content['site']), # On récupère l'adresse IP du posteur 'ip' => plxUtils::getIp(), # Commentaire parent en cas de réponse @@ -1125,8 +1123,8 @@ public function addCommentaire($content) { - - + +

', true) ?>
 	
 
Date: Wed, 7 Feb 2024 17:32:00 +0100
Subject: [PATCH 3/3] plxAdmin : strCheck, bonne indentation et trim aux bons
 endroits
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

login et name sont verifiés en amont du xml (strCheck inutile)
PATTERN_NAME
cat_name est trimé avant le test
---
 core/lib/class.plx.admin.php | 98 ++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 49 deletions(-)

diff --git a/core/lib/class.plx.admin.php b/core/lib/class.plx.admin.php
index 411095b2d..c4449238d 100644
--- a/core/lib/class.plx.admin.php
+++ b/core/lib/class.plx.admin.php
@@ -70,17 +70,17 @@ public function getPage() {
 		# On check pour avoir le numero de page
 		if(!empty($_GET['page']) AND is_numeric($_GET['page']) AND $_GET['page'] > 0)
 			$this->page = $_GET['page'];
-			elseif($savePage) {
-				if(!empty($_POST['sel_cat'])) {
-					$this->page = 1;
-				} else {
-					$this->page = !empty($_SESSION['page'][$pageName]) ? intval($_SESSION['page'][$pageName]) : 1;
-				}
-			}
-			# On sauvegarde
-			if($savePage) {
-				$_SESSION['page'][$pageName] = $this->page;
+		elseif($savePage) {
+			if(!empty($_POST['sel_cat'])) {
+				$this->page = 1;
+			} else {
+				$this->page = !empty($_SESSION['page'][$pageName]) ? intval($_SESSION['page'][$pageName]) : 1;
 			}
+		}
+		# On sauvegarde
+		if($savePage) {
+			$_SESSION['page'][$pageName] = $this->page;
+		}
 	}
 
 	/**
@@ -492,22 +492,22 @@ public function editProfil($content) {
 		if(isset($content['profil']) AND trim($content['name'])=='')
 			return plxMsg::Error(L_ERR_USER_EMPTY);
 
-			if(trim($content['email'])!='' AND !plxUtils::checkMail(trim($content['email'])))
-				return plxMsg::Error(L_ERR_INVALID_EMAIL);
+		if(trim($content['email'])!='' AND !plxUtils::checkMail(trim($content['email'])))
+			return plxMsg::Error(L_ERR_INVALID_EMAIL);
 
-			if(!in_array($content['lang'], plxUtils::getLangs()))
-				return plxMsg::Error(L_UNKNOWN_ERROR);
+		if(!in_array($content['lang'], plxUtils::getLangs()))
+			return plxMsg::Error(L_UNKNOWN_ERROR);
 
-			$this->aUsers[$_SESSION['user']]['name'] = trim($content['name']);
-			$this->aUsers[$_SESSION['user']]['infos'] = trim($content['content']);
-			$this->aUsers[$_SESSION['user']]['email'] = trim($content['email']);
-			$this->aUsers[$_SESSION['user']]['lang'] = $content['lang'];
+		$this->aUsers[$_SESSION['user']]['name'] = $content['name'];
+		$this->aUsers[$_SESSION['user']]['infos'] = $content['content'];
+		$this->aUsers[$_SESSION['user']]['email'] = $content['email'];
+		$this->aUsers[$_SESSION['user']]['lang'] = $content['lang'];
 
-			$_SESSION['admin_lang'] = $content['lang'];
+		$_SESSION['admin_lang'] = $content['lang'];
 
-			# Hook plugins
-			if(eval($this->plxPlugins->callHook('plxAdminEditProfil'))) return;
-			return $this->editUsers(null, true);
+		# Hook plugins
+		if(eval($this->plxPlugins->callHook('plxAdminEditProfil'))) return;
+		return $this->editUsers(null, true);
 	}
 
 	/**
@@ -699,7 +699,7 @@ public function editUsers($content, $action=false) {
 
 				$this->aUsers[$user_id]['delete'] = isset($this->aUsers[$user_id]['delete']) ? $this->aUsers[$user_id]['delete'] : 0;
 				$this->aUsers[$user_id]['lang'] = isset($this->aUsers[$user_id]['lang']) ? $this->aUsers[$user_id]['lang'] : $this->aConf['default_lang'];
-				$this->aUsers[$user_id]['infos'] = isset($this->aUsers[$user_id]['infos']) ? $this->aUsers[$user_id]['infos'] : '';
+				$this->aUsers[$user_id]['infos'] = isset($this->aUsers[$user_id]['infos']) ? trim($this->aUsers[$user_id]['infos']) : '';
 
 				$this->aUsers[$user_id]['password_token'] = isset($this->aUsers[$user_id]['_password_token']) ? $this->aUsers[$user_id]['_password_token']  : '';
 				$this->aUsers[$user_id]['password_token_expiry'] = isset($this->aUsers[$user_id]['_password_token_expiry']) ? $this->aUsers[$user_id]['_password_token_expiry'] : '';
@@ -746,8 +746,8 @@ public function editUsers($content, $action=false) {
 				}
 ?>
 	
-		
-		
+		
+		
 		
 		
 		
@@ -797,14 +797,14 @@ public function editUser($content) {
 		if(!in_array($content['lang'], plxUtils::getLangs()))
 			return plxMsg::Error(L_UNKNOWN_ERROR);
 
-			$this->aUsers[$content['id']]['email'] = $content['email'];
-			$this->aUsers[$content['id']]['infos'] = trim($content['content']);
-			$this->aUsers[$content['id']]['lang'] = $content['lang'];
+		$this->aUsers[$content['id']]['email'] = $content['email'];
+		$this->aUsers[$content['id']]['infos'] = $content['content'];
+		$this->aUsers[$content['id']]['lang'] = $content['lang'];
 
-			# Hook plugins
-			eval($this->plxPlugins->callHook('plxAdminEditUser'));
+		# Hook plugins
+		eval($this->plxPlugins->callHook('plxAdminEditUser'));
 
-			return $this->editUsers(null,true);
+		return $this->editUsers(null,true);
 	}
 
 	/**
@@ -863,7 +863,7 @@ public function editCategories($content, $action=false) {
 		# Ajout d'une nouvelle catégorie à partir de la page article
 		elseif(!empty($content['new_category'])) {
 			# Test pour autoriser uniquement les caractères alphanumériques
-			$cat_name = $content['new_catname'];
+			$cat_name = trim($content['new_catname']);
 			if(!preg_match(PATTERN_NAME, $cat_name)) {
 				return plxMsg::Error(L_INVALID_VALUE . ' : ' . $cat_name);
 			}
@@ -900,7 +900,7 @@ public function editCategories($content, $action=false) {
 
 			foreach($content['catNum'] as $cat_id) {
 				# Test pour autoriser uniquement les caractères alphanumériques
-				$cat_name = $content[$cat_id.'_name'];
+				$cat_name = trim($content[$cat_id.'_name']);
 				if(!preg_match(PATTERN_NAME, $cat_name)) {
 					return plxMsg::Error(L_INVALID_VALUE . ' : ' . $cat_name);
 				}
@@ -917,14 +917,14 @@ public function editCategories($content, $action=false) {
 				$this->aCats[$cat_id]['active'] = $content[$cat_id.'_active'];
 				$this->aCats[$cat_id]['ordre'] = intval($content[$cat_id.'_ordre']);
 				$this->aCats[$cat_id]['homepage'] = isset($this->aCats[$cat_id]['homepage']) ? $this->aCats[$cat_id]['homepage'] : 1;
-				$this->aCats[$cat_id]['description'] = isset($this->aCats[$cat_id]['description']) ? $this->aCats[$cat_id]['description'] : '';
+				$this->aCats[$cat_id]['description'] = isset($this->aCats[$cat_id]['description']) ? trim($this->aCats[$cat_id]['description']) : '';
 				$this->aCats[$cat_id]['template'] = isset($this->aCats[$cat_id]['template']) ? $this->aCats[$cat_id]['template'] : 'categorie.php';
-				$this->aCats[$cat_id]['thumbnail'] = isset($this->aCats[$cat_id]['thumbnail']) ? $this->aCats[$cat_id]['thumbnail'] : '';
-				$this->aCats[$cat_id]['thumbnail_title'] = isset($this->aCats[$cat_id]['thumbnail_title']) ? $this->aCats[$cat_id]['thumbnail_title'] : '';
-				$this->aCats[$cat_id]['thumbnail_alt'] = isset($this->aCats[$cat_id]['thumbnail_alt']) ? $this->aCats[$cat_id]['thumbnail_alt'] : '';
-				$this->aCats[$cat_id]['title_htmltag'] = isset($this->aCats[$cat_id]['title_htmltag']) ? $this->aCats[$cat_id]['title_htmltag'] : '';
-				$this->aCats[$cat_id]['meta_description'] = isset($this->aCats[$cat_id]['meta_description']) ? $this->aCats[$cat_id]['meta_description'] : '';
-				$this->aCats[$cat_id]['meta_keywords'] = isset($this->aCats[$cat_id]['meta_keywords']) ? $this->aCats[$cat_id]['meta_keywords'] : '';
+				$this->aCats[$cat_id]['thumbnail'] = isset($this->aCats[$cat_id]['thumbnail']) ? trim($this->aCats[$cat_id]['thumbnail']) : '';
+				$this->aCats[$cat_id]['thumbnail_title'] = isset($this->aCats[$cat_id]['thumbnail_title']) ? trim($this->aCats[$cat_id]['thumbnail_title']) : '';
+				$this->aCats[$cat_id]['thumbnail_alt'] = isset($this->aCats[$cat_id]['thumbnail_alt']) ? trim($this->aCats[$cat_id]['thumbnail_alt']) : '';
+				$this->aCats[$cat_id]['title_htmltag'] = isset($this->aCats[$cat_id]['title_htmltag']) ? trim($this->aCats[$cat_id]['title_htmltag']) : '';
+				$this->aCats[$cat_id]['meta_description'] = isset($this->aCats[$cat_id]['meta_description']) ? trim($this->aCats[$cat_id]['meta_description']) : '';
+				$this->aCats[$cat_id]['meta_keywords'] = isset($this->aCats[$cat_id]['meta_keywords']) ? trim($this->aCats[$cat_id]['meta_keywords']) : '';
 
 				# Hook plugins
 				eval($this->plxPlugins->callHook('plxAdminEditCategoriesUpdate'));
@@ -1007,14 +1007,14 @@ public function editCategories($content, $action=false) {
 	public function editCategorie($content) {
 		# Mise à jour du fichier categories.xml
 		$this->aCats[$content['id']]['homepage'] = intval($content['homepage']);
-		$this->aCats[$content['id']]['description'] = trim($content['content']);
+		$this->aCats[$content['id']]['description'] = $content['content'];
 		$this->aCats[$content['id']]['template'] = $content['template'];
 		$this->aCats[$content['id']]['thumbnail'] = $content['thumbnail'];
 		$this->aCats[$content['id']]['thumbnail_title'] = $content['thumbnail_title'];
 		$this->aCats[$content['id']]['thumbnail_alt'] = $content['thumbnail_alt'];
-		$this->aCats[$content['id']]['title_htmltag'] = trim($content['title_htmltag']);
-		$this->aCats[$content['id']]['meta_description'] = trim($content['meta_description']);
-		$this->aCats[$content['id']]['meta_keywords'] = trim($content['meta_keywords']);
+		$this->aCats[$content['id']]['title_htmltag'] = $content['title_htmltag'];
+		$this->aCats[$content['id']]['meta_description'] = $content['meta_description'];
+		$this->aCats[$content['id']]['meta_keywords'] = $content['meta_keywords'];
 		# Hook plugins
 		eval($this->plxPlugins->callHook('plxAdminEditCategorie'));
 		return $this->editCategories(null, true);
@@ -1049,7 +1049,7 @@ public function editStatiques($content, $action=false) {
 		# mise à jour de la liste des pages statiques
 		elseif(!empty($content['update'])) {
 			foreach($content['staticNum'] as $static_id) {
-				$stat_name = $content[$static_id.'_name'];
+				$stat_name = trim($content[$static_id.'_name']);
 				if($stat_name!='') {
 					$url = (!empty($content[$static_id.'_url'])) ? plxUtils::urlify($content[$static_id.'_url']) : '';
 					$stat_url = (!empty($url)) ? $url : plxUtils::urlify($stat_name);
@@ -1066,10 +1066,10 @@ public function editStatiques($content, $action=false) {
 					$this->aStats[$static_id]['active'] = $content[$static_id.'_active'];
 					$this->aStats[$static_id]['menu'] = $content[$static_id.'_menu'];
 					$this->aStats[$static_id]['ordre'] = intval($content[$static_id.'_ordre']);
-					$this->aStats[$static_id]['template'] = (isset($this->aStats[$static_id]['template'])?$this->aStats[$static_id]['template']:'static.php');
-					$this->aStats[$static_id]['title_htmltag'] = (isset($this->aStats[$static_id]['title_htmltag'])?$this->aStats[$static_id]['title_htmltag']:'');
-					$this->aStats[$static_id]['meta_description'] = (isset($this->aStats[$static_id]['meta_description'])?$this->aStats[$static_id]['meta_description']:'');
-					$this->aStats[$static_id]['meta_keywords'] = (isset($this->aStats[$static_id]['meta_keywords'])?$this->aStats[$static_id]['meta_keywords']:'');
+					$this->aStats[$static_id]['template'] = isset($this->aStats[$static_id]['template']) ? $this->aStats[$static_id]['template'] : 'static.php';
+					$this->aStats[$static_id]['title_htmltag'] = isset($this->aStats[$static_id]['title_htmltag']) ? trim($this->aStats[$static_id]['title_htmltag']) : '';
+					$this->aStats[$static_id]['meta_description'] = isset($this->aStats[$static_id]['meta_description']) ? trim($this->aStats[$static_id]['meta_description']) : '';
+					$this->aStats[$static_id]['meta_keywords'] = isset($this->aStats[$static_id]['meta_keywords']) ? trim($this->aStats[$static_id]['meta_keywords']) : '';
 					if(plxUtils::getValue($this->aStats[$static_id]['date_creation'])=='') {
 						$this->aStats[$static_id]['date_creation'] = date('YmdHi');
 						$this->aStats[$static_id]['date_update'] = date('YmdHi');