| Current Path : /home/h/a/p/happyrenas/find.myreco.online/public/ |
Linux webd005.cluster105.gra.hosting.ovh.net 5.15.206-ovh-vps-grsec-zfs-classid #1 SMP Fri May 15 02:41:25 UTC 2026 x86_64 |
| Current File : /home/h/a/p/happyrenas/find.myreco.online/public/dispo.php |
<?php
declare(strict_types=1);
header('Content-Type: text/html; charset=utf-8');
session_start();
require_once __DIR__ . '/../configuration.php';
require_once __DIR__ . '/../includes/fonctions.php';
/* ------------------------------------------------------------
Helpers
------------------------------------------------------------ */
function page_exit(string $message, int $code = 200): void
{
http_response_code($code);
echo '<!doctype html><html lang="fr"><head>';
echo '<meta charset="utf-8">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<title>Find Myreco</title>';
// favicon (URL absolue)
$ico = htmlspecialchars(APP_BASE_URL . '/img/icone.png', ENT_QUOTES, 'UTF-8');
echo '<link rel="icon" href="' . $ico . '">';
echo '<link rel="shortcut icon" href="' . $ico . '">';
echo '</head><body style="font-family:Arial,Helvetica,sans-serif;padding:18px;color:#111827;">';
echo $message;
echo '</body></html>';
exit;
}
function h2($s): string {
return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
}
/** Format date FR (utilise date_fr_auto() si dispo) */
function fmt_date_fr(string $ymd): string {
if (function_exists('date_fr_auto')) return (string)date_fr_auto($ymd);
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $ymd)) return $ymd;
$dt = DateTimeImmutable::createFromFormat('!Y-m-d', $ymd);
return $dt ? $dt->format('d/m/Y') : $ymd;
}
/* ------------------------------------------------------------
Inputs / validation
------------------------------------------------------------ */
$a = (string)($_GET['a'] ?? '');
$t = (string)($_GET['t'] ?? '');
$sig = (string)($_GET['sig'] ?? '');
if (!in_array($a, ['accept', 'refuse'], true) || !preg_match('/^[a-f0-9]{32}$/', $t)) {
page_exit('Lien invalide.', 400);
}
if (!hash_equals(make_sig($a, $t), $sig)) {
page_exit('Signature invalide.', 403);
}
/**
* IMPORTANT:
* On limite volontairement aux demandes hébergeur (modele_id=1),
* pour éviter qu’un action_token d’un autre email (recap, accusé, etc.)
* puisse être interprété ici.
*/
$row = $db->get_row("
SELECT *
FROM email_queue
WHERE action_token = '" . $db->escape($t) . "'
AND modele_id = 1
LIMIT 1
");
if (!$row) {
page_exit('Demande introuvable.', 404);
}
// déjà répondu ?
if (($row->response_status ?? 'pending') !== 'pending') {
page_exit('Réponse déjà enregistrée.<br>Merci.');
}
$ip = $_SERVER['REMOTE_ADDR'] ?? null;
$now = date('Y-m-d H:i:s');
/* ------------------------------------------------------------
Context JSON
------------------------------------------------------------ */
$ctx = [];
if (!empty($row->context_json)) {
$tmp = json_decode((string)$row->context_json, true);
if (is_array($tmp)) $ctx = $tmp;
}
$voyageur_email = (string)($ctx['form']['email'] ?? '');
$voyageur_nom = (string)($ctx['form']['nom'] ?? '');
$hebergement_nom = (string)($ctx['hebergement']['name'] ?? '');
$hebergement_ville = (string)($ctx['hebergement']['ville'] ?? '');
$site_reservation = (string)($ctx['hebergement']['site_reservation'] ?? '');
$email_reservation = (string)($ctx['hebergement']['email_reservation'] ?? '');
$site = (string)($ctx['hebergement']['site'] ?? '');
$full_address = (string)($ctx['hebergement']['full_address'] ?? ''); // ✅ correction
$date_debut = (string)($ctx['form']['date_debut'] ?? '');
$date_fin = (string)($ctx['form']['date_fin'] ?? '');
$voyageur_nombre = (string)($ctx['form']['voyageur_nombre'] ?? '');
$user_message = (string)($ctx['form']['message'] ?? '');
/* ------------------------------------------------------------
REFUSE : enregistre la réponse + email voyageur + accusé hôte
------------------------------------------------------------ */
if ($a === 'refuse') {
/* Enregistrement réponse */
$db->query("
UPDATE email_queue
SET response_status = 'refused',
response_at = '" . $db->escape($now) . "',
response_ip = '" . $db->escape((string)$ip) . "'
WHERE id = " . (int)$row->id . "
LIMIT 1
");
/* -------------------------
Email voyageur (modèle_refus)
-------------------------- */
$tplPath = __DIR__ . '/../matrice/modele_refus.html';
$tpl = is_file($tplPath) ? (string)file_get_contents($tplPath) : '';
// fallback minimal si template absent
if (trim($tpl) === '') {
$tpl = "<p>Merci pour votre demande. Malheureusement, nous n'avons pas de disponibilités pour cette demande.</p>";
}
$vars2 = [
'hebergement_nom' => h2($hebergement_nom),
'hebergement_ville' => h2($hebergement_ville),
'site_reservation' => h2($site_reservation),
'email_reservation' => h2($email_reservation),
'site' => h2($site),
'date_debut' => h2(fmt_date_fr($date_debut)),
'date_fin' => h2(fmt_date_fr($date_fin)),
'voyageur_nombre' => h2($voyageur_nombre),
'message' => nl2br(h2($user_message)),
];
$tpl = tpl_if_blocks($tpl, $vars2);
$tpl = tpl_vars($tpl, $vars2);
if (filter_var($voyageur_email, FILTER_VALIDATE_EMAIL)) {
$request_uid = (string)($row->request_uid ?? '');
if ($request_uid === '') $request_uid = bin2hex(random_bytes(16));
$action_token2 = bin2hex(random_bytes(16));
$modele_id = 2;
$objet = "Réponse — $hebergement_nom";
$objet = "Non Disponibilité — $hebergement_nom — " . date_fr_auto($date_debut) . " → " . date_fr_auto($date_fin);
// Note: response_status laissé à NULL (email informatif)
$db->query("
INSERT INTO email_queue
(action_token, request_uid, token, modele_id, expediteur, destinataire_principal, destinataire_copie,
objet, message, context_json, status, error_message, retries, last_attempt, next_attempt, created_at)
VALUES
(
'" . $db->escape($action_token2) . "',
'" . $db->escape($request_uid) . "',
'" . $db->escape((string)$row->token) . "',
" . (int)$modele_id . ",
'" . $db->escape('contact@myreco.online') . "',
'" . $db->escape($voyageur_email) . "',
'',
'" . $db->escape($objet) . "',
'" . $db->escape($tpl) . "',
'" . $db->escape((string)$row->context_json) . "',
'queued',
NULL,
0,
NULL,
'" . $db->escape($now) . "',
NOW()
)
");
}
/* -------------------------
ACK HÉBERGEUR (modele_accuse_refus)
-------------------------- */
$host_email = $email_reservation ?: '';
if (!filter_var($host_email, FILTER_VALIDATE_EMAIL)) {
$host_email="pasdemail@myreco.online";
}
$tplPathAck = __DIR__ . '/../matrice/modele_accuse_refus.html';
$tplAck = is_file($tplPathAck) ? (string)file_get_contents($tplPathAck) : '';
if (trim($tplAck) === '') {
$tplAck = "<p>Copie de votre réponse — refusé</p>";
}
$nom_commercial = (string)($ctx['hebergement']['nom_commercial'] ?? $hebergement_nom);
$reply_status = 'refusé';
$reply_datetime = (new DateTimeImmutable($now))->format('d/m/Y à H:i');
$platform_name = 'Find Myreco';
$view_in_browser_url = APP_BASE_URL;
$unsubscribe_url = APP_BASE_URL . '/public/unsubscribe.php?email=' . urlencode($host_email);
$varsAck = [
'platform_name' => h2($platform_name),
'view_in_browser_url' => h2($view_in_browser_url),
'reply_status' => h2($reply_status),
'reply_datetime' => h2($reply_datetime),
'reply_details' => '',
'email_1' => h2($voyageur_email),
'nom_commercial' => h2($nom_commercial),
'date_start' => h2(fmt_date_fr($date_debut)),
'date_end' => h2(fmt_date_fr($date_fin)),
'guests' => h2($voyageur_nombre),
'nom_du_client' => h2($voyageur_nom),
'email_client' => h2($voyageur_email),
'traveler_message' => nl2br(h2($user_message)),
'full_address' => h2($full_address),
'site' => h2($site),
'unsubscribe_url' => h2($unsubscribe_url),
];
$tplAck = tpl_if_blocks($tplAck, $varsAck);
$ackHtml = tpl_vars($tplAck, $varsAck);
$action_token3 = bin2hex(random_bytes(16));
$request_uid = (string)($row->request_uid ?? '');
if ($request_uid === '') $request_uid = bin2hex(random_bytes(16));
$objetAck = "[MyReco] Accusé d'envoi — [DISPO:NON] — ".$nom_commercial ." du " . date_fr_auto($date_debut) . " au " . date_fr_auto($date_fin)." - ".$voyageur_nombre." pers.";
// Note: response_status laissé à NULL (email informatif)
$db->query("
INSERT INTO email_queue
(action_token, request_uid, token, modele_id, expediteur, destinataire_principal, destinataire_copie,
objet, message, context_json, status, error_message, retries, last_attempt, next_attempt, created_at)
VALUES
(
'" . $db->escape($action_token3) . "',
'" . $db->escape($request_uid) . "',
'" . $db->escape((string)$row->token) . "',
0,
'" . $db->escape('contact@myreco.online') . "',
'" . $db->escape($host_email) . "',
'',
'" . $db->escape($objetAck) . "',
'" . $db->escape($ackHtml) . "',
'" . $db->escape((string)$row->context_json) . "',
'queued',
NULL,
0,
NULL,
'" . $db->escape($now) . "',
NOW()
)
");
//}
// --- Affichage du message envoyé au voyageur (aperçu) ---
$preview_html = $tpl;
// Sécurité basique : on évite d'exécuter du JS si un jour il y en a dans un template
$preview_html = preg_replace('/<script\b[^>]*>.*?<\/script>/is', '', $preview_html);
page_exit('
<div style="max-width:900px;margin:0 auto;">
<div style="font-size:16px;font-weight:700;margin-bottom:6px;">
Merci pour votre réponse.
</div>
<div style="margin-bottom:16px;">
Le voyageur a été informé.
</div>
<div style="font-size:13px;color:#6b7280;margin:10px 0 8px 0;">
Contenu du message envoyé au voyageur :
</div>
<div style="border:1px solid rgba(158,132,105,.45);border-radius:14px;overflow:hidden;background:#fff;">
<div style="background:#9e8469;color:#fff;padding:10px 12px;font-weight:700;">
Aperçu email
</div>
<div style="padding:12px;">
' . $preview_html . '
</div>
</div>
</div>
');
}
/* ------------------------------------------------------------
ACCEPT : délégation à accept.php
(accept.php gère l’enregistrement + les emails associés)
------------------------------------------------------------ */
header('Location: ' . APP_BASE_URL . '/public/accept.php?t=' . urlencode($t) . '&sig=' . urlencode($sig));
exit;