Files
ms1inscription-v5/php/sync_static_db.php
stephan c7482016ce Implement superadmin login redirection and session handling improvements
This commit introduces a new function, `fxSuperadmRedirectToLoginIfNeeded`, to streamline the login redirection process for superadmin users. It enhances session management by checking for user authentication and allowing legacy account access under specific conditions. Additionally, the login flow is updated to ensure users are redirected appropriately after login, improving the overall security and user experience in the superadmin interface. These changes aim to enhance maintainability and clarity in session handling across various superadmin pages.
2026-07-07 14:15:48 -04:00

295 lines
13 KiB
PHP

<?php
/**
* Tableau de bord sync tables statiques — préprod dev, superadm seulement.
* Source : devinscription_preprod
*/
require_once('inc_start_time.php');
require_once('inc_fonctions.php');
require_once('inc_fx_messages.php');
require_once('inc_fx_static_sync.php');
if (empty($_SESSION['usa_id'])) {
fxAdminRequireSuperadmLogin();
}
if (!fxAdminStaticSyncAllowed()) {
header('HTTP/1.1 403 Forbidden');
echo 'Accès refusé.';
exit;
}
set_time_limit(300);
function ssEsc($str) {
return htmlspecialchars((string)$str, ENT_QUOTES, 'UTF-8');
}
$strCsrf = fxStaticSyncEnsureCsrfToken();
$strFlash = '';
$strFlashType = 'info';
$tabPopFlash = fxStaticSyncPopFlash();
if (is_array($tabPopFlash)) {
$strFlash = $tabPopFlash['message'];
$strFlashType = $tabPopFlash['type'];
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'sync') {
if (!fxStaticSyncValidateCsrf($_POST['csrf'] ?? '')) {
fxStaticSyncSetFlash('Jeton CSRF invalide.', 'bad');
} else {
$strTable = trim($_POST['table'] ?? '');
$strEnvId = trim($_POST['env'] ?? '');
$tabDef = fxStaticSyncFindTableDef($strTable);
$tabEnv = fxStaticSyncFindEnvDef($strEnvId);
if (!$tabDef || !$tabEnv || !empty($tabEnv['is_source'])) {
fxStaticSyncSetFlash('Paramètres invalides.', 'bad');
} else {
$tabConnections = fxStaticSyncOpenConnections();
$objSource = $tabConnections['dev_preprod'];
$objTarget = $tabConnections[$strEnvId];
if (!$objSource || !$objTarget) {
fxStaticSyncSetFlash(
'Connexion BD impossible — ' . fxStaticSyncFormatConnectionError($tabEnv),
'bad'
);
} else {
$tabResult = fxStaticSyncCopyTable($objSource, $objTarget, $strTable, $tabDef);
if ($tabResult['ok']) {
$tabVerify = fxStaticSyncCompareEnvPair($objSource, $objTarget, $tabDef);
$strMsg = $tabDef['label'] . ' → ' . $tabEnv['label'] . ' : ' . $tabResult['message'];
if ($tabVerify['status'] === 'ok') {
$strMsg .= ' Vérification : aligné.';
fxStaticSyncSetFlash($strMsg, 'ok');
} else {
$strMsg .= ' ATTENTION — après sync : '
. fxStaticSyncStatusLabel($tabVerify['status'], $tabVerify) . '.';
fxStaticSyncSetFlash($strMsg, 'bad');
}
} else {
fxStaticSyncSetFlash(
$tabDef['label'] . ' → ' . $tabEnv['label'] . ' — échec : ' . $tabResult['message'],
'bad'
);
}
}
}
}
header('Location: sync_static_db.php#sync-result');
exit;
}
$tabConnections = fxStaticSyncOpenConnections();
$tabEnvs = fxStaticSyncEnvironmentDefinitions();
$tabReport = fxStaticSyncBuildReport($tabConnections);
$strDetailTable = trim($_GET['detail_table'] ?? '');
$strDetailEnv = trim($_GET['detail_env'] ?? '');
$tabDetail = null;
if ($strDetailTable !== '' && $strDetailEnv !== '') {
$tabDetail = fxStaticSyncGetDiffDetail($strDetailTable, $strDetailEnv, $tabConnections);
}
?><!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Sync tables statiques</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; background: #f4f6f8; color: #222; }
h1 { font-size: 1.4rem; margin: 0 0 8px; }
.sub { color: #555; margin-bottom: 20px; font-size: 0.95rem; }
.flash { padding: 10px 14px; border-radius: 6px; margin-bottom: 16px; white-space: pre-wrap; word-break: break-word; }
.flash-ok { background: #d4edda; border: 1px solid #b7dfc3; }
.flash-bad { background: #f8d7da; border: 1px solid #f1b8be; }
.flash-info { background: #e8f0fe; border: 1px solid #c5d7fb; }
.warn-box { background: #fff3cd; border: 1px solid #ffecb5; padding: 12px 14px; border-radius: 6px; margin-bottom: 16px; font-size: 0.9rem; }
.warn-box strong { color: #856404; }
table { width: 100%; border-collapse: collapse; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.08); }
th, td { border: 1px solid #ddd; padding: 8px 10px; vertical-align: top; font-size: 0.9rem; }
th { background: #eef2f7; text-align: left; }
.ss-ok { background: #d4edda; color: #155724; }
.ss-warn { background: #fff3cd; color: #856404; }
.ss-bad { background: #f8d7da; color: #721c24; }
.ss-muted { background: #e9ecef; color: #495057; }
.ss-schema { background: #fde2e2; color: #7f1d1d; border: 1px solid #f5c2c2; }
.badge { display: inline-block; padding: 3px 8px; border-radius: 4px; font-size: 0.82rem; font-weight: 600; max-width: 100%; line-height: 1.35; }
.count { font-size: 0.82rem; color: #444; margin-top: 4px; }
.count-hint { font-size: 0.78rem; color: #666; }
.btn { display: inline-block; margin-top: 6px; padding: 4px 10px; font-size: 0.82rem; border: 1px solid #888; background: #fff; border-radius: 4px; cursor: pointer; text-decoration: none; color: #222; }
.btn:hover { background: #f0f0f0; }
.btn-sync { border-color: #2e6da4; color: #1a4f7a; }
.detail-box { margin-top: 24px; background: #fff; padding: 16px; border: 1px solid #ccc; border-radius: 6px; }
.detail-box h2 { margin-top: 0; font-size: 1.1rem; }
.detail-list { margin: 0; padding-left: 18px; }
.detail-list li { margin-bottom: 8px; }
.legend { margin: 16px 0; font-size: 0.85rem; }
.legend span { display: inline-block; margin-right: 12px; padding: 2px 8px; border-radius: 4px; }
code { background: #f1f1f1; padding: 1px 4px; border-radius: 3px; }
</style>
</head>
<body>
<h1>Sync tables statiques</h1>
<div class="warn-box">
<strong>Attention — opération destructive.</strong>
Sync = recopie complète depuis dev préprod (efface la cible). Un clic sur Sync.
</div>
<p class="sub">
Source de vérité : <strong>dev préprod</strong> (<code><?php echo ssEsc($arrConDatabasePreProd['db'] ?? ''); ?></code>).
Comparaison vers dev prod, client préprod et client prod.
</p>
<div id="sync-result"></div>
<?php if ($strFlash !== '') { ?>
<div class="flash flash-<?php echo ssEsc($strFlashType); ?>"><?php echo ssEsc($strFlash); ?></div>
<?php } ?>
<div class="legend">
<span class="ss-ok">Données alignées</span>
<span class="ss-warn">Il en manque X</span>
<span class="ss-bad">Il y en a X en trop</span>
<span class="ss-warn">Contenu différent</span>
<span class="ss-schema">Structures non alignées</span>
<span class="ss-muted">Table absente / connexion</span>
</div>
<table>
<thead>
<tr>
<th>Table</th>
<th>Source<br><small><?php echo ssEsc($tabEnvs['dev_preprod']['config']['db'] ?? ''); ?></small></th>
<?php foreach ($tabEnvs as $strEnvId => $tabEnv) {
if (!empty($tabEnv['is_source'])) {
continue;
} ?>
<th><?php echo ssEsc($tabEnv['label']); ?><br><small><?php echo ssEsc($tabEnv['config']['db'] ?? ''); ?></small></th>
<?php } ?>
</tr>
</thead>
<tbody>
<?php foreach ($tabReport as $tabRow) {
$tabDef = $tabRow['def']; ?>
<tr>
<td>
<strong><?php echo ssEsc($tabDef['label']); ?></strong><br>
<code><?php echo ssEsc($tabDef['table']); ?></code>
</td>
<td class="ss-muted">
<span class="badge"><?php echo (int)$tabRow['source_count']; ?> ligne(s)</span>
<?php if (!empty($tabRow['source_dupes'])) { ?>
<div class="count-hint"><?php echo (int)$tabRow['source_dupes']; ?> doublon(s) clé en source</div>
<?php } ?>
</td>
<?php foreach ($tabEnvs as $strEnvId => $tabEnv) {
if (!empty($tabEnv['is_source'])) {
continue;
}
$tabCmp = isset($tabRow['envs'][$strEnvId]) ? $tabRow['envs'][$strEnvId] : null;
if (!$tabCmp) {
continue;
}
$strClass = fxStaticSyncStatusClass($tabCmp['status']);
$strLabel = fxStaticSyncStatusLabel($tabCmp['status'], $tabCmp);
?>
<td class="<?php echo ssEsc($strClass); ?>">
<span class="badge"><?php echo ssEsc($strLabel); ?></span>
<div class="count">
Cible <?php echo (int)$tabCmp['target_count']; ?> · Source <?php echo (int)$tabCmp['source_count']; ?>
</div>
<?php if ($tabCmp['status'] === 'schema_mismatch') {
$tabSchemaDiff = array(
'missing_in_target' => isset($tabCmp['schema_missing_cols']) ? $tabCmp['schema_missing_cols'] : array(),
'extra_in_target' => isset($tabCmp['schema_extra_cols']) ? $tabCmp['schema_extra_cols'] : array(),
);
$strSchemaDiff = fxStaticSyncFormatSchemaDiff($tabSchemaDiff);
if ($strSchemaDiff !== '') { ?>
<div class="count"><?php echo ssEsc($strSchemaDiff); ?></div>
<?php } } ?>
<?php if ($tabCmp['status'] !== 'ok' && $tabCmp['status'] !== 'no_connection') { ?>
<a class="btn" href="?detail_table=<?php echo urlencode($tabDef['table']); ?>&amp;detail_env=<?php echo urlencode($strEnvId); ?>">Détails</a>
<?php } ?>
<?php if ($tabCmp['status'] === 'no_connection') {
$strConnErr = fxStaticSyncConnectError($tabEnv['config']['db'] ?? '');
if ($strConnErr !== '') { ?>
<div class="count-hint"><?php echo ssEsc($strConnErr); ?></div>
<?php } } ?>
<?php if ($tabCmp['status'] !== 'no_connection' && $tabCmp['status'] !== 'schema_mismatch') { ?>
<form method="post" style="display:inline;">
<input type="hidden" name="action" value="sync">
<input type="hidden" name="csrf" value="<?php echo ssEsc($strCsrf); ?>">
<input type="hidden" name="table" value="<?php echo ssEsc($tabDef['table']); ?>">
<input type="hidden" name="env" value="<?php echo ssEsc($strEnvId); ?>">
<button type="submit" class="btn btn-sync">Sync →</button>
</form>
<?php } ?>
</td>
<?php } ?>
</tr>
<?php } ?>
</tbody>
</table>
<?php if (is_array($tabDetail) && !empty($tabDetail['compare'])) {
$tabCmp = $tabDetail['compare'];
$tabDef = fxStaticSyncFindTableDef($strDetailTable);
$tabEnv = fxStaticSyncFindEnvDef($strDetailEnv);
?>
<div class="detail-box">
<h2>Détails — <?php echo ssEsc($tabDef['label'] ?? $strDetailTable); ?> → <?php echo ssEsc($tabEnv['label'] ?? $strDetailEnv); ?></h2>
<p>
<?php
$intDelta = (int)$tabCmp['target_count'] - (int)$tabCmp['source_count'];
if ($intDelta < 0) {
echo 'Il en manque ' . abs($intDelta) . ' (cible ' . (int)$tabCmp['target_count']
. ' · source ' . (int)$tabCmp['source_count'] . ')';
} elseif ($intDelta > 0) {
echo 'Il y en a ' . $intDelta . ' en trop (cible ' . (int)$tabCmp['target_count']
. ' · source ' . (int)$tabCmp['source_count'] . ')';
} else {
echo 'Même nombre de lignes, contenu différent (cible ' . (int)$tabCmp['target_count']
. ' · source ' . (int)$tabCmp['source_count'] . ')';
}
?>
<?php if ($tabCmp['status'] === 'schema_mismatch') {
$tabSchemaDiff = array(
'missing_in_target' => isset($tabCmp['schema_missing_cols']) ? $tabCmp['schema_missing_cols'] : array(),
'extra_in_target' => isset($tabCmp['schema_extra_cols']) ? $tabCmp['schema_extra_cols'] : array(),
);
$strSchemaDiff = fxStaticSyncFormatSchemaDiff($tabSchemaDiff);
if ($strSchemaDiff !== '') { ?>
<br><?php echo ssEsc($strSchemaDiff); ?>
<?php } } ?>
<a class="btn" href="sync_static_db.php" style="margin-left:12px;">Fermer</a>
</p>
<?php if (!empty($tabDetail['samples'])) { ?>
<ul class="detail-list">
<?php foreach ($tabDetail['samples'] as $tabSample) { ?>
<li>
<strong><?php echo ssEsc(fxStaticSyncFormatKeyPreview($tabSample['key'])); ?></strong>
(<?php
echo ssEsc($tabSample['type'] === 'extra' ? 'en trop'
: ($tabSample['type'] === 'missing' ? 'manque' : 'contenu diff.'));
?>)
<?php if ($tabDef['table'] === 'info' && $tabSample['type'] === 'diff') { ?>
<br>Source : <em><?php echo ssEsc($tabSample['source_texte']); ?></em>
<br>Cible : <em><?php echo ssEsc($tabSample['target_texte']); ?></em>
<?php } ?>
</li>
<?php } ?>
</ul>
<?php } else { ?>
<p>Aucun écart à afficher.</p>
<?php } ?>
</div>
<?php } ?>
</body>
</html>