249 lines
13 KiB
PHP
249 lines
13 KiB
PHP
<?php
|
|
// ============================================================================
|
|
// cron_quarantaine.php - Réexamen périodique des archives en quarantaine
|
|
// (MMSI divergent, ou aucune affectation active - cf synthèse §38-39).
|
|
// Exécuté manuellement ou via cron, après qu'un administrateur ait mis à jour
|
|
// les données concernées (TB_Bateaux.MMSI, TB_Affectations_bateaux) :
|
|
// /usr/bin/php /var/www/cron_quarantaine.php
|
|
//
|
|
// Ne retente PAS automatiquement : parcourt les fichiers du répertoire de
|
|
// quarantaine, et pour chacun, relit sa ligne TB_Archives_traitees existante
|
|
// (jamais une nouvelle ligne - une UPDATE, contrairement à
|
|
// cron_archivage.php) puis retente la résolution (affectation, puis MMSI).
|
|
// Si la cause est levée : traitement complet, identique à cron_archivage.php
|
|
// à partir de ce point. Sinon : le fichier reste en quarantaine, rien n'est
|
|
// modifié, nouvelle tentative au prochain lancement.
|
|
// ============================================================================
|
|
|
|
// Même précaution que cron_archivage.php : certains fichiers inclus utilisent des chemins relatifs,
|
|
// résolus par rapport au répertoire de travail - imprévisible pour une tâche planifiée.
|
|
chdir("/var/www/html");
|
|
|
|
require_once __DIR__ . "/config/config.php";
|
|
require_once __DIR__ . "/config/fonctions_bdd.php";
|
|
require_once __DIR__ . "/fonctions_archivage.php";
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Relit une ligne TB_Archives_traitees encore en attente (Date_resolution
|
|
// IS NULL - donc nécessairement un des deux statuts de quarantaine) pour ce
|
|
// nom de fichier. Renvoie null si introuvable (incohérence à examiner
|
|
// manuellement : un fichier en quarantaine devrait toujours avoir sa ligne).
|
|
// ----------------------------------------------------------------------------
|
|
function Lire_ligne_en_attente($db, $nom_fichier)
|
|
{
|
|
$requete = "SELECT Statut FROM TB_Archives_traitees WHERE Nom_fichier=? AND Date_resolution IS NULL";
|
|
$stmt = $db->prepare($requete);
|
|
$stmt->bind_param('s', $nom_fichier);
|
|
$stmt->execute();
|
|
$stmt->bind_result($statut);
|
|
$trouve = $stmt->fetch();
|
|
$stmt->close();
|
|
if (!$trouve) return null;
|
|
return ['statut' => $statut];
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Met à jour une ligne TB_Archives_traitees existante (contrairement à
|
|
// cron_archivage.php, qui en crée toujours une nouvelle) - la ligne de
|
|
// quarantaine, créée au moment de la mise en attente, est ici tranchée
|
|
// définitivement (cf synthèse §39).
|
|
// ----------------------------------------------------------------------------
|
|
function Trancher_archive_en_attente($db, $nom_fichier, $id_bateau_final, $id_generation, $statut, $detail_erreur = null, $mmsi_recu = null, $mmsi_attendu = null)
|
|
{
|
|
// MMSI_recu/MMSI_attendu ne sont mis à jour QUE si connus à cet appel (une archive mise en quarantaine
|
|
// 'sans_affectation' n'avait pas encore de MMSI à comparer) - sinon, on conserve les valeurs déjà
|
|
// enregistrées au moment de la mise en quarantaine initiale, plutôt que de les écraser par NULL
|
|
// (cf synthèse §39) :
|
|
if ($mmsi_recu !== null)
|
|
{
|
|
$requete = "UPDATE TB_Archives_traitees
|
|
SET ID_Bateau_final=?, ID_Generation=?, Statut=?, Detail_erreur=?, MMSI_recu=?, MMSI_attendu=?, Date_resolution=NOW()
|
|
WHERE Nom_fichier=?";
|
|
$stmt = $db->prepare($requete);
|
|
$stmt->bind_param('iisssss', $id_bateau_final, $id_generation, $statut, $detail_erreur, $mmsi_recu, $mmsi_attendu, $nom_fichier);
|
|
}
|
|
else
|
|
{
|
|
$requete = "UPDATE TB_Archives_traitees
|
|
SET ID_Bateau_final=?, ID_Generation=?, Statut=?, Detail_erreur=?, Date_resolution=NOW()
|
|
WHERE Nom_fichier=?";
|
|
$stmt = $db->prepare($requete);
|
|
$stmt->bind_param('iisss', $id_bateau_final, $id_generation, $statut, $detail_erreur, $nom_fichier);
|
|
}
|
|
$ok = $stmt->execute();
|
|
$stmt->close();
|
|
return $ok;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Reconstruit l'adresse MAC (format XX:XX:XX:XX:XX:XX) à partir des 12
|
|
// premiers caractères hexadécimaux du nom de fichier.
|
|
// ----------------------------------------------------------------------------
|
|
function Adresse_mac_depuis_nom($nom_fichier)
|
|
{
|
|
preg_match('/^([0-9A-Fa-f]{12})_/', $nom_fichier, $m);
|
|
return implode(':', str_split(strtoupper($m[1]), 2));
|
|
}
|
|
|
|
function Executer_cron_quarantaine()
|
|
{
|
|
Ouverture_bdd("127.0.0.1:3307", BDD_USER, BDD_PASSWORD, BDD_DATABASE);
|
|
$db = $_SESSION['db'];
|
|
|
|
if (!is_dir(REPERTOIRE_QUARANTAINE))
|
|
{
|
|
echo "Répertoire de quarantaine introuvable (" . REPERTOIRE_QUARANTAINE . ") - rien à faire.\n";
|
|
Fermeture_bdd();
|
|
return;
|
|
}
|
|
|
|
$fichiers = array_values(array_filter(scandir(REPERTOIRE_QUARANTAINE),
|
|
fn($f) => preg_match('/^[0-9A-Fa-f]{12}_\d{6}_\d{6}_[0-9A-Fa-f]{16}\.sql\.gz\.enc$/', $f)));
|
|
echo count($fichiers) . " archive(s) en quarantaine à réexaminer.\n\n";
|
|
|
|
foreach ($fichiers as $nom)
|
|
{
|
|
$chemin = REPERTOIRE_QUARANTAINE . "/" . $nom;
|
|
|
|
$adresse_mac = Adresse_mac_depuis_nom($nom);
|
|
$verrou = Verrouiller_boitier($adresse_mac);
|
|
if (!$verrou['ok'])
|
|
{
|
|
echo " - {$nom} : " . $verrou['raison'] . " - réexamen au prochain passage.\n";
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
$ligne = Lire_ligne_en_attente($db, $nom);
|
|
if ($ligne === null)
|
|
{
|
|
echo " - {$nom} : aucune ligne TB_Archives_traitees en attente trouvée - incohérence, à examiner manuellement.\n";
|
|
continue;
|
|
}
|
|
|
|
$contenu_chiffre = file_get_contents($chemin);
|
|
|
|
$affectation = Resoudre_affectation_active($db, $adresse_mac);
|
|
if (!$affectation['existe'])
|
|
{
|
|
echo " - {$nom} : toujours aucune affectation active - reste en quarantaine.\n";
|
|
continue;
|
|
}
|
|
$id_bateau = $affectation['id_bateau'];
|
|
|
|
$dechiffrement = Decrypter_archive($contenu_chiffre);
|
|
if (!$dechiffrement['ok'])
|
|
{
|
|
// Un échec de déchiffrement ne se résoudra pas en attendant (contrairement à l'affectation ou
|
|
// au MMSI, qui dépendent d'une action administrative future) - rejet direct, comme
|
|
// cron_archivage.php (cf synthèse §38) :
|
|
echo " - {$nom} : ÉCHEC de déchiffrement (" . $dechiffrement['raison'] . ") - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Échec de déchiffrement : " . $dechiffrement['raison']);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
|
|
$mmsi_recu = $dechiffrement['entete']['No_mmsi'] ?? null;
|
|
$mmsi_attendu_connu = null;
|
|
if ($mmsi_recu !== null)
|
|
{
|
|
$verification_mmsi = Verifier_mmsi($db, $id_bateau, $mmsi_recu);
|
|
$mmsi_attendu_connu = $verification_mmsi['attendu'];
|
|
if ($verification_mmsi['statut'] === 'quarantaine')
|
|
{
|
|
echo " - {$nom} : MMSI toujours divergent ({$mmsi_recu} / {$verification_mmsi['attendu']}) - reste en quarantaine.\n";
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// La cause de la quarantaine est levée : traitement complet, même déroulé que cron_archivage.php :
|
|
$origine_bdd = $dechiffrement['entete']['Origine_bdd'] ?? 'normale';
|
|
$version_cible = $dechiffrement['entete']['Version_soft_no_package'] ?? null;
|
|
$generation_active = Resoudre_generation_active($db, $id_bateau);
|
|
$nouvelle_generation = Nouvelle_generation_necessaire($origine_bdd, $generation_active);
|
|
|
|
$fichier_sql = Resoudre_fichier_sql($db, $version_cible);
|
|
if ($fichier_sql === false)
|
|
{
|
|
echo " - {$nom} : version logicielle '{$version_cible}' inconnue de TB_Versions - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Version logicielle '{$version_cible}' inconnue de TB_Versions", $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
$contenu_fichier_sql = @file_get_contents(REPERTOIRE_VERSIONS_SQL . "/" . $fichier_sql);
|
|
if ($contenu_fichier_sql === false)
|
|
{
|
|
echo " - {$nom} : fichier {$fichier_sql} introuvable sur le VPS - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Fichier {$fichier_sql} introuvable sur le VPS", $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
|
|
if ($nouvelle_generation)
|
|
{
|
|
$zone_usine = Extraire_zone_usine($contenu_fichier_sql);
|
|
if ($zone_usine === false)
|
|
{
|
|
echo " - {$nom} : marqueur Factory_structure introuvable dans {$fichier_sql} - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Marqueur Factory_structure introuvable dans {$fichier_sql}", $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
$motif = ($origine_bdd === 'factory' || $origine_bdd === 'restauration') ? $origine_bdd : 'creation_initiale';
|
|
$resultat_generation = Creer_generation($db, $id_bateau, $motif, $zone_usine, $version_cible);
|
|
if (!$resultat_generation['ok'])
|
|
{
|
|
echo " - {$nom} : échec de création de génération : " . $resultat_generation['raison'] . " - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Échec de création de génération : " . $resultat_generation['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
$nom_base_cible = $resultat_generation['nom_base'];
|
|
}
|
|
else
|
|
{
|
|
$nom_base_cible = $generation_active['nom_base'];
|
|
// Même migration préalable que cron_archivage.php (synthèse §46) :
|
|
$migration = Migrer_generation($db, $generation_active, $version_cible, $fichier_sql, $contenu_fichier_sql);
|
|
if (!$migration['ok'])
|
|
{
|
|
echo " - {$nom} : " . $migration['raison'] . " - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', $migration['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$chargement = Charger_contenu_archive($nom_base_cible, $dechiffrement['sql']);
|
|
if (!$chargement['ok'])
|
|
{
|
|
echo " - {$nom} : échec de chargement dans {$nom_base_cible} : " . $chargement['raison'] . " - rejetée.\n";
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, null, 'rejetee', "Échec de chargement dans {$nom_base_cible} : " . $chargement['raison'], $mmsi_recu, $mmsi_attendu_connu);
|
|
if (!is_dir(REPERTOIRE_ERREURS)) @mkdir(REPERTOIRE_ERREURS, 0750, true);
|
|
rename($chemin, REPERTOIRE_ERREURS . "/" . $nom);
|
|
continue;
|
|
}
|
|
|
|
$generation_pour_enregistrement = Resoudre_generation_active($db, $id_bateau);
|
|
Trancher_archive_en_attente($db, $nom, $id_bateau, $generation_pour_enregistrement['cle'], 'traitee', null, $mmsi_recu, $mmsi_attendu_connu);
|
|
unlink($chemin);
|
|
echo " - {$nom} : quarantaine levée, chargée dans {$nom_base_cible}.\n";
|
|
}
|
|
finally
|
|
{
|
|
Liberer_boitier($verrou['poignee']);
|
|
}
|
|
}
|
|
|
|
Fermeture_bdd();
|
|
}
|
|
|
|
Executer_cron_quarantaine();
|