Files
maria_uslugi/contact.php
T
2026-03-05 10:25:39 +01:00

381 lines
16 KiB
PHP
Raw 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
declare(strict_types=1);
require_once __DIR__ . '/../includes/bootstrap_global.php';
// ===== Helpers header (identiques à index.php) =====
function is_client_logged_in(): bool {
$role = $_SESSION['role'] ?? ($_SESSION['user_type'] ?? '');
if (!empty($_SESSION['user_id']) && $role === 'client') return true;
if (!empty($_SESSION['client_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'client') return true;
if (!empty($_SESSION['user_id']) && $role === 'praticien') return true;
if (!empty($_SESSION['praticien_id'])) return true;
if (!empty($_SESSION['reference_id']) && $role === 'praticien') return true;
return false;
}
function include_header_clean(string $absPath): void {
global $translations, $lang;
ob_start();
include $absPath; // /public/includes/header.php
$buf = ob_get_clean() ?: '';
// 0) DOCTYPE + <html>…</html>
$buf = preg_replace('~<!doctype\s+html[^>]*>~i', '', $buf);
$buf = preg_replace('~</?html\b[^>]*>~i', '', $buf);
// 1) retirer <head>…</head> et <body> ouverts/fermés
$buf = preg_replace('~<head\b[^>]*>.*?</head>~is', '', $buf);
$buf = preg_replace('~</?body\b[^>]*>~i', '', $buf);
// 2) retirer les <link> CSS “globaux” pour éviter d’écraser la home
$buf = preg_replace('~<link[^>]+href="[^"]*(bootstrap[^"]*\.css|mobil_style\.css|site_style\.css|fonts\.googleapis)[^"]*"[^>]*>~i', '', $buf);
// 3) retirer le <script> Bootstrap CDN (on le charge déjà en bas de la page)
$buf = preg_replace('~<script[^>]+src="[^"]*bootstrap[^"]*bundle[^"]*\.js[^"]*"[^>]*>\s*</script>~i', '', $buf);
echo $buf; // garde <header> + tes scripts inline utiles
}
/* ---------- Utils ---------- */
function envget(string $k): string {
return trim((string)($_ENV[$k] ?? $_SERVER[$k] ?? getenv($k) ?? ''));
}
function t(array $translations, string $key, string $fallback = ''): string {
$val = $translations[$key] ?? '';
if ($val === '') return $fallback;
return (string)$val;
}
$LOG_DIR = __DIR__ . '/tmp';
$LOG_FILE = $LOG_DIR . '/contact.log';
if (!is_dir($LOG_DIR)) { @mkdir($LOG_DIR, 0770, true); } // dossier local, pas servi publiquement
/* ---------- CSRF ---------- */
if (empty($_SESSION['pub_csrf'])) {
$_SESSION['pub_csrf'] = bin2hex(random_bytes(32));
}
$CSRF = $_SESSION['pub_csrf'];
// --- reCAPTCHA v2 (lecture robuste) ---
$rcCfg = [];
$cfgPath = __DIR__ . '/includes/recaptcha.php';
if (is_file($cfgPath)) {
$rcCfg = require $cfgPath; // ['site' => '...', 'secret' => '...']
}
$RECAPTCHA_SITE_KEY = trim((string)($rcCfg['site'] ?? envget('RECAPTCHA_SITE_KEY') ?? ''));
$RECAPTCHA_SECRET_KEY = trim((string)($rcCfg['secret'] ?? envget('RECAPTCHA_SECRET_KEY') ?? ''));
// Considère la clé "valide" si longueur réaliste (>= 20) – évite les faux négatifs
$HAS_SITE = (strlen($RECAPTCHA_SITE_KEY) >= 20);
$HAS_SECRET = (strlen($RECAPTCHA_SECRET_KEY) >= 20);
// (optionnel) forcer l’affichage en test: /contact.php?testcaptcha=1
if (($_GET['testcaptcha'] ?? '') === '1') $HAS_SITE = true;
/* ---------- État page ---------- */
$errors = [];
$sent = false;
/* ---------- POST ---------- */
if (($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
// CSRF
if (!hash_equals($_SESSION['pub_csrf'] ?? '', $_POST['csrf'] ?? '')) {
$errors[] = t($translations, 'contact_err_security', 'Security error. Refresh and try again.');
}
// Honeypot anti-bot
if (!empty($_POST['website'] ?? '')) {
$errors[] = t($translations, 'contact_err_spam', 'Spam suspected.');
}
// Données utilisateur
$prenom = trim($_POST['prenom'] ?? '');
$nom = trim($_POST['nom'] ?? '');
$email = trim($_POST['email'] ?? '');
$sujet = trim($_POST['sujet'] ?? '');
$message = trim($_POST['message'] ?? '');
// Validations
if (mb_strlen($prenom) < 2) $errors[] = t($translations, 'contact_err_prenom', 'Please enter your first name.');
if (mb_strlen($nom) < 2) $errors[] = t($translations, 'contact_err_nom', 'Please enter your last name.');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) $errors[] = t($translations, 'contact_err_email', 'Please enter a valid email.');
if (mb_strlen($sujet) < 3) $errors[] = t($translations, 'contact_err_sujet', 'Subject is too short.');
if (mb_strlen($message) < 10) $errors[] = t($translations, 'contact_err_message', 'Message is too short.');
// reCAPTCHA serveur
if ($HAS_SECRET) {
$token = $_POST['g-recaptcha-response'] ?? '';
if ($token === '') {
$errors[] = t($translations, 'contact_err_captcha_required', 'Please confirm you are not a robot.');
} else {
$resp = @file_get_contents(
'https://www.google.com/recaptcha/api/siteverify?secret=' . urlencode($RECAPTCHA_SECRET_KEY) .
'&response=' . urlencode($token) .
'&remoteip=' . urlencode($_SERVER['REMOTE_ADDR'] ?? '')
);
$ver = $resp ? json_decode($resp, true) : ['success' => false];
if (empty($ver['success'])) $errors[] = t($translations, 'contact_err_captcha_failed', 'reCAPTCHA verification failed.');
}
}
// Envoi
if (!$errors) {
$to = 'contact@uslugi.fr';
$subjectPrefix = t($translations, 'contact_send_subject_prefix', 'Contact form message — ');
$subject = $subjectPrefix . $sujet;
$mailH3 = t($translations, 'contact_mail_h3', 'New message from uslugi.fr');
$lblName = t($translations, 'contact_mail_label_name', 'Name');
$lblEmail = t($translations, 'contact_mail_label_email', 'Email');
$lblSubject = t($translations, 'contact_mail_label_subject', 'Subject');
$lblMessage = t($translations, 'contact_mail_label_message', 'Message');
$html = '
<h3>'.htmlspecialchars($mailH3, ENT_QUOTES, 'UTF-8').'</h3>
<p><strong>'.htmlspecialchars($lblName, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($prenom).' '.htmlspecialchars($nom).'</p>
<p><strong>'.htmlspecialchars($lblEmail, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($email).'</p>
<p><strong>'.htmlspecialchars($lblSubject, ENT_QUOTES, 'UTF-8').':</strong> '.htmlspecialchars($sujet).'</p>
<p><strong>'.htmlspecialchars($lblMessage, ENT_QUOTES, 'UTF-8').':</strong><br>'.nl2br(htmlspecialchars($message)).'</p>
';
$text = $mailH3 . "\n"
. $lblName . ": $prenom $nom\n"
. $lblEmail . ": $email\n"
. $lblSubject . ": $sujet\n\n"
. $lblMessage . ":\n$message\n";
try {
// From et Reply-To (tableaux) comme attendus par ton wrapper
$fromEmail = 'no-reply@uslugi.fr';
$fromName = 'USLUGI.FR';
$replyEmail = filter_var($email, FILTER_VALIDATE_EMAIL) ? $email : 'contact@uslugi.fr';
$replyName = trim($prenom.' '.$nom) ?: 'USLUGI.FR';
// Appel wrapper: retourne [bool $ok, ?string $err]
[$ok, $err] = uslugi_mail(
$to,
$subject,
$html,
$text,
[
'from' => [$fromEmail, $fromName],
'reply_to' => [$replyEmail, $replyName],
// 'bcc' => ['tonmail@gmail.com'],
]
);
if ($ok !== true) {
throw new RuntimeException('Wrapper mail send failed.');
}
// OK
$sent = true;
$_POST = [];
@file_put_contents($LOG_FILE, sprintf(
"[%s] OK to=%s subj=%s reply=%s ip=%s\n",
date('c'), $to, $sujet, $email, $_SERVER['REMOTE_ADDR'] ?? '-'
), FILE_APPEND);
} catch (Throwable $e) {
error_log('MAIL ERROR: ' . $e->getMessage());
@file_put_contents($LOG_FILE, sprintf(
"[%s] ERR to=%s subj=%s\n",
date('c'), $to, $sujet
), FILE_APPEND);
// Message utilisateur générique (jamais d’info sensible à l’écran)
$errors[] = t($translations, 'contact_err_send_failed', 'Failed to send message. Please try later.');
}
}
}
// Lang HTML
$langHtml = preg_match('~^[a-z]{2}(-[A-Z]{2})?$~', (string)($lang ?? '')) ? (string)$lang : 'ru';
?>
<!doctype html>
<html lang="<?= htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?= htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?= htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?= htmlspecialchars($translations['seo_contact_keywords'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="author" content="Uslugi.fr">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="<?= asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?= asset('/includes/mobil_style.css') ?>">
<style>
/* HERO bleu et cadre */
.hero-contact{ background:#8CA9FF; padding: clamp(16px,4vw,32px); }
.contact-wrap{ max-width:980px; margin:0 auto; font-family:"Montserrat",system-ui,-apple-system,"Segoe UI",Roboto,Arial,sans-serif; }
.contact-frame{
background:#fff; border:1px solid #DFE4FF; border-radius:22px;
box-shadow:0 16px 40px rgba(56,55,139,.14);
padding:clamp(16px,3vw,28px);
}
.contact h1{ font-size:clamp(24px,5.6vw,34px); margin:0 0 10px; }
.contact p.muted{ color:#6b7280; margin:0 0 14px; }
/* Forme */
.form-label{ font-weight:600; }
.form-control{ border-radius:12px; padding:12px 14px; }
textarea.form-control{ min-height: 180px; }
/* Bouton rouge arrondi */
.btn-red{
--bs-btn-bg:#E03C3F; --bs-btn-border-color:#E03C3F;
--bs-btn-hover-bg:#c53637; --bs-btn-hover-border-color:#c53637;
--bs-btn-active-bg:#a62e2f; --bs-btn-active-border-color:#a62e2f;
--bs-btn-hover-color:#fff;
color:#fff; border-radius:9999px; padding:12px 22px;
}
</style>
<?php include_once __DIR__ . '/includes/tracking.php'; ?>
</head>
<body>
<?php if (is_client_logged_in()): ?>
<?php
require_once __DIR__ . '/public/includes/init_pr_cl.php';
include_header_clean(__DIR__ . '/public/includes/header.php'); ?>
<?php else: ?>
<header class="site-header">
<div class="container">
<div class="header-left">
<div class="brand">
<a href="/index.php"><img src="/public/uploads/img/logo_u.png"
alt="uslugi.fr"
class="logo-mobile"></a>
<a href="/index.php"><img src="/public/uploads/img/logo.png"
alt="uslugi.fr"
class="logo-desktop"></a>
</div>
<div class="lang-switch">
<?php require __DIR__ . '/includes/menu_langue.php'; ?>
</div>
</div>
<nav class="header-actions">
<a class="btn-login" href="/connexion.php">
<span class="d-sm-none"><?php echo htmlspecialchars($translations['btn_se_connecter'] ?? 'Connexion', ENT_QUOTES, 'UTF-8')?></span>
<span class="d-none d-sm-inline"><?php echo htmlspecialchars($translations['ja_spec'] ?? 'Je suis spécialiste', ENT_QUOTES, 'UTF-8')?></span>
</a>
<div class="dropdown">
<button
class="btn btn-logo rounded-circle d-inline-flex align-items-center justify-content-center question-btn"
type="button"
data-bs-toggle="dropdown"
data-bs-auto-close="true"
aria-expanded="false"
aria-label="<?php echo htmlspecialchars(t($translations, 'howitworks_help_aria', 'Help'), ENT_QUOTES, 'UTF-8')?>">
?
</button>
<ul class="dropdown-menu dropdown-menu-end shadow help-menu menu-panel">
<li><a href="/how-it-work.php"><?php echo htmlspecialchars($translations['kak_rabotaet'] ?? 'Как это работает', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/about.php"><?php echo htmlspecialchars($translations['pro_nas'] ?? 'О нас', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/faq.php"><?php echo htmlspecialchars($translations['faq'] ?? 'FAQ', ENT_QUOTES, 'UTF-8')?></a></li>
<li><a href="/contact.php"><?php echo htmlspecialchars($translations['nam_pisat'] ?? 'Написать нам', ENT_QUOTES, 'UTF-8')?></a></li>
</ul>
</div>
</nav>
</div>
</header>
<?php endif; ?>
<main class="contact">
<section class="hero-contact">
<div class="container contact-wrap">
<div class="contact-frame">
<h1><?= htmlspecialchars(t($translations, 'contact_h1', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h1>
<p class="muted"><?= htmlspecialchars(t($translations, 'contact_intro', 'Fill the form — we will reply as soon as possible.'), ENT_QUOTES, 'UTF-8') ?></p>
<?php if (!empty($errors)): ?>
<div class="alert alert-danger" role="alert">
<?= implode('<br>', array_map(static fn($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'), $errors)) ?>
</div>
<?php elseif ($sent): ?>
<div class="alert alert-success" role="alert">
<?= htmlspecialchars(t($translations, 'contact_success_sent', 'Thank you! Your message has been sent.'), ENT_QUOTES, 'UTF-8') ?>
</div>
<?php endif; ?>
<form method="post" action="" novalidate>
<input type="hidden" name="csrf" value="<?= htmlspecialchars($CSRF, ENT_QUOTES, 'UTF-8') ?>">
<!-- Honeypot invisible -->
<input type="text" name="website" autocomplete="off" tabindex="-1"
style="position:absolute;left:-9999px;opacity:0" aria-hidden="true">
<div class="row g-3">
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_nom', 'Last name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="nom" class="form-control"
value="<?= htmlspecialchars($_POST['nom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_prenom', 'First name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="prenom" class="form-control"
value="<?= htmlspecialchars($_POST['prenom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_email', 'Email'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="email" name="email" class="form-control" inputmode="email"
placeholder="<?= htmlspecialchars(t($translations, 'contact_email_placeholder', 'name@example.com'), ENT_QUOTES, 'UTF-8') ?>"
value="<?= htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_sujet', 'Subject'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="sujet" class="form-control"
value="<?= htmlspecialchars($_POST['sujet'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?= htmlspecialchars(t($translations, 'contact_label_message', 'Message'), ENT_QUOTES, 'UTF-8') ?></label>
<textarea name="message" class="form-control" required><?= htmlspecialchars($_POST['message'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
</div>
<?php if ($HAS_SITE): ?>
<div class="col-12">
<div class="g-recaptcha" data-sitekey="<?= htmlspecialchars($RECAPTCHA_SITE_KEY, ENT_QUOTES, 'UTF-8') ?>"></div>
</div>
<?php endif; ?>
<div class="col-12 d-flex justify-content-end">
<button type="submit" class="btn btn-red">
<?= htmlspecialchars(t($translations, 'contact_btn_submit', 'Send'), ENT_QUOTES, 'UTF-8') ?>
</button>
</div>
</div>
</form>
</div>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p><?= $translations['copyr'] ?></p>
</div>
</footer>
<?php if ($HAS_SITE): ?>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<?php endif; ?>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>