Files
ms1inscription-v5/ms1_kc_set.php
2026-05-28 15:33:51 -04:00

683 lines
22 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Outil temporaire : modifier key_chain_http pour un pk_key_chain.
* Accès 1 : /ms1_kc_set.php?k=<KEYCHAIN_HTTP_EDIT_SECRET>
* Accès 2 : compte connecté dont com_id est dans KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS
*/
$blnNoMaintenance = true;
session_start();
require_once __DIR__ . '/php/inc_fonctions.php';
header('X-Robots-Tag: noindex, nofollow');
header('Cache-Control: no-store, no-cache, must-revalidate');
global $objDatabase, $vDomaine;
function kc_set_allowed_com_ids()
{
if (!defined('KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS') || KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS === '') {
return [];
}
$arr = array_map('intval', explode(',', KEYCHAIN_HTTP_EDIT_ALLOWED_COM_IDS));
return array_values(array_filter($arr, function ($id) {
return $id > 0;
}));
}
function kc_set_com_id_authorized()
{
if (!isset($_SESSION['com_id']) || (int) $_SESSION['com_id'] <= 0) {
return false;
}
return in_array((int) $_SESSION['com_id'], kc_set_allowed_com_ids(), true);
}
$strSecret = isset($_GET['k']) ? (string) $_GET['k'] : '';
$blnAuthSecret = ($strSecret !== '' && hash_equals(KEYCHAIN_HTTP_EDIT_SECRET, $strSecret));
if ($blnAuthSecret) {
$_SESSION['kc_edit_auth_key'] = 1;
}
$blnAuthUser = kc_set_com_id_authorized();
$blnAuth = $blnAuthSecret || $blnAuthUser || !empty($_SESSION['kc_edit_auth_key']);
if (!$blnAuth) {
if (!isset($_SESSION['com_id']) && kc_set_allowed_com_ids() !== []) {
$_SESSION['redirect_after_login'] = $_SERVER['REQUEST_URI'];
header('Location: ' . $vDomaine . '/compte');
exit;
}
http_response_code(403);
echo '<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8"><title>Accès refusé</title></head><body>';
echo '<p>Accès refusé.</p>';
if (kc_set_allowed_com_ids() !== []) {
echo '<p><a href="' . htmlspecialchars($vDomaine . '/compte', ENT_QUOTES, 'UTF-8') . '">Se connecter</a></p>';
}
echo '</body></html>';
exit;
}
if (empty($_SESSION['kc_edit_csrf'])) {
$_SESSION['kc_edit_csrf'] = bin2hex(random_bytes(16));
}
$strCsrf = $_SESSION['kc_edit_csrf'];
$strBasePath = $_SERVER['PHP_SELF'];
function kc_set_page_url(array $params = [])
{
global $strBasePath;
$query = $params;
if (!empty($_SESSION['kc_edit_auth_key']) && !isset($query['k'])) {
$query = array_merge(['k' => KEYCHAIN_HTTP_EDIT_SECRET], $query);
}
$qs = http_build_query($query);
return $strBasePath . ($qs !== '' ? '?' . $qs : '');
}
$strPageUrl = kc_set_page_url();
$strBaseUrlHtml = htmlspecialchars($strPageUrl, ENT_QUOTES, 'UTF-8');
$blnCanShareLink = !empty($_SESSION['kc_edit_auth_key']);
$strShareUrl = '';
if ($blnCanShareLink) {
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$strShareUrl = $scheme . '://' . $_SERVER['HTTP_HOST'] . kc_set_page_url(['k' => KEYCHAIN_HTTP_EDIT_SECRET]);
}
$strUserName = '';
if ($blnAuthUser && !empty($_SESSION['com_prenom'])) {
$strUserName = trim((string) $_SESSION['com_prenom']);
} elseif ($blnAuthUser && !empty($_SESSION['com_info']['com_prenom'])) {
$strUserName = trim((string) $_SESSION['com_info']['com_prenom']);
}
$strMessage = '';
$strMessageClass = '';
$intPk = 0;
$strCurrentHttp = '';
$blnShowUrlForm = false;
$strVehiculeSaisi = '';
if (!empty($_GET['ok'])) {
$strMessage = 'Le lien de votre code QR a été enregistré. Vous pouvez modifier un autre véhicule ci-dessous.';
$strMessageClass = 'ok';
}
function kc_set_parse_vehicule_no($input)
{
$input = trim((string) $input);
if ($input === '' || !ctype_digit($input)) {
return 0;
}
$no = intval($input);
if ($no <= 0) {
return 0;
}
return $no + KEYCHAIN_HTTP_EDIT_SHIFT;
}
function kc_set_validate_url($url)
{
$url = trim($url);
if ($url === '') {
return false;
}
if (!filter_var($url, FILTER_VALIDATE_URL)) {
return false;
}
$parts = parse_url($url);
if (empty($parts['scheme']) || !in_array(strtolower($parts['scheme']), ['http', 'https'], true)) {
return false;
}
return $url;
}
function kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, $strNewHttp)
{
global $objDatabase, $strMessage, $strMessageClass, $strCurrentHttp, $blnShowUrlForm;
if ($strVehiculeSaisi !== '' && kc_set_parse_vehicule_no($strVehiculeSaisi) !== $intPk) {
$intPk = 0;
}
if ($intPk <= 0) {
$strMessage = 'Veuillez recommencer avec votre numéro de véhicule.';
$strMessageClass = 'err';
return false;
}
$sqlCheck = 'SELECT pk_key_chain FROM key_chain WHERE pk_key_chain = ' . $intPk;
if ($objDatabase->fxGetRow($sqlCheck) === null) {
$strMessage = 'Code QR introuvable. Vérifiez votre numéro de véhicule.';
$strMessageClass = 'err';
return false;
}
$sqlUpdate = "UPDATE key_chain SET key_chain_http = '" . $objDatabase->fxEscape($strNewHttp) . "' WHERE pk_key_chain = " . $intPk;
if ($objDatabase->fxQuery($sqlUpdate) === false) {
$strMessage = 'Impossible denregistrer pour le moment. Réessayez plus tard.';
$strMessageClass = 'err';
$blnShowUrlForm = true;
$strCurrentHttp = $strNewHttp;
return false;
}
header('Location: ' . kc_set_page_url(['ok' => '1']));
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$strPostedCsrf = isset($_POST['csrf']) ? (string) $_POST['csrf'] : '';
if (!hash_equals($strCsrf, $strPostedCsrf)) {
$strMessage = 'Veuillez recharger la page et réessayer.';
$strMessageClass = 'err';
} else {
$strAction = isset($_POST['action']) ? (string) $_POST['action'] : '';
if ($strAction === 'load') {
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
$intPk = kc_set_parse_vehicule_no($strVehiculeSaisi);
if ($intPk <= 0) {
$strMessage = 'Veuillez entrer un numéro de véhicule valide.';
$strMessageClass = 'err';
} else {
$sql = 'SELECT key_chain_http FROM key_chain WHERE pk_key_chain = ' . $intPk;
$row = $objDatabase->fxGetRow($sql);
if ($row === null || !isset($row['key_chain_http'])) {
$strMessage = 'Aucun code QR trouvé pour ce numéro de véhicule.';
$strMessageClass = 'err';
} else {
$strCurrentHttp = $row['key_chain_http'];
$blnShowUrlForm = true;
}
}
} elseif ($strAction === 'save') {
$intPk = intval(isset($_POST['pk']) ? $_POST['pk'] : 0);
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
$strLienPost = isset($_POST['lien_qr']) ? trim((string) $_POST['lien_qr']) : '';
$strNewHttp = kc_set_validate_url($strLienPost);
if ($strNewHttp === false) {
$strMessage = 'Veuillez entrer une adresse Web valide (commençant par http:// ou https://).';
$strMessageClass = 'err';
$blnShowUrlForm = true;
$strCurrentHttp = $strLienPost;
} else {
kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, $strNewHttp);
}
} elseif ($strAction === 'save_ms1') {
$intPk = intval(isset($_POST['pk']) ? $_POST['pk'] : 0);
$strVehiculeSaisi = isset($_POST['vehicule_no']) ? trim((string) $_POST['vehicule_no']) : '';
kc_set_save_lien_for_pk($intPk, $strVehiculeSaisi, 'https://ms1.ca');
}
}
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="robots" content="noindex, nofollow">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Code QR — lien de redirection</title>
<style>
:root {
--ms1-orange: #ff8c00;
--ms1-orange-dark: #e67a00;
--ms1-ink: #1a1a2e;
--ms1-card: #ffffff;
--ms1-muted: #5c6370;
--ms1-ok: #0d7a4a;
--ms1-err: #b42318;
--radius: 16px;
--shadow: 0 12px 40px rgba(26, 26, 46, 0.12);
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
color: var(--ms1-ink);
background:
radial-gradient(ellipse 80% 50% at 50% -10%, rgba(255, 140, 0, 0.25), transparent),
linear-gradient(160deg, #f8f4ef 0%, #eef2f7 45%, #e8edf5 100%);
padding: 1.5rem 1rem 3rem;
}
.page {
max-width: 640px;
margin: 0 auto;
animation: fadeUp 0.5s ease-out;
}
@keyframes fadeUp {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
.hero {
text-align: center;
margin-bottom: 1.5rem;
}
.qr-icon {
width: 56px;
height: 56px;
margin: 0 auto 0.75rem;
background: var(--ms1-ink);
border-radius: 12px;
padding: 10px;
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
box-shadow: 0 6px 20px rgba(26, 26, 46, 0.2);
}
.qr-icon span {
background: var(--ms1-orange);
border-radius: 2px;
}
.qr-icon span:nth-child(5) { background: #fff; }
h1 {
margin: 0;
font-size: 1.75rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.user-bar {
margin-top: 0.5rem;
color: var(--ms1-muted);
font-size: 1rem;
}
.intro {
text-align: center;
font-size: 1.08rem;
line-height: 1.6;
color: var(--ms1-muted);
margin: 0 0 1.5rem;
padding: 0 0.5rem;
}
.steps {
display: flex;
justify-content: center;
gap: 0.5rem;
margin-bottom: 1.25rem;
}
.step {
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.95rem;
background: #dde3eb;
color: var(--ms1-muted);
transition: transform 0.2s, background 0.2s;
}
.step.active {
background: var(--ms1-orange);
color: #fff;
transform: scale(1.08);
box-shadow: 0 4px 14px rgba(255, 140, 0, 0.45);
}
.step.done {
background: var(--ms1-ok);
color: #fff;
}
.step-line {
width: 2rem;
height: 3px;
align-self: center;
background: #dde3eb;
border-radius: 2px;
}
.card {
background: var(--ms1-card);
border-radius: var(--radius);
box-shadow: var(--shadow);
padding: 1.75rem 1.5rem 1.5rem;
border: 1px solid rgba(255, 255, 255, 0.8);
}
.field-label {
display: block;
font-weight: 700;
font-size: 1.05rem;
margin-bottom: 0.6rem;
color: var(--ms1-ink);
}
.field-wrap {
position: relative;
margin-bottom: 0.25rem;
}
.input-vehicule {
width: 100%;
padding: 1rem 1.15rem;
font-size: 1.75rem;
font-weight: 700;
text-align: center;
letter-spacing: 0.08em;
border: 2px solid #e2e8f0;
border-radius: 12px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.input-vehicule:focus {
outline: none;
border-color: var(--ms1-orange);
box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2);
}
.input-lien {
width: 100%;
padding: 1rem 1.15rem;
font-size: 1.05rem;
line-height: 1.45;
border: 2px solid #e2e8f0;
border-radius: 12px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.input-lien:focus {
outline: none;
border-color: var(--ms1-orange);
box-shadow: 0 0 0 4px rgba(255, 140, 0, 0.2);
}
.input-lien::placeholder {
color: #9aa3af;
font-family: inherit;
}
.actions {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem 1rem;
margin-top: 1.25rem;
}
.btn-enter {
display: inline-flex;
align-items: center;
gap: 0.55rem;
padding: 0.85rem 1.5rem;
font-size: 1.05rem;
font-weight: 700;
color: #fff;
background: linear-gradient(180deg, var(--ms1-orange) 0%, var(--ms1-orange-dark) 100%);
border: none;
border-radius: 999px;
cursor: pointer;
box-shadow: 0 6px 20px rgba(255, 140, 0, 0.4);
transition: transform 0.15s, box-shadow 0.15s;
}
.btn-enter:hover {
transform: translateY(-2px);
box-shadow: 0 10px 28px rgba(255, 140, 0, 0.5);
}
.btn-enter:active {
transform: translateY(0);
}
.btn-ms1 {
display: inline-flex;
align-items: center;
padding: 0.85rem 1.25rem;
font-size: 1rem;
font-weight: 700;
color: var(--ms1-ink);
background: #fff;
border: 2px solid var(--ms1-ink);
border-radius: 999px;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.btn-ms1:hover {
background: var(--ms1-ink);
color: #fff;
}
.btn-enter:disabled {
opacity: 0.85;
cursor: wait;
transform: none;
}
.btn-enter .key-cap {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 2rem;
height: 1.75rem;
padding: 0 0.4rem;
background: rgba(255, 255, 255, 0.25);
border-radius: 6px;
font-size: 0.9rem;
border: 1px solid rgba(255, 255, 255, 0.35);
}
.hint {
color: var(--ms1-muted);
font-size: 0.9rem;
margin: 0;
}
.msg {
margin: 0 0 1.25rem;
padding: 1rem 1.15rem;
border-radius: 12px;
font-size: 1rem;
font-weight: 500;
animation: fadeUp 0.35s ease-out;
}
.msg.ok {
background: #e6f4ed;
color: var(--ms1-ok);
border: 1px solid #b8e6d0;
}
.msg.err {
background: #fdecea;
color: var(--ms1-err);
border: 1px solid #f5c4c0;
}
.back {
text-align: center;
margin-top: 1.5rem;
}
.back a {
color: var(--ms1-muted);
text-decoration: none;
font-weight: 600;
padding: 0.5rem 1rem;
border-radius: 8px;
transition: color 0.2s, background 0.2s;
}
.back a:hover {
color: var(--ms1-orange-dark);
background: rgba(255, 140, 0, 0.1);
}
.share-box {
background: #fff8ee;
border: 1px dashed var(--ms1-orange);
border-radius: 12px;
padding: 1rem 1.15rem;
margin-bottom: 1.25rem;
}
.share-box strong {
display: block;
margin-bottom: 0.5rem;
font-size: 0.95rem;
}
.share-row {
display: flex;
gap: 0.5rem;
flex-wrap: wrap;
}
.share-url {
flex: 1 1 12rem;
min-width: 0;
padding: 0.55rem 0.65rem;
font-size: 0.82rem;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #fff;
}
.btn-copy {
padding: 0.55rem 1rem;
font-weight: 600;
font-size: 0.9rem;
border: none;
border-radius: 8px;
background: var(--ms1-ink);
color: #fff;
cursor: pointer;
}
.btn-copy:hover { background: #2d2d44; }
@media (max-width: 480px) {
.actions { flex-direction: column; align-items: stretch; }
.btn-enter { justify-content: center; }
}
</style>
</head>
<body>
<div class="page">
<header class="hero">
<div class="qr-icon" aria-hidden="true">
<span></span><span></span><span></span>
<span></span><span></span><span></span>
<span></span><span></span><span></span>
</div>
<h1>Code QR</h1>
<?php if ($strUserName !== '') { ?>
<p class="user-bar">Bonjour <?php echo htmlspecialchars($strUserName, ENT_QUOTES, 'UTF-8'); ?>.</p>
<?php } ?>
</header>
<p class="intro">Entrez votre numéro de véhicule. Vous pourrez ainsi changer le lien de votre code QR.</p>
<?php if ($blnCanShareLink && $strShareUrl !== '') { ?>
<div class="share-box">
<strong>Lien à envoyer aux autres</strong>
<p class="hint" style="margin:0 0 0.65rem;">Chaque personne ouvre ce lien et entre <em>son</em> numéro de véhicule.</p>
<div class="share-row">
<input type="text" class="share-url" id="share_url" readonly value="<?php echo htmlspecialchars($strShareUrl, ENT_QUOTES, 'UTF-8'); ?>">
<button type="button" class="btn-copy" id="btn_copy_link">Copier le lien</button>
</div>
</div>
<?php } ?>
<div class="steps" aria-hidden="true">
<span class="step <?php echo !$blnShowUrlForm ? 'active' : 'done'; ?>">1</span>
<span class="step-line"></span>
<span class="step <?php echo $blnShowUrlForm ? 'active' : ''; ?>">2</span>
</div>
<?php if ($strMessage !== '') { ?>
<div class="msg <?php echo htmlspecialchars($strMessageClass, ENT_QUOTES, 'UTF-8'); ?>" role="status"><?php
echo htmlspecialchars($strMessage, ENT_QUOTES, 'UTF-8');
?></div>
<?php } ?>
<div class="card">
<?php if (!$blnShowUrlForm) { ?>
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" id="frm_load">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="load">
<label class="field-label" for="vehicule_no">Numéro de véhicule</label>
<div class="field-wrap">
<input type="text" inputmode="numeric" pattern="[0-9]+" class="input-vehicule" id="vehicule_no" name="vehicule_no" required autofocus placeholder="ex. 8" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="actions">
<button type="submit" class="btn-enter">
<span class="key-cap">↵</span>
<span>Continuer</span>
</button>
<p class="hint">Remplissez le numéro, puis cliquez ou appuyez sur Entrée.</p>
</div>
</form>
<?php } else { ?>
<?php if ($strVehiculeSaisi !== '') { ?>
<p class="hint" style="margin:0 0 1rem;">Véhicule <strong><?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?></strong></p>
<?php } ?>
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" id="frm_save">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="save">
<input type="hidden" name="pk" value="<?php echo (int) $intPk; ?>">
<input type="hidden" name="vehicule_no" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
<label class="field-label" for="lien_qr">Lien de votre code QR</label>
<div class="field-wrap">
<input type="url" class="input-lien" id="lien_qr" name="lien_qr" required autofocus placeholder="https://..." value="<?php echo htmlspecialchars($strCurrentHttp, ENT_QUOTES, 'UTF-8'); ?>">
</div>
<div class="actions">
<button type="submit" class="btn-enter">
<span class="key-cap">↵</span>
<span>Enregistrer</span>
</button>
<p class="hint">Ou enregistrer directement le lien par défaut :</p>
</div>
</form>
<form method="post" action="<?php echo $strBaseUrlHtml; ?>" style="margin-top:0.75rem;">
<input type="hidden" name="csrf" value="<?php echo htmlspecialchars($strCsrf, ENT_QUOTES, 'UTF-8'); ?>">
<input type="hidden" name="action" value="save_ms1">
<input type="hidden" name="pk" value="<?php echo (int) $intPk; ?>">
<input type="hidden" name="vehicule_no" value="<?php echo htmlspecialchars($strVehiculeSaisi, ENT_QUOTES, 'UTF-8'); ?>">
<button type="submit" class="btn-ms1">Mettre le lien vers ms1.ca</button>
</form>
<p class="hint" style="margin-top:0.75rem;">Sinon modifiez ladresse ci-dessus et appuyez sur Entrée pour enregistrer.</p>
<?php } ?>
</div>
<?php if ($blnShowUrlForm) { ?>
<p class="back"><a href="<?php echo $strBaseUrlHtml; ?>">← Autre numéro de véhicule</a></p>
<?php } ?>
</div>
<?php if ($blnCanShareLink && $strShareUrl !== '') { ?>
<script>
(function () {
var btn = document.getElementById('btn_copy_link');
var input = document.getElementById('share_url');
if (!btn || !input) return;
btn.addEventListener('click', function () {
input.select();
input.setSelectionRange(0, 99999);
var ok = false;
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(input.value).then(function () { ok = true; });
}
try { ok = document.execCommand('copy') || ok; } catch (e) {}
btn.textContent = ok ? 'Copié !' : 'Sélectionné — Ctrl+C';
setTimeout(function () { btn.textContent = 'Copier le lien'; }, 2000);
});
})();
</script>
<?php } ?>
</body>
</html>