$ttl) { $redir = $_SERVER['REQUEST_URI'] ?? 'index.php?page=afficher_messages'; header('Location: ?page=reauth&redir='.rawurlencode($redir)); return; } try { $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (Throwable) {} $e = static fn($s)=>htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\Exception; // CSRF helper if (!function_exists('require_post_csrf')) { function require_post_csrf() { global $translations; if ($_SERVER['REQUEST_METHOD']!=='POST') { http_response_code(405); exit($translations['contactad_method_not_allowed'] ?? 'Méthode non autorisée'); } if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'])) { http_response_code(419); exit($translations['contactad_csrf_invalid'] ?? 'CSRF invalide'); } } } // Отправка письма через PHPMailer (HTML + текст) function admin_send_reply(string $to, string $subject, string $html, string $text): array { /** @var array $MAILCFG */ global $MAILCFG; $m = new PHPMailer(true); try { $m->isSMTP(); $m->Host = $MAILCFG['smtp']['host']; $m->Port = $MAILCFG['smtp']['port']; $m->SMTPSecure = $MAILCFG['smtp']['secure']; $m->SMTPAuth = $MAILCFG['smtp']['auth']; $m->Username = $MAILCFG['smtp']['username']; $m->Password = $MAILCFG['smtp']['password']; $m->CharSet = 'UTF-8'; $m->Encoding = 'base64'; $m->XMailer = ''; if (!empty($MAILCFG['bounce'])) { // Envelope From / return-path (для SPF/DMARC) $m->Sender = $MAILCFG['bounce']; } $from = $MAILCFG['from'] ?? ['no-reply@uslugi.fr','USLUGI.FR']; $rpto = $MAILCFG['reply_to'] ?? ['no-reply@uslugi.fr','USLUGI.FR']; $m->setFrom($from[0], $from[1] ?? ''); if (!empty($rpto[0])) { $m->addReplyTo($rpto[0], $rpto[1] ?? ''); } $m->addAddress($to); // Анти-автоответы (по желанию) if (!empty($MAILCFG['suppress_auto'])) { $m->addCustomHeader('Auto-Submitted', 'auto-generated'); $m->addCustomHeader('X-Auto-Response-Suppress', 'All'); } $m->isHTML(true); $m->Subject = $subject; $m->Body = $html; $m->AltBody = $text; $m->send(); return [true, null]; } catch (Throwable $e) { error_log('PHPMailer admin reply error: '.$e->getMessage().($m->ErrorInfo ? ' | '.$m->ErrorInfo : '')); return [false, $e->getMessage()]; } } // Действия POST: ответ / удаление $err = null; if ($_SERVER['REQUEST_METHOD'] === 'POST') { require_post_csrf(); $action = $_POST['action'] ?? ''; if ($action === 'reply') { $id = (int)($_POST['id'] ?? 0); $txt = trim((string)($_POST['reply'] ?? '')); if ($id <= 0 || $txt === '') { $err = $translations['contactad_err_invalid_data'] ?? 'Données invalides'; } else { $st = $pdo->prepare("SELECT * FROM contact_messages WHERE id=? LIMIT 1"); $st->execute([$id]); $m = $st->fetch(PDO::FETCH_ASSOC); if (!$m) { $err = $translations['contactad_err_not_found'] ?? 'Message introuvable'; } else { $to = (string)$m['email']; $subj = $translations['contactad_mail_subject_reply'] ?? "Réponse de l'administrateur"; $greet= $translations['contactad_mail_greeting'] ?? "Bonjour"; $orig = $translations['contactad_mail_original_label'] ?? "Votre message initial :"; // HTML версия $origHtml = nl2br($e($m['message'])); $html = '

'.$e($greet).' '.$e($m['prenom'].' '.$m['nom']).',

'.$e($txt).'


'.$e($orig).'

'.$origHtml.'
'; // Текстовая версия $text = $greet.' '.($m['prenom'].' '.$m['nom']).","."\n\n". $txt."\n\n". "-----------------------\n".$orig."\n".$m['message']."\n"; // Отправка [$ok,$errSend] = admin_send_reply($to, $subj, $html, $text); // Записываем статус "repondu" в любом случае (как раньше) $stU = $pdo->prepare("UPDATE contact_messages SET statut='repondu', reponse=?, replied_by=?, replied_at=NOW() WHERE id=?"); $stU->execute([$txt, (int)($_SESSION['compte_id'] ?? 0), $id]); if (function_exists('log_admin_action')) { log_admin_action( $pdo, (int)($_SESSION['compte_id'] ?? 0), 'contact_reply', json_encode(['id'=>$id,'email'=>$to,'sent'=>(bool)$ok,'error'=>$errSend], JSON_UNESCAPED_UNICODE) ); } // Возврат к списку (без id) header('Location: ?page=afficher_messages&flash=1'); return; } } } elseif ($action === 'delete') { $id = (int)($_POST['id'] ?? 0); if ($id > 0) { $del = $pdo->prepare("DELETE FROM contact_messages WHERE id=?"); $del->execute([$id]); if (function_exists('log_admin_action')) { log_admin_action($pdo, (int)($_SESSION['compte_id'] ?? 0), 'contact_delete', json_encode(['id'=>$id,'deleted'=>$del->rowCount()>0], JSON_UNESCAPED_UNICODE)); } header('Location: ?page=afficher_messages&deleted=1'); return; } else { $err = $translations['contactad_err_invalid_id'] ?? 'ID invalide'; } } } // Открытое сообщение? $msg = null; if (isset($_GET['id'])) { $id = (int)$_GET['id']; $st = $pdo->prepare("SELECT * FROM contact_messages WHERE id=? LIMIT 1"); $st->execute([$id]); $msg = $st->fetch(PDO::FETCH_ASSOC); if ($msg && $msg['statut'] === 'nouveau') { $pdo->prepare("UPDATE contact_messages SET statut='lu' WHERE id=?")->execute([$id]); $msg['statut'] = 'lu'; } } // Список (пагинация) $page = max(1, (int)($_GET['p'] ?? 1)); $per = 25; $off = ($page - 1) * $per; $total = (int)$pdo->query("SELECT COUNT(*) FROM contact_messages")->fetchColumn(); $rows = $pdo->query("SELECT id, nom, prenom, email, sujet, statut, created_at FROM contact_messages ORDER BY id DESC LIMIT $per OFFSET $off")->fetchAll(PDO::FETCH_ASSOC); $pages = max(1, (int)ceil($total / $per)); ?>

1): ?>
# •
—