connect_error) { $_SESSION['erreurs_connexion_db'][$i] = $_SESSION['db']->connect_errno; $_SESSION['db'] = NULL; sleep($i+1); // Attente avant de recommencer (en secondes). NB : le délai d'attente augmente à chaque tentative... } else break; } if ($_SESSION['db'] == NULL) // Erreur de la fonction de connexion, malgré plusieurs tentatives : { if (PRODUCTION) { // Préparation du texte d'erreur en dur et dans les 2 langues car si la BDD n'est pas accessible, on aura du mal à aller y chercher les messages d'erreur... : $message_erreur = '

Oups ! Une erreur est survenue.

Essayez de rafraichir la page mais si le problème persiste, n\'hésitez pas à nous contacter à : '.$_SESSION['Config__Adresse_email_contact'].'

NB : Ce message a été automatiquement envoyé aux services techniques de Koriolan pour être traité.
Car vous offrir un service irréprochable est notre priorité !

'; $message_erreur .= '
'; $message_erreur .= '

Oops! An error occurred.

Try to refresh the page but if the problem persists, please contact us at : '.$_SESSION['Config__Adresse_email_contact'].'

NB: This message has automatically been sent to Koriolan technical services for processing.
Because offering you an irreproachable service is our permanent concern !

'; // Affichage du message d'erreur : echo '
'.$message_erreur.'
'; Enregistrement_log("\tOups ! Erreur de connexion à MYSQL", __FILE__, __LINE__); } else { $message_erreur = '

Oups ! Une erreur est survenue lors de l\'ouverture de la BDD.

'.MAX_TENTATIVES_CONNEXIONS_BDD.' tentatives ont été effectuées et ont toutes échouées

'; echo '

Les erreurs récupérées sont :'; for ($i=0; $i'; echo '

'; } exit(); // Arrêt du script. } else { if ($_SESSION['erreurs_connexion_db'][0] != 0) // Si on s'est connecté mais qu'au moins une erreur a été détectée, on enregistre dans l'historique l'évènement). { for ($i=0; (($_SESSION['erreurs_connexion_db'][$i] != 0) AND ($iconnect_error) { Enregistrement_log("\tOuverture_bdd_bateau : échec de connexion à la BDD principale pour résoudre la génération active", __FILE__, __LINE__); return false; } $requete = "SELECT Nom_base FROM TB_Generations_bateau WHERE ID_Bateau=? AND Date_fin IS NULL"; $stmt = $db_principale->prepare($requete); $stmt->bind_param('i', $id_bateau); $stmt->execute(); $stmt->bind_result($nom_base); $trouve = $stmt->fetch(); $stmt->close(); $db_principale->close(); if (!$trouve) { // Aucune génération active : ce bateau n'a encore jamais transmis d'archive. return false; } Ouverture_bdd(BDD_BATEAUX_HOST.":".BDD_BATEAUX_PORT, BDD_BATEAUX_USER, BDD_BATEAUX_PASSWORD, $nom_base); return true; } //************************************************************************************************************ // Fonction : Exécute une requête MYSQL // Reçoit : La requête, le fichier et la ligne d'où est appelée la fonction // Retour : Le résultat de la requête. // Attention : Si une erreur se produit lors de l'exécution, une page d'erreur est affichée et l'exécution est arrêtée ! //************************************************************************************************************ function Requete_bdd($requete, $fichier, $ligne) { $retour = mysqli_query($_SESSION['db'], $requete); if ($retour == false) // Erreur de la fonction MYSQLI_QUERY : { // Préparation du texte d'erreur : $message_erreur = nl2br($_SESSION['textes']['fonctions_bdd']['all']['retour']['message_erreur']); // Mise à jour des parametres du texte : $message_erreur = str_replace("[[Email]]", $_SESSION['Config__Adresse_email_contact'], $message_erreur); // Affichage du message d'erreur : echo '
'.$message_erreur.'
'; // Enregistrement dans le fichier de logs : Enregistrement_log("\tOups ! Erreur MYSQL. Requête = [".$requete."], message d'erreur = [".mysqli_error($_SESSION['db'])."]", $fichier, $ligne); exit(); // Arrêt du script. } else return($retour); // Requete revenue sans erreur... } //************************************************************************************************************ // Fonction : Exécution d'une requête préparée dans la BDD // Reçoit : La requête à exécuter, un array avec les paramètres de la requête, le fichier d'origine et la ligne d'origine // Retour : Le retour de la requête si aucune erreur. En cas d'erreur, le script est arrêté après l'affichage d'une page d'erreur //************************************************************************************************************ function Requete_preparee_bdd($requete, $parametres, $fichier, $ligne) { $texte_erreur = ""; if ($stmt = mysqli_prepare($_SESSION['db'], $requete)) // Création de la requête préparée { // Récupération des éléments du tableau de paramètres reçu : $types = ""; $nb = 0; foreach ($parametres as $parametre) { $types .= $parametre[0]; // Concaténation des types pour obtenir une chaine de tous les types, les uns derrière les autres $valeurs[$nb ++] = $parametre[1]; // Récupération de la valeur de chaque paramètre dans un tableau temporaire } // Création d'un tableau avec tous les paramètres de la fonction 'mysqli_stmt_bind_param' : if ($nb > 0) { $params[] = $stmt; // Premier paramètre : identifiant de la requête préparée $params[] = &$types; // Second paramètre : chaine de caractère avec tous les types for ($i=0; $i<$nb; $i++) $params[] = &$valeurs[$i]; // Troisième et au-delà : une valeur par paramètre // Appel de la fonction 'mysqli_stmt_bind_param' à travers 'call_user_func_array' qui permet de passer un tableau en argument : if (call_user_func_array("mysqli_stmt_bind_param", $params) == false) // NB : le retour de 'call_user_func_array' est celui de 'mysqli_stmt_bind_param' { $texte_erreur = "\tOups ! Le binding de la requête préparée [".$requete."] a échoué avec le message d'erreur [".mysqli_error($_SESSION['db'])."]"; } } // Si le nombre de paramètres est nul, c'est qu'il n'y a pas de variable dans la requet et qu'on peut donc l'exécuter sans binding... // exécution de la requête préparée avec le binding des variables fait : if (mysqli_stmt_execute($stmt) == false) // Exécution de la requête { $texte_erreur = "\tOups ! L'exécution de la requête préparée [".$requete."] a échoué avec le message d'erreur [".mysqli_error($_SESSION['db'])."]"; } // Récupération du jeu de résultats : $retour = mysqli_stmt_get_result($stmt); if (($retour == false) AND (mysqli_error($_SESSION['db']) != "")) // Il se peut que 'mysqli_stmt_get_result' renvoie 'false' si la requête exécutée n'attend pas de réponse (UPDATE, INSERT). On vériife donc si une erreur MySql a été déclenchée avant de passer en erreur... { $texte_erreur = "\tOups ! La recherche des résultats de la requête préparée [".$requete."] a échoué avec le message d'erreur [".mysqli_error($_SESSION['db'])."]"; } } else $texte_erreur = "\tOups ! La création de la requête préparée [".$requete."] a échoué avec le message d'erreur [".mysqli_error($_SESSION['db'])."]"; mysqli_stmt_close($stmt); // Libération de la requête préparée // Traitement des cas d'erreur : // (NB : $texte_erreur est différent de $message_erreur !!) if ($texte_erreur != "") { // Préparation du texte d'erreur : $message_erreur = nl2br($_SESSION['textes']['fonctions_bdd']['all']['retour']['message_erreur']); // Mise à jour des parametres du texte : $message_erreur = str_replace("[[Email]]", $_SESSION['Config__Adresse_email_contact'], $message_erreur); // Affichage du message d'erreur : echo '
'.$message_erreur.'
'; // Enregistrement dans le fichier de logs : Enregistrement_log($texte_erreur, $fichier, $ligne); exit(); // Arrêt du script. } else return($retour); // Requete revenue sans erreur... } //************************************************************************************************************ // Fonction : Fetch de ligne de résultat MYSQL // Reçoit : La réponse complète de la requête (au sein de laquelle la ligne doit être cherchée) // Retour : La ligne de resultat suivante ou FALSE si aucune ligne supplémentaire n'existe. //************************************************************************************************************ function Recherche_ligne_bdd($reponse) { // Récupération du type de retour à renvoyer : if (func_num_args() > 1) { $resulttype = func_get_arg(1); switch(func_get_arg(1)) { case MYSQLI_ASSOC : {$resulttype = MYSQLI_ASSOC; break;} // ne renvoi que la version associative du tableau de retour case MYSQLI_NUM : {$resulttype = MYSQLI_NUM; break;} // ne renvoi que la version numérique du tableau de retour case MYSQLI_BOTH : default : {$resulttype = MYSQLI_BOTH; break;} // renvoi les deux versions (associative et numérique) du tableau de retour } } else $resulttype = MYSQLI_BOTH; // Valeur par défaut de la fonction. // Recherche de la ligne return(mysqli_fetch_array($reponse, $resulttype)); } //************************************************************************************************************ // Fonction : Libération de jeu de résultat MYSQL // Reçoit : La variable à libérer // Retour : Rien //************************************************************************************************************ function Liberation_jeu_de_resultat_bdd($reponse) { mysqli_free_result($reponse); } //************************************************************************************************************ // Fonction : Récupération de l'id créé // Reçoit : Rien // Retour : L'ID de l'enregistrement qui vient d'être ajouté //************************************************************************************************************ function Recuperation_id_cree_bdd() { return(mysqli_insert_id($_SESSION['db'])); } //************************************************************************************************************ // Fonction : Liste des champs de base de données // Reçoit : Rien // Retour : La liste des champs //************************************************************************************************************ function Champs_bdd($reponse) { return(mysqli_fetch_fields($reponse)); } //************************************************************************************************************ // Fonction : Comptage des résultats de la requête // Reçoit : La requête dont le comptage est recherché // Retour : Le nombre de lignes de résultats de la requête //************************************************************************************************************ function Comptage_resultats_requete($requete) { $reponse = Requete_bdd('SELECT COUNT(*) AS total FROM ('.$requete.') AS Total', __FILE__, __LINE__); // Le second AS est nécessaire mais ne sert pas... $donnees = Recherche_ligne_bdd($reponse); Liberation_jeu_de_resultat_bdd($reponse); return($donnees['total']); } //************************************************************************************************************ // Fonction : Protection d'une requête contre les injections SQL // Reçoit : La requête à traiter // Retour : La requête après traitement //************************************************************************************************************ function Protection_mysql($requete) { return(mysqli_real_escape_string($_SESSION['db'], $requete)); } //************************************************************************************************************ // Fonction : Fermeture de base de données // Reçoit : Rien // Retour : Rien //************************************************************************************************************ function Fermeture_bdd() { if ($_SESSION['db'] != NULL) // SDIR # 289 { mysqli_close($_SESSION['db']); $_SESSION['db'] = NULL; // SDIR # 289 } } //************************************************************************************************************ // Fonction : Encryptage d'un message // Reçoit : Le message à encrypter // Retour : Le message encrypté //************************************************************************************************************ function Encryptage($message) { // La clé (secrète) est le mdp du user : $key = $_SESSION['login_key']; // algorythme choisi selon http://fr.php.net/manual/fr/mcrypt.ciphers.php $algo = MCRYPT_BLOWFISH; // mode choisi selon http://fr.php.net/manual/fr/mcrypt.constants.php $mode = MCRYPT_MODE_CBC ; //Réduction de la taille de la clé selon la taille maximale supportée par l'algorythme mcrypt choisi : $key = substr($key, 0, mcrypt_module_get_algo_key_size($algo)); // Création d'un vecteur d'initialisation selon la taille maximale possible : $iv = mcrypt_create_iv(mcrypt_get_iv_size($algo, $mode), MCRYPT_DEV_URANDOM); // Chiffrage du message : $data = mcrypt_encrypt($algo, $key, $message, $mode, $iv); // Retour du message après ajouté devant l'IV qui sera nécessaire au décodage (l'IV n'est pas confidentiel) // puis avoir encodé le tout en base64 (utile si l'on veut mettre le résultat dans une base de donnée) return(base64_encode($iv.$data)); } //************************************************************************************************************ // Fonction : Décryptage d'un message // Reçoit : Le message crypté // Retour : Le message décrypté //************************************************************************************************************ function Decryptage($message_crypte) { // La clé (secrète) est le mdp du user : $key = $_SESSION['login_key']; // algorythme choisi selon http://fr.php.net/manual/fr/mcrypt.ciphers.php $algo = MCRYPT_BLOWFISH; // mode choisi selon http://fr.php.net/manual/fr/mcrypt.constants.php $mode = MCRYPT_MODE_CBC ; //Réduction de la taille de la clé selon la taille maximale supportée par l'algorythme mcrypt choisi : $key = substr($key, 0, mcrypt_module_get_algo_key_size($algo)); // Rechjerche de la taille du vecteur d'initialisation (dépend uniquement du mode de cryptage) : $size = mcrypt_get_iv_size($algo, $mode); // Désencodage en base64 : $message_crypte = base64_decode($message_crypte); // Extraction de l'IV qui est stocké en début de message : $iv = substr($message_crypte, 0, $size); // On extrait l'IV (qui est de longueur connue) du début du message. // Extraction du message crypté proprement dit : $message_crypte = substr($message_crypte, $size); // On ne garde que la fin du message (sans l'IV). // Retour du message décrypté : return(trim(mcrypt_decrypt($algo, $key, $message_crypte, $mode, $iv))); // Le TRIM permet de supprimer les 0x00 qui sont ajoutés à la fin pour former des blocs de 8 octets... } //************************************************************************************************************ // Fonction : Rencryptage d'un message // Reçoit : Le message à encrypter (les variables de session $_SESSION['login_key'] et $_SESSION['new_login_key'] sont utilisées pour assurer le décryptage puis le rencryptage) // Retour : Le message encrypté //************************************************************************************************************ function Rencryptage($message_crypte) { // Décodage avec ancienne clé : // La clé (secrète) est l'ancien mdp du user : $key = $_SESSION['login_key']; // algorythme choisi selon http://fr.php.net/manual/fr/mcrypt.ciphers.php $algo = MCRYPT_BLOWFISH; // mode choisi selon http://fr.php.net/manual/fr/mcrypt.constants.php $mode = MCRYPT_MODE_CBC ; //Réduction de la taille de la clé selon la taille maximale supportée par l'algorythme mcrypt choisi : $key = substr($key, 0, mcrypt_module_get_algo_key_size($algo)); // Rechjerche de la taille du vecteur d'initialisation (dépend uniquement du mode de cryptage) : $size = mcrypt_get_iv_size($algo, $mode); // Désencodage en base64 : $message_crypte = base64_decode($message_crypte); // Extraction de l'IV qui est stocké en début de message : $iv = substr($message_crypte, 0, $size); // On extrait l'IV (qui est de longueur connue) du début du message. // Extraction du message crypté proprement dit : $message_crypte = substr($message_crypte, $size); // On ne garde que la fin du message (sans l'IV). // Retour du message décrypté : $message_decrypte = trim(mcrypt_decrypt($algo, $key, $message_crypte, $mode, $iv)); // Le TRIM permet de supprimer les 0x00 qui sont ajoutés à la fin pour former des blocs de 8 octets... // Encodage avec nouvelle clé : // La clé (secrète) est le nouveau mdp du user : $key = $_SESSION['new_login_key']; //Réduction de la taille de la clé selon la taille maximale supportée par l'algorythme mcrypt choisi : $key = substr($key, 0, mcrypt_module_get_algo_key_size($algo)); // Création d'un vecteur d'initialisation selon la taille maximale possible : $iv = mcrypt_create_iv(mcrypt_get_iv_size($algo, $mode), MCRYPT_DEV_URANDOM); // Chiffrage du message : $data = mcrypt_encrypt($algo, $key, $message_decrypte, $mode, $iv); // Retour du message après ajouté devant l'IV qui sera nécessaire au décodage (l'IV n'est pas confidentiel) // puis avoir encodé le tout en base64 (utile si l'on veut mettre le résultat dans une base de donnée) return(base64_encode($iv.$data)); } //************************************************************************************************************ // Fonction : Génération de mot de passe aléatoire // Reçoit : La longueur du mot de passe à générer // Retour : Le mot de passe généré //************************************************************************************************************ function Mdp_aleatoire($longueur) { $password = ""; $prec = 0; for($i = 0; $i < $longueur; $i++) { $random = rand(48,122); // chiffres de 48 à 57, maj de 65 à 90 et min de 97 à 122 // Suppression des caractères non alphanumériques : if (($random == ord("0")) OR (($random >= 58) AND ($random <= 64)) OR ($random == ord("I")) OR ($random == ord("O")) OR ($random == ord("l")) OR ($random == ord("o")) OR (($random >= 91) AND ($random <= 96)) OR ($random == $prec)) // Evite les doublons de caractères identiques (difficile à lire) { $i--; continue; } $password .= chr($random); $prec = $random; } return($password); } //************************************************************************************************************ // Fonction : Vérification de la conformité d'un mot de passe (longueur, caractères utilisés, etc...) // Reçoit : Le mot de passe à vérifier // Retour : La liste des champs //************************************************************************************************************ function Check_mdp($mdp) { global $message_erreur; // $pattern = "#(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z]).{".MIN_TAILLE_MOTS_DE_PASSE.",".MAX_TAILLE_MOTS_DE_PASSE."}#"; // Nombre de caractères entre MIN et MAX, caractères minuscules ou majuscules ou chiffres ou '_' et '-' : // $pattern = "#^[a-zA-Z0-9_-]{".MIN_TAILLE_MOTS_DE_PASSE.",".."}#"; $longueur = strlen($mdp); if ($longueur < MIN_TAILLE_MOTS_DE_PASSE) return(0); if ($longueur > MAX_TAILLE_MOTS_DE_PASSE) return(0); for ($i = 0; $i < $longueur; $i ++) { if (($mdp[$i] >= 'A') AND ($mdp[$i] <= 'Z')) continue; if (($mdp[$i] >= 'a') AND ($mdp[$i] <= 'z')) continue; if (($mdp[$i] >= '0') AND ($mdp[$i] <= '9')) continue; if ($mdp[$i] == '_') continue; if ($mdp[$i] == '-') continue; if ($mdp[$i] == '!') continue; if ($mdp[$i] == '*') continue; if ($mdp[$i] == '=') continue; if ($mdp[$i] == '.') continue; return(-3); } return(1); // if (preg_match($pattern, $mdp)) return(true); // else return(false); } //************************************************************************************************************ // Fonction : Dump de base de données // Reçoit : La BDD à dumper, la table concernée, le nom du fichier de sortie et le type de sortie attendu. Voir documentation de la fonction PHP 'mysqldump' pour détails). // Retour : La liste des champs //************************************************************************************************************ function Dump_bdd($bdd, $table, $fichier_sortie, $type_sortie) { // Appel de la fonction de DUMP : system('mysqldump --host='.BDD_HOST.' --user='.BDD_USER.' --password='.BDD_PASSWORD.' '.BDD_DATABASE.' --tables '.$table.' '.$type_sortie.' '.$fichier_sortie.' '); } //================================================================================================================== // Fonction : Création d'un fichier d'archive (compressé et encodé) à partir d'un répertoire // Reçoit : Le chemin complet du répertoire à archiver et le nom du fichier de sortie. // Retour : 0 si Ok, <0 si erreur //================================================================================================================== function creer_archive_chiffree(string $repertoire_a_chiffrer, string $fichier_sortie) { if (!is_dir($repertoire_a_chiffrer)) return (-1); $tarFile = $fichier_sortie . '.tar'; $gzFile = $tarFile . '.gz'; $encFile = $gzFile . '.enc'; foreach ([$tarFile, $gzFile] as $f) { if (file_exists($f)) { unlink($f); } } // 1. Archivage + compression (tar.gz) $phar = new PharData($tarFile); // $phar->buildFromDirectory($repertoire_a_chiffrer); $phar->buildFromDirectory("."); $phar->compress(Phar::GZ); unset($phar); unlink($tarFile); // 2. Chiffrement AES-256-CBC avec clé dérivée par PBKDF2 $contenu = file_get_contents($gzFile); $salt = openssl_random_pseudo_bytes(16); $iv = openssl_random_pseudo_bytes(16); $iterations = 100000; $cle = openssl_pbkdf2(BDD_BATEAU_PASSWORD, $salt, 32, $iterations, 'sha256'); $chiffre = openssl_encrypt($contenu, 'aes-256-cbc', $cle, OPENSSL_RAW_DATA, $iv); if ($chiffre === false) return (-2); // Format du fichier : salt(16) + iv(16) + données chiffrées file_put_contents($encFile, $salt . $iv . $chiffre); unlink($gzFile); return(0); } //================================================================================================================== // Fonction : // Reçoit : Le chemin complet du répertoire à archiver et le nom du fichier de sortie. // Retour : 0 si Ok, <0 si erreur //================================================================================================================== function dechiffrer_archive(string $fichierChiffre, string $dossierDestination, string $motDePasse) { $contenu = file_get_contents($fichierChiffre); $salt = substr($contenu, 0, 16); $iv = substr($contenu, 16, 16); $donnees = substr($contenu, 32); $iterations = 100000; $cle = openssl_pbkdf2($motDePasse, $salt, 32, $iterations, 'sha256'); $dechiffre = openssl_decrypt($donnees, 'aes-256-cbc', $cle, OPENSSL_RAW_DATA, $iv); if ($dechiffre === false) return (-1); if (!is_dir($dossierDestination)) mkdir($dossierDestination, 0755, true); $tmpGz = tempnam(sys_get_temp_dir(), 'restore_') . '.tar.gz'; file_put_contents($tmpGz, $dechiffre); $phar = new PharData($tmpGz); $phar->extractTo($dossierDestination, null, true); unlink($tmpGz); echo "Archive extraite dans : ".$dossierDestination."\n"; return (0); }