Files

425 lines
17 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
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="<?php echo htmlspecialchars($langHtml, ENT_QUOTES, 'UTF-8') ?>">
<head>
<meta charset="UTF-8">
<title><?php echo htmlspecialchars($translations['seo_contact_title'], ENT_QUOTES, 'UTF-8') ?></title>
<meta name="description" content="<?php echo htmlspecialchars($translations['seo_contact_desc'], ENT_QUOTES, 'UTF-8') ?>">
<meta name="keywords" content="<?php echo 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="<?php echo asset('/includes/site_style.css') ?>">
<link rel="stylesheet" href="<?php echo asset('/includes/custom_style.css') ?>">
<link rel="stylesheet" href="<?php echo 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><?php echo htmlspecialchars(t($translations, 'contact_h1', 'Contact us'), ENT_QUOTES, 'UTF-8') ?></h1>
<p class="muted"><?php echo 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">
<?php echo 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">
<?php echo 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="<?php echo 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"><?php echo htmlspecialchars(t($translations, 'contact_label_nom', 'Last name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="nom" class="form-control"
value="<?php echo htmlspecialchars($_POST['nom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_prenom', 'First name'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="prenom" class="form-control"
value="<?php echo htmlspecialchars($_POST['prenom'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_email', 'Email'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="email" name="email" class="form-control" inputmode="email"
placeholder="<?php echo htmlspecialchars(t($translations, 'contact_email_placeholder', 'name@example.com'), ENT_QUOTES, 'UTF-8') ?>"
value="<?php echo htmlspecialchars($_POST['email'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_sujet', 'Subject'), ENT_QUOTES, 'UTF-8') ?></label>
<input type="text" name="sujet" class="form-control"
value="<?php echo htmlspecialchars($_POST['sujet'] ?? '', ENT_QUOTES, 'UTF-8') ?>" required>
</div>
<div class="col-12">
<label class="form-label"><?php echo htmlspecialchars(t($translations, 'contact_label_message', 'Message'), ENT_QUOTES, 'UTF-8') ?></label>
<textarea name="message" class="form-control" required><?php echo htmlspecialchars($_POST['message'] ?? '', ENT_QUOTES, 'UTF-8') ?></textarea>
</div>
<?php if ($HAS_SITE): ?>
<div class="col-12">
<div class="g-recaptcha" data-sitekey="<?php echo 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">
<?php echo 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><?php echo $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>