Diagnostique
Outil de Diagnostic Système
Une page de diagnostic permet de vérifier en un clin d'œil si le serveur web (www-data) possède bien les droits d'écriture nécessaires. Cela évite de chercher pendant des heures la source d'un bug de permission.
1. Création du fichier sur le serveur
Depuis votre terminal, connectez-vous à votre Raspberry Pi et créez le fichier de diagnostic :
sudo nano /var/www/html/diag.phpCopiez le code ci-dessous et collez-le dans l'éditeur :
<?php
// diag.php - Diagnostic Centralisé & Maintenance
ini_set('display_errors', 1);
error_reporting(E_ALL);
header('Content-Type: text/html; charset=utf-8');
session_start();
date_default_timezone_set('Europe/Paris');
// --- CONFIGURATION ---
$config_path = '/var/www/html/data/.env.php';
$config = file_exists($config_path) ? include($config_path) : [];
define('BLACKLIST_FILE', ($config['DATA_DIR'] ?? '/var/www/html/data/') . 'ip_blacklist.json');
define('LOG_FILE', $config['LOG_PATH'] ?? '/var/log/camera_status.log');
// --- MODULE DE TEST HTACCESS ---
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
$base_url = $protocol . "://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
$test_url = rtrim($base_url, '/') . '/data/.env.php';
// Test de l'accès via flux (plus léger que cURL pour un diag)
$context = stream_context_create(['http' => ['method' => 'GET', 'timeout' => 3, 'ignore_errors' => true]]);
$response_header = @get_headers($test_url, 1, $context);
$http_code = $response_header[0] ?? '';
$htaccess_ok = (strpos($http_code, '403') !== false || strpos($http_code, '401') !== false);
// Fonction pour écrire dans l'historique de l'index
function writeLogDiag($source, $message, $details = "-") {
$line = "[" . date('Y-m-d H:i:s') . "] [$source] $message: $details\n";
file_put_contents(LOG_FILE, $line, FILE_APPEND | LOCK_EX);
}
$message_test = "";
// --- LOGIQUE DES TESTS ---
if (isset($_GET['action'])) {
switch ($_GET['action']) {
case 'test_sms':
if (isset($config['FREE_SMS_ACTIVE']) && $config['FREE_SMS_ACTIVE']) {
$url = "https://smsapi.free-mobile.fr/sendmsg?" . http_build_query([
'user' => $config['FREE_USER'], 'pass' => $config['FREE_PASS'], 'msg' => "Test Alarme : SMS OK"
]);
$res = @file_get_contents($url);
$message_test = ($res !== FALSE) ? "<p style='color:green; font-weight:bold;'>✅ SMS envoyé avec succès.</p>" : "<p style='color:red; font-weight:bold;'>❌ Échec envoi SMS.</p>";
} else {
$message_test = "<p style='color:orange; font-weight:bold;'>ℹ️ SMS ignoré : Le service est désactivé dans votre configuration.</p>";
}
break;
case 'test_mail':
if (isset($config['MAIL_ENABLED']) && $config['MAIL_ENABLED']) {
$headers = "From: ".$config['MAIL_FROM']."\r\nContent-Type: text/plain; charset=utf-8";
$sent = mail($config['MAIL_DEST'], "Test Diag", "Email fonctionnel.", $headers);
$message_test = $sent ? "<p style='color:green; font-weight:bold;'>✅ Email transmis au système.</p>" : "<p style='color:red; font-weight:bold;'>❌ Échec Email.</p>";
} else {
$message_test = "<p style='color:orange; font-weight:bold;'>ℹ️ Email ignoré : Service désactivé.</p>";
}
break;
case 'test_ban':
$fake_ip = "1.2.3.4";
$blacklist = file_exists(BLACKLIST_FILE) ? json_decode(file_get_contents(BLACKLIST_FILE), true) : [];
$blacklist[$fake_ip] = ['blocked_time' => date('Y-m-d H:i:s'), 'reason' => 'TEST DIAGNOSTIC'];
file_put_contents(BLACKLIST_FILE, json_encode($blacklist, JSON_PRETTY_PRINT));
writeLogDiag("SECURITY", "IP bannie (TEST DIAG)", $fake_ip);
$message_test = "<p style='color:green; font-weight:bold;'>✅ IP 1.2.3.4 ajoutée. Vérifiez l'historique sur l'Index.</p>";
break;
}
}
// --- OUTILS D'AFFICHAGE ---
function get_permissions($file) {
if (!file_exists($file)) return '<span style="color:red;">Absent ❌</span>';
$perms = fileperms($file);
return substr(sprintf('%o', $perms), -3) . " ✅";
}
function check_writable($file) {
if (!file_exists($file)) return '---';
return is_writable($file) ? '<span style="color:green; font-weight:bold;">OUI ✅</span>' : '<span style="color:red; font-weight:bold;">NON ❌</span>';
}
$files_to_check = [
'Scripts Web' => ['index.php', 'config.php', 'secure_action.php', 'admin.php', 'webhook_presence.php'],
'Sécurité & Config' => ['data/.env.php', 'data/.htaccess'],
'Données (JSON)' => ['data/devices_status.json', 'data/ip_blacklist.json'],
'Système' => [LOG_FILE]
];
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Diagnostic Système</title>
<style>
body { font-family: -apple-system, sans-serif; background: #f2f2f7; padding: 20px; color: #1c1c1e; line-height: 1.5; }
.card { background: white; padding: 25px; border-radius: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); margin-bottom: 20px; max-width: 800px; margin-left: auto; margin-right: auto; }
table { width: 100%; max-width: 600px; margin: 15px auto; border-collapse: collapse; background: white; font-size: 0.85em; }
th, td { padding: 10px; border: 1px solid #efeff4; text-align: left; }
th { background: #f8f8fa; color: #8e8e93; text-transform: uppercase; font-size: 0.75em; }
.col-status { width: 80px; text-align: center; }
.btn { display: inline-block; padding: 10px 18px; background: #007aff; color: white; text-decoration: none; border-radius: 8px; margin: 5px; font-weight: bold; font-size: 0.9em; }
.note { font-size: 0.85em; color: #636366; margin-top: 10px; font-style: italic; }
h1, h2 { color: #1c1c1e; text-align: center; margin-top: 0; }
.msg-box { text-align: center; margin-top: 15px; padding: 10px; border-radius: 8px; }
.security-warning { border: 2px solid #ff3b30; background-color: #fff5f5; color: #d70015; padding: 15px; border-radius: 12px; margin-top: 20px; }
.htaccess-box { padding: 15px; border-radius: 12px; margin-bottom: 20px; text-align: left; }
.status-ok { background: #e5f9e7; border: 1px solid #34c759; color: #248a3d; }
.status-danger { background: #fff5f5; border: 2px solid #ff3b30; color: #d70015; }
</style>
</head>
<body>
<div class="card">
<h1>🔍 Diagnostic : Alarme-2 Maison</h1>
<p style="text-align: center; font-size: 0.9em; color: #8e8e93;">Utilisateur PHP : <strong><?php echo exec('whoami'); ?></strong></p>
<div class="htaccess-box <?php echo $htaccess_ok ? 'status-ok' : 'status-danger'; ?>">
<strong>🛡️ Protection .htaccess :</strong>
<?php if ($htaccess_ok): ?>
<span>Activée ✅ (Accès distant au dossier /data/ interdit)</span>
<?php else: ?>
<span style="display:block; margin-top:5px;">⚠️ <strong>DANGER : Accès non protégé !</strong><br>
Le dossier <code>/data/</code> est accessible via le Web. <br>
Action : Réglez <strong>AllowOverride All</strong> dans la conf Apache.</span>
<?php endif; ?>
</div>
<div class="msg-box"><?php echo $message_test; ?></div>
</div>
<div class="card" style="text-align: center;">
<h2>⚡ Actions de Test</h2>
<p class="note">Vérifiez la réception réelle des alertes sur vos appareils.</p>
<a href="?action=test_sms" class="btn">Test SMS Free</a>
<a href="?action=test_mail" class="btn">Test Email</a>
<a href="?action=test_ban" class="btn" style="background:#ff3b30;">Test Bannissement</a>
</div>
<div class="card">
<h2>1. Vérification des Fichiers et Droits</h2>
<p class="note">Note : Les scripts web ne doivent normalement PAS être en écriture (NON ❌) pour plus de sécurité.</p>
<table>
<thead>
<tr>
<th>Nom du fichier</th>
<th class="col-status">Droits</th>
<th class="col-status">Écriture</th>
</tr>
</thead>
<tbody>
<?php foreach ($files_to_check as $category => $files): ?>
<tr><th colspan="3" style="background:#f2f2f7; color: #1c1c1e;"><?php echo $category; ?></th></tr>
<?php foreach ($files as $file):
$path = (strpos($file, '/') === 0) ? $file : "/var/www/html/" . $file; ?>
<tr>
<td><code><?php echo basename($file); ?></code></td>
<td class="col-status"><?php echo get_permissions($path); ?></td>
<td class="col-status"><?php echo check_writable($path); ?></td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="card" style="text-align: center;">
<h2>2. Sécurité & Rappels</h2>
<div class="security-warning">
<p><strong>⚠️ RAPPEL DE SÉCURITÉ CRITIQUE</strong></p>
<p style="font-size: 0.95em;">Une fois votre configuration terminée et validée :</p>
<ul style="text-align: left; display: inline-block; font-size: 0.9em;">
<li>Supprimez ou renommez le fichier <strong>config.php</strong>.</li>
<li>Supprimez ou renommez ce fichier <strong>diag.php</strong>.</li>
</ul>
</div>
<p style="margin-top: 20px;"><a href="index.php" style="color: #007aff; text-decoration: none; font-weight: bold;">← Retour au Dashboard</a></p>
</div>
</body>
</html>
// diag.php - Diagnostic Centralisé & Maintenance
ini_set('display_errors', 1);
error_reporting(E_ALL);
header('Content-Type: text/html; charset=utf-8');
session_start();
date_default_timezone_set('Europe/Paris');
// --- CONFIGURATION ---
$config_path = '/var/www/html/data/.env.php';
$config = file_exists($config_path) ? include($config_path) : [];
define('BLACKLIST_FILE', ($config['DATA_DIR'] ?? '/var/www/html/data/') . 'ip_blacklist.json');
define('LOG_FILE', $config['LOG_PATH'] ?? '/var/log/camera_status.log');
// --- MODULE DE TEST HTACCESS ---
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? "https" : "http";
$base_url = $protocol . "://" . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']);
$test_url = rtrim($base_url, '/') . '/data/.env.php';
// Test de l'accès via flux (plus léger que cURL pour un diag)
$context = stream_context_create(['http' => ['method' => 'GET', 'timeout' => 3, 'ignore_errors' => true]]);
$response_header = @get_headers($test_url, 1, $context);
$http_code = $response_header[0] ?? '';
$htaccess_ok = (strpos($http_code, '403') !== false || strpos($http_code, '401') !== false);
// Fonction pour écrire dans l'historique de l'index
function writeLogDiag($source, $message, $details = "-") {
$line = "[" . date('Y-m-d H:i:s') . "] [$source] $message: $details\n";
file_put_contents(LOG_FILE, $line, FILE_APPEND | LOCK_EX);
}
$message_test = "";
// --- LOGIQUE DES TESTS ---
if (isset($_GET['action'])) {
switch ($_GET['action']) {
case 'test_sms':
if (isset($config['FREE_SMS_ACTIVE']) && $config['FREE_SMS_ACTIVE']) {
$url = "https://smsapi.free-mobile.fr/sendmsg?" . http_build_query([
'user' => $config['FREE_USER'], 'pass' => $config['FREE_PASS'], 'msg' => "Test Alarme : SMS OK"
]);
$res = @file_get_contents($url);
$message_test = ($res !== FALSE) ? "<p style='color:green; font-weight:bold;'>✅ SMS envoyé avec succès.</p>" : "<p style='color:red; font-weight:bold;'>❌ Échec envoi SMS.</p>";
} else {
$message_test = "<p style='color:orange; font-weight:bold;'>ℹ️ SMS ignoré : Le service est désactivé dans votre configuration.</p>";
}
break;
case 'test_mail':
if (isset($config['MAIL_ENABLED']) && $config['MAIL_ENABLED']) {
$headers = "From: ".$config['MAIL_FROM']."\r\nContent-Type: text/plain; charset=utf-8";
$sent = mail($config['MAIL_DEST'], "Test Diag", "Email fonctionnel.", $headers);
$message_test = $sent ? "<p style='color:green; font-weight:bold;'>✅ Email transmis au système.</p>" : "<p style='color:red; font-weight:bold;'>❌ Échec Email.</p>";
} else {
$message_test = "<p style='color:orange; font-weight:bold;'>ℹ️ Email ignoré : Service désactivé.</p>";
}
break;
case 'test_ban':
$fake_ip = "1.2.3.4";
$blacklist = file_exists(BLACKLIST_FILE) ? json_decode(file_get_contents(BLACKLIST_FILE), true) : [];
$blacklist[$fake_ip] = ['blocked_time' => date('Y-m-d H:i:s'), 'reason' => 'TEST DIAGNOSTIC'];
file_put_contents(BLACKLIST_FILE, json_encode($blacklist, JSON_PRETTY_PRINT));
writeLogDiag("SECURITY", "IP bannie (TEST DIAG)", $fake_ip);
$message_test = "<p style='color:green; font-weight:bold;'>✅ IP 1.2.3.4 ajoutée. Vérifiez l'historique sur l'Index.</p>";
break;
}
}
// --- OUTILS D'AFFICHAGE ---
function get_permissions($file) {
if (!file_exists($file)) return '<span style="color:red;">Absent ❌</span>';
$perms = fileperms($file);
return substr(sprintf('%o', $perms), -3) . " ✅";
}
function check_writable($file) {
if (!file_exists($file)) return '---';
return is_writable($file) ? '<span style="color:green; font-weight:bold;">OUI ✅</span>' : '<span style="color:red; font-weight:bold;">NON ❌</span>';
}
$files_to_check = [
'Scripts Web' => ['index.php', 'config.php', 'secure_action.php', 'admin.php', 'webhook_presence.php'],
'Sécurité & Config' => ['data/.env.php', 'data/.htaccess'],
'Données (JSON)' => ['data/devices_status.json', 'data/ip_blacklist.json'],
'Système' => [LOG_FILE]
];
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Diagnostic Système</title>
<style>
body { font-family: -apple-system, sans-serif; background: #f2f2f7; padding: 20px; color: #1c1c1e; line-height: 1.5; }
.card { background: white; padding: 25px; border-radius: 15px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); margin-bottom: 20px; max-width: 800px; margin-left: auto; margin-right: auto; }
table { width: 100%; max-width: 600px; margin: 15px auto; border-collapse: collapse; background: white; font-size: 0.85em; }
th, td { padding: 10px; border: 1px solid #efeff4; text-align: left; }
th { background: #f8f8fa; color: #8e8e93; text-transform: uppercase; font-size: 0.75em; }
.col-status { width: 80px; text-align: center; }
.btn { display: inline-block; padding: 10px 18px; background: #007aff; color: white; text-decoration: none; border-radius: 8px; margin: 5px; font-weight: bold; font-size: 0.9em; }
.note { font-size: 0.85em; color: #636366; margin-top: 10px; font-style: italic; }
h1, h2 { color: #1c1c1e; text-align: center; margin-top: 0; }
.msg-box { text-align: center; margin-top: 15px; padding: 10px; border-radius: 8px; }
.security-warning { border: 2px solid #ff3b30; background-color: #fff5f5; color: #d70015; padding: 15px; border-radius: 12px; margin-top: 20px; }
.htaccess-box { padding: 15px; border-radius: 12px; margin-bottom: 20px; text-align: left; }
.status-ok { background: #e5f9e7; border: 1px solid #34c759; color: #248a3d; }
.status-danger { background: #fff5f5; border: 2px solid #ff3b30; color: #d70015; }
</style>
</head>
<body>
<div class="card">
<h1>🔍 Diagnostic : Alarme-2 Maison</h1>
<p style="text-align: center; font-size: 0.9em; color: #8e8e93;">Utilisateur PHP : <strong><?php echo exec('whoami'); ?></strong></p>
<div class="htaccess-box <?php echo $htaccess_ok ? 'status-ok' : 'status-danger'; ?>">
<strong>🛡️ Protection .htaccess :</strong>
<?php if ($htaccess_ok): ?>
<span>Activée ✅ (Accès distant au dossier /data/ interdit)</span>
<?php else: ?>
<span style="display:block; margin-top:5px;">⚠️ <strong>DANGER : Accès non protégé !</strong><br>
Le dossier <code>/data/</code> est accessible via le Web. <br>
Action : Réglez <strong>AllowOverride All</strong> dans la conf Apache.</span>
<?php endif; ?>
</div>
<div class="msg-box"><?php echo $message_test; ?></div>
</div>
<div class="card" style="text-align: center;">
<h2>⚡ Actions de Test</h2>
<p class="note">Vérifiez la réception réelle des alertes sur vos appareils.</p>
<a href="?action=test_sms" class="btn">Test SMS Free</a>
<a href="?action=test_mail" class="btn">Test Email</a>
<a href="?action=test_ban" class="btn" style="background:#ff3b30;">Test Bannissement</a>
</div>
<div class="card">
<h2>1. Vérification des Fichiers et Droits</h2>
<p class="note">Note : Les scripts web ne doivent normalement PAS être en écriture (NON ❌) pour plus de sécurité.</p>
<table>
<thead>
<tr>
<th>Nom du fichier</th>
<th class="col-status">Droits</th>
<th class="col-status">Écriture</th>
</tr>
</thead>
<tbody>
<?php foreach ($files_to_check as $category => $files): ?>
<tr><th colspan="3" style="background:#f2f2f7; color: #1c1c1e;"><?php echo $category; ?></th></tr>
<?php foreach ($files as $file):
$path = (strpos($file, '/') === 0) ? $file : "/var/www/html/" . $file; ?>
<tr>
<td><code><?php echo basename($file); ?></code></td>
<td class="col-status"><?php echo get_permissions($path); ?></td>
<td class="col-status"><?php echo check_writable($path); ?></td>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="card" style="text-align: center;">
<h2>2. Sécurité & Rappels</h2>
<div class="security-warning">
<p><strong>⚠️ RAPPEL DE SÉCURITÉ CRITIQUE</strong></p>
<p style="font-size: 0.95em;">Une fois votre configuration terminée et validée :</p>
<ul style="text-align: left; display: inline-block; font-size: 0.9em;">
<li>Supprimez ou renommez le fichier <strong>config.php</strong>.</li>
<li>Supprimez ou renommez ce fichier <strong>diag.php</strong>.</li>
</ul>
</div>
<p style="margin-top: 20px;"><a href="index.php" style="color: #007aff; text-decoration: none; font-weight: bold;">← Retour au Dashboard</a></p>
</div>
</body>
</html>
2. Comment utiliser cette page
- Lancez le diagnostic : Ouvrez votre navigateur à l'adresse
http://[VOTRE_IP]/diag.php. - Analysez les résultats :
- Si la colonne "Écriture" affiche NON ❌ en rouge, relancez les commandes
chownouchmodsur ce fichier. - Si le test Sudoers est en rouge, vérifiez votre fichier
/etc/sudoersviavisudo.
- Si la colonne "Écriture" affiche NON ❌ en rouge, relancez les commandes
⚠️ Conseil de sécurité
Ce fichier révèle des informations sensibles sur votre serveur. Une fois que tout est vert, supprimez-le immédiatement : sudo rm /var/www/html/diag.php