Feat: onglet SMTP dans l'administration
- Formulaire d'édition des paramètres SMTP (serveur, port, chiffrement, utilisateur, mot de passe, expéditeur) stockés dans data/smtp_settings.json (écrit par www-data, contrairement au .env en lecture seule) - Test de connexion SMTP avec logs PHPMailer complets (DEBUG_SERVER) - Envoi d'email de test avec contenu personnalisé anti-spam - src/SmtpSettings.php : lecture/écriture smtp_settings.json avec fallback env() - mailer.php : lit les paramètres depuis SmtpSettings en priorité - admin.js : indicateurs spinner sur les boutons pendant le traitement
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Sélection globale articles
|
||||
var checkAll = document.getElementById('check-all');
|
||||
if (checkAll) {
|
||||
checkAll.addEventListener('change', function () {
|
||||
@@ -7,4 +8,31 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Indicateurs de traitement formulaire SMTP (config + tester connexion)
|
||||
var smtpForm = document.getElementById('smtp-config-form');
|
||||
if (smtpForm) {
|
||||
smtpForm.addEventListener('submit', function (e) {
|
||||
var clicked = e.submitter;
|
||||
if (!clicked) return;
|
||||
smtpForm.querySelectorAll('button[type="submit"]').forEach(function (btn) {
|
||||
btn.disabled = true;
|
||||
});
|
||||
var isSave = clicked.id === 'smtp-save-btn';
|
||||
clicked.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>'
|
||||
+ (isSave ? 'Enregistrement…' : 'En cours…');
|
||||
});
|
||||
}
|
||||
|
||||
// Indicateur de traitement envoi email de test
|
||||
var smtpTestForm = document.getElementById('smtp-test-form');
|
||||
if (smtpTestForm) {
|
||||
smtpTestForm.addEventListener('submit', function () {
|
||||
var btn = document.getElementById('smtp-send-btn');
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1" role="status" aria-hidden="true"></span>En cours…';
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1991,9 +1991,138 @@ switch ($action) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($tab === 'smtp') {
|
||||
if (!isAdmin()) {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
require_once BASE_PATH . '/src/SmtpSettings.php';
|
||||
$adminData['smtp_config'] = [
|
||||
'host' => smtpCfg('host', 'SMTP_HOST'),
|
||||
'port' => smtpCfg('port', 'SMTP_PORT'),
|
||||
'secure' => smtpCfg('secure', 'SMTP_SECURE'),
|
||||
'user' => smtpCfg('user', 'SMTP_USER'),
|
||||
'has_pass' => smtpCfg('pass', 'SMTP_PASS') !== '',
|
||||
'from' => smtpCfg('from', 'SMTP_FROM'),
|
||||
'from_name' => smtpCfg('from_name', 'SMTP_FROM_NAME'),
|
||||
];
|
||||
$adminData['smtp_test'] = $_SESSION['smtp_test_result'] ?? null;
|
||||
unset($_SESSION['smtp_test_result']);
|
||||
}
|
||||
|
||||
include BASE_PATH . '/templates/admin.php';
|
||||
break;
|
||||
|
||||
case 'admin_smtp_save':
|
||||
requireAuth();
|
||||
if (!isAdmin()) {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
require_once BASE_PATH . '/src/SmtpSettings.php';
|
||||
|
||||
saveSmtpSettings([
|
||||
'host' => $_POST['smtp_host'] ?? '',
|
||||
'port' => $_POST['smtp_port'] ?? '',
|
||||
'secure' => $_POST['smtp_secure'] ?? '',
|
||||
'user' => $_POST['smtp_user'] ?? '',
|
||||
'pass' => $_POST['smtp_pass'] ?? '',
|
||||
'from' => $_POST['smtp_from'] ?? '',
|
||||
'from_name' => $_POST['smtp_from_name'] ?? '',
|
||||
]);
|
||||
header('Location: /admin/smtp?saved=1');
|
||||
exit;
|
||||
|
||||
case 'admin_smtp_test':
|
||||
requireAuth();
|
||||
if (!isAdmin()) {
|
||||
http_response_code(403);
|
||||
exit;
|
||||
}
|
||||
require_once BASE_PATH . '/src/SmtpSettings.php';
|
||||
require_once BASE_PATH . '/src/mailer.php';
|
||||
|
||||
$mode = in_array($_POST['mode'] ?? '', ['connect', 'send'], true) ? $_POST['mode'] : 'connect';
|
||||
$testEmail = trim($_POST['test_email'] ?? '');
|
||||
if ($testEmail !== '' && !filter_var($testEmail, FILTER_VALIDATE_EMAIL)) {
|
||||
$testEmail = '';
|
||||
}
|
||||
|
||||
$smtpLogs = [];
|
||||
$smtpOk = false;
|
||||
$smtpErrMsg = '';
|
||||
|
||||
try {
|
||||
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
|
||||
$mail->isSMTP();
|
||||
$mail->Host = smtpCfg('host', 'SMTP_HOST', 'localhost');
|
||||
$mail->Port = (int)smtpCfg('port', 'SMTP_PORT', '587');
|
||||
$_stUser = smtpCfg('user', 'SMTP_USER');
|
||||
$_stPass = smtpCfg('pass', 'SMTP_PASS');
|
||||
$mail->SMTPAuth = ($_stUser !== '' || $_stPass !== '');
|
||||
$mail->Username = $_stUser;
|
||||
$mail->Password = $_stPass;
|
||||
$smtpSecure = strtolower(smtpCfg('secure', 'SMTP_SECURE', 'tls'));
|
||||
if ($smtpSecure === 'ssl') {
|
||||
$mail->SMTPSecure = \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS;
|
||||
} elseif ($smtpSecure === 'tls') {
|
||||
$mail->SMTPSecure = \PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS;
|
||||
}
|
||||
$mail->Timeout = 15;
|
||||
$mail->SMTPOptions = ['ssl' => ['verify_peer' => true, 'verify_peer_name' => true, 'allow_self_signed' => false]];
|
||||
$mail->SMTPDebug = \PHPMailer\PHPMailer\SMTP::DEBUG_SERVER;
|
||||
$mail->Debugoutput = static function (string $str) use (&$smtpLogs): void {
|
||||
$smtpLogs[] = rtrim($str);
|
||||
};
|
||||
|
||||
if ($mode === 'send' && $testEmail !== '') {
|
||||
$mail->CharSet = 'UTF-8';
|
||||
$mail->isHTML(true);
|
||||
$_smtpFrom = smtpCfg('from', 'SMTP_FROM', 'no-reply@varlog.a5l.fr');
|
||||
$_smtpFromName = smtpCfg('from_name', 'SMTP_FROM_NAME', 'varlog');
|
||||
$mail->setFrom($_smtpFrom, $_smtpFromName);
|
||||
$mail->addAddress($testEmail);
|
||||
$_siteName = siteTitle();
|
||||
$_siteUrl = rtrim(APP_URL, '/');
|
||||
$_sentAt = date('d/m/Y à H\hi', time());
|
||||
$mail->Subject = 'Vérification de la configuration email — ' . $_siteName;
|
||||
$mail->Body = '<!DOCTYPE html><html lang="fr"><head><meta charset="UTF-8">'
|
||||
. '<meta name="viewport" content="width=device-width,initial-scale=1"></head>'
|
||||
. '<body style="font-family:sans-serif;color:#1a1a1a;max-width:520px;margin:0 auto;padding:32px 16px">'
|
||||
. '<p>Bonjour,</p>'
|
||||
. '<p>Cet email confirme que la configuration SMTP de <strong>' . htmlspecialchars($_siteName) . '</strong> fonctionne correctement.</p>'
|
||||
. '<p>Envoyé le ' . $_sentAt . ' depuis <a href="' . htmlspecialchars($_siteUrl) . '">' . htmlspecialchars($_siteUrl) . '</a>.</p>'
|
||||
. '<hr style="border:none;border-top:1px solid #e5e7eb;margin:28px 0">'
|
||||
. '<p style="color:#6b7280;font-size:0.82em">Vous recevez cet email car un administrateur a effectué un test de configuration depuis l\'interface d\'administration de ' . htmlspecialchars($_siteName) . '.'
|
||||
. ' Si vous n\'attendiez pas cet email, vous pouvez l\'ignorer.</p>'
|
||||
. '</body></html>';
|
||||
$mail->AltBody = "Bonjour,\r\n\r\n"
|
||||
. "Cet email confirme que la configuration SMTP de {$_siteName} fonctionne correctement.\r\n\r\n"
|
||||
. "Envoyé le {$_sentAt} depuis {$_siteUrl}.\r\n\r\n"
|
||||
. "--\r\n"
|
||||
. "Vous recevez cet email car un administrateur a effectué un test de configuration depuis l'interface d'administration de {$_siteName}."
|
||||
. " Si vous n'attendiez pas cet email, vous pouvez l'ignorer.";
|
||||
$mail->send();
|
||||
} else {
|
||||
$mail->smtpConnect();
|
||||
$mail->smtpClose();
|
||||
}
|
||||
$smtpOk = true;
|
||||
} catch (\Exception $e) {
|
||||
$smtpErrMsg = $e->getMessage();
|
||||
}
|
||||
|
||||
$_SESSION['smtp_test_result'] = [
|
||||
'success' => $smtpOk,
|
||||
'error' => $smtpErrMsg,
|
||||
'logs' => $smtpLogs,
|
||||
'mode' => $mode,
|
||||
'email' => $testEmail,
|
||||
'ts' => date('d/m/Y H:i:s'),
|
||||
];
|
||||
header('Location: /admin/smtp');
|
||||
exit;
|
||||
|
||||
case 'admin_bulk_delete':
|
||||
requireAuth();
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
Reference in New Issue
Block a user