Compare commits
1 Commits
master
...
e484ae8919
| Author | SHA1 | Date | |
|---|---|---|---|
| e484ae8919 |
19
config.php
19
config.php
@@ -1,25 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
define('DB_HOST', 'mariadb');
|
define('DB_HOST', 'smarthome_db');
|
||||||
define('DB_USER', 'smarthome_user');
|
define('DB_USER', 'smarthome_user');
|
||||||
define('DB_PASSWORD', 'SH_LaSalle_SD8');
|
define('DB_PASSWORD', 'SH_LaSalle_SD8');
|
||||||
define('DB_NAME', 'smarthome');
|
define('DB_NAME', 'smarthome');
|
||||||
|
|
||||||
define('JWT_SECRET', 'smarthome_secret_key_2024_smart_home_project_very_long_key');
|
define('JWT_SECRET', 'smarthome_secret_key_2024_smart_home_project_very_long_key');
|
||||||
|
define('MQTT_BROKER', 'localhost');
|
||||||
define('MQTT_BROKER', 'mosquitto');
|
|
||||||
define('MQTT_PORT', 1883);
|
define('MQTT_PORT', 1883);
|
||||||
define('MQTT_TOPIC_CLIMATE', 'smarthome/climate');
|
define('MQTT_TOPIC_CLIMATE', 'smarthome/climate');
|
||||||
define('MQTT_TOPIC_SECURITY', 'smarthome/security');
|
define('MQTT_TOPIC_SECURITY', 'smarthome/security');
|
||||||
|
|
||||||
function get_db() {
|
function get_db() {
|
||||||
try {
|
$conn = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
|
||||||
$pdo = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME . ";charset=utf8", DB_USER, DB_PASSWORD, [
|
if ($conn->connect_error) {
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
die(json_encode(['error' => 'Connexion échouée : ' . $conn->connect_error]));
|
||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
|
|
||||||
]);
|
|
||||||
return $pdo;
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
die(json_encode(['error' => 'Connexion échouée : ' . $e->getMessage()]));
|
|
||||||
}
|
}
|
||||||
|
return $conn;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -5,38 +5,27 @@ require_once 'vendor/autoload.php';
|
|||||||
use PhpMqtt\Client\MqttClient;
|
use PhpMqtt\Client\MqttClient;
|
||||||
use PhpMqtt\Client\ConnectionSettings;
|
use PhpMqtt\Client\ConnectionSettings;
|
||||||
|
|
||||||
try {
|
function insert_climate($data) {
|
||||||
$db = get_db();
|
$db = get_db();
|
||||||
} catch (Exception $e) {
|
$stmt = $db->prepare("INSERT INTO climate_data (temperature, humidity, pressure, luminosity) VALUES (?, ?, ?, ?)");
|
||||||
die("Impossible de démarrer le script : " . $e->getMessage() . "\n");
|
$stmt->bind_param("dddd",
|
||||||
|
$data['temperature'],
|
||||||
|
$data['humidity'],
|
||||||
|
$data['pressure'],
|
||||||
|
$data['luminosity']
|
||||||
|
);
|
||||||
|
$stmt->execute();
|
||||||
|
$db->close();
|
||||||
|
echo "Donnée climatique insérée : " . json_encode($data) . "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
function insert_climate($db, $data) {
|
function insert_security($data) {
|
||||||
try {
|
$db = get_db();
|
||||||
$stmt = $db->prepare("INSERT INTO climate_data (temperature, humidity, pressure, luminosity) VALUES (:temp, :hum, :pres, :lum)");
|
$stmt = $db->prepare("INSERT INTO security_events (event_type, location) VALUES (?, ?)");
|
||||||
$stmt->execute([
|
$stmt->bind_param("ss", $data['event_type'], $data['location']);
|
||||||
':temp' => $data['temperature'],
|
$stmt->execute();
|
||||||
':hum' => $data['humidity'],
|
$db->close();
|
||||||
':pres' => $data['pressure'],
|
echo "Événement sécurité inséré : " . json_encode($data) . "\n";
|
||||||
':lum' => $data['luminosity']
|
|
||||||
]);
|
|
||||||
echo "Donnée climatique insérée : " . json_encode($data) . "\n";
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
echo "Erreur d'insertion climat : " . $e->getMessage() . "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function insert_security($db, $data) {
|
|
||||||
try {
|
|
||||||
$stmt = $db->prepare("INSERT INTO security_events (event_type, location) VALUES (:event, :loc)");
|
|
||||||
$stmt->execute([
|
|
||||||
':event' => $data['event_type'],
|
|
||||||
':loc' => $data['location']
|
|
||||||
]);
|
|
||||||
echo "Événement sécurité inséré : " . json_encode($data) . "\n";
|
|
||||||
} catch (PDOException $e) {
|
|
||||||
echo "Erreur d'insertion sécurité : " . $e->getMessage() . "\n";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$mqtt = new MqttClient(MQTT_BROKER, MQTT_PORT);
|
$mqtt = new MqttClient(MQTT_BROKER, MQTT_PORT);
|
||||||
@@ -44,18 +33,14 @@ $settings = (new ConnectionSettings())->setKeepAliveInterval(60);
|
|||||||
$mqtt->connect($settings);
|
$mqtt->connect($settings);
|
||||||
echo "Connecté au broker MQTT\n";
|
echo "Connecté au broker MQTT\n";
|
||||||
|
|
||||||
$mqtt->subscribe(MQTT_TOPIC_CLIMATE, function($topic, $message) use ($db) {
|
$mqtt->subscribe(MQTT_TOPIC_CLIMATE, function($topic, $message) {
|
||||||
$data = json_decode($message, true);
|
$data = json_decode($message, true);
|
||||||
if ($data) {
|
insert_climate($data);
|
||||||
insert_climate($db, $data);
|
|
||||||
}
|
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
$mqtt->subscribe(MQTT_TOPIC_SECURITY, function($topic, $message) use ($db) {
|
$mqtt->subscribe(MQTT_TOPIC_SECURITY, function($topic, $message) {
|
||||||
$data = json_decode($message, true);
|
$data = json_decode($message, true);
|
||||||
if ($data) {
|
insert_security($data);
|
||||||
insert_security($db, $data);
|
|
||||||
}
|
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
$mqtt->loop(true);
|
$mqtt->loop(true);
|
||||||
|
|||||||
1
smart-house---final-
Submodule
1
smart-house---final-
Submodule
Submodule smart-house---final- added at 4188ca3abc
8
smart-house---final-/.idea/modules.xml
generated
8
smart-house---final-/.idea/modules.xml
generated
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectModuleManager">
|
|
||||||
<modules>
|
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/smart-house---final-.iml" filepath="$PROJECT_DIR$/.idea/smart-house---final-.iml" />
|
|
||||||
</modules>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
19
smart-house---final-/.idea/php.xml
generated
19
smart-house---final-/.idea/php.xml
generated
@@ -1,19 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="MessDetectorOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PHPCSFixerOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
|
||||||
<option name="highlightLevel" value="WARNING" />
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PhpStanOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PsalmOptionsConfiguration">
|
|
||||||
<option name="transferred" value="true" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<module type="WEB_MODULE" version="4">
|
|
||||||
<component name="NewModuleRootManager">
|
|
||||||
<content url="file://$MODULE_DIR$" />
|
|
||||||
<orderEntry type="inheritedJdk" />
|
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
|
||||||
</component>
|
|
||||||
</module>
|
|
||||||
6
smart-house---final-/.idea/vcs.xml
generated
6
smart-house---final-/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
65
smart-house---final-/.idea/workspace.xml
generated
65
smart-house---final-/.idea/workspace.xml
generated
@@ -1,65 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ChangeListManager">
|
|
||||||
<list default="true" id="badd9711-30eb-4220-b16e-f09f234f961a" name="Changes" comment="">
|
|
||||||
<change beforePath="$PROJECT_DIR$/dashboard.js" beforeDir="false" afterPath="$PROJECT_DIR$/dashboard.js" afterDir="false" />
|
|
||||||
</list>
|
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
||||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
||||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
||||||
</component>
|
|
||||||
<component name="ComposerSettings">
|
|
||||||
<execution />
|
|
||||||
</component>
|
|
||||||
<component name="Git.Settings">
|
|
||||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
||||||
</component>
|
|
||||||
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="/bin/php" />
|
|
||||||
<component name="ProjectColorInfo">{
|
|
||||||
"associatedIndex": 3,
|
|
||||||
"fromUser": false
|
|
||||||
}</component>
|
|
||||||
<component name="ProjectId" id="3EXNCY6gnuLEQsMDkAdCuksKzxz" />
|
|
||||||
<component name="ProjectViewState">
|
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
|
||||||
<option name="showLibraryContents" value="true" />
|
|
||||||
</component>
|
|
||||||
<component name="PropertiesComponent"><![CDATA[{
|
|
||||||
"keyToString": {
|
|
||||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
||||||
"RunOnceActivity.git.unshallow": "true",
|
|
||||||
"RunOnceActivity.typescript.service.memoryLimit.init": "true",
|
|
||||||
"codeWithMe.voiceChat.enabledByDefault": "false",
|
|
||||||
"git-widget-placeholder": "main",
|
|
||||||
"last_opened_file_path": "/home/enzo/smart-house---final-",
|
|
||||||
"nodejs_package_manager_path": "npm",
|
|
||||||
"vue.rearranger.settings.migration": "true"
|
|
||||||
}
|
|
||||||
}]]></component>
|
|
||||||
<component name="SharedIndexes">
|
|
||||||
<attachedChunks>
|
|
||||||
<set>
|
|
||||||
<option value="bundled-js-predefined-d6986cc7102b-31caf2ab9e3c-JavaScript-PS-261.24374.185" />
|
|
||||||
<option value="bundled-php-predefined-a98d8de5180a-6bbb74dbab74-com.jetbrains.php.sharedIndexes-PS-261.24374.185" />
|
|
||||||
</set>
|
|
||||||
</attachedChunks>
|
|
||||||
</component>
|
|
||||||
<component name="TaskManager">
|
|
||||||
<task active="true" id="Default" summary="Default task">
|
|
||||||
<changelist id="badd9711-30eb-4220-b16e-f09f234f961a" name="Changes" comment="" />
|
|
||||||
<created>1780320829467</created>
|
|
||||||
<option name="number" value="Default" />
|
|
||||||
<option name="presentableId" value="Default" />
|
|
||||||
<updated>1780320829467</updated>
|
|
||||||
<workItem from="1780320830997" duration="1815000" />
|
|
||||||
<workItem from="1780399893551" duration="890000" />
|
|
||||||
<workItem from="1780481022356" duration="718000" />
|
|
||||||
</task>
|
|
||||||
<servers />
|
|
||||||
</component>
|
|
||||||
<component name="TypeScriptGeneratedFilesManager">
|
|
||||||
<option name="version" value="3" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
http_response_code(404);
|
|
||||||
session_start();
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div style="text-align: center; padding: 80px 20px;">
|
|
||||||
<h1 style="font-size: 5em; color: #3bc4e8; margin-bottom: 10px;">404</h1>
|
|
||||||
<h2 style="font-size: 1.5em; margin-bottom: 15px;">Page introuvable</h2>
|
|
||||||
<p style="color: #aaa; margin-bottom: 30px;">La page que vous cherchez n'existe pas ou a été déplacée.</p>
|
|
||||||
<a href="/smart-house---final-/dashboard.php" class="btn-primary">🏠 Retour au dashboard</a>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,126 +0,0 @@
|
|||||||
# 🏠 Smart House
|
|
||||||
|
|
||||||
Application web de tableau de bord domotique développée en PHP, permettant de surveiller et gérer une maison intelligente.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Présentation
|
|
||||||
|
|
||||||
Smart House est un dashboard web qui permet de visualiser en temps réel les données de capteurs (climat, sécurité, énergie, lumière) et de gérer les utilisateurs avec un système de rôles Admin/User.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✨ Fonctionnalités
|
|
||||||
|
|
||||||
### Authentification
|
|
||||||
- Connexion / Inscription sécurisée
|
|
||||||
- Blocage après 3 tentatives échouées (5 minutes)
|
|
||||||
- Déconnexion automatique après 15 minutes d'inactivité
|
|
||||||
- Régénération de session après connexion
|
|
||||||
|
|
||||||
### Gestion des utilisateurs
|
|
||||||
- Inscription avec validation obligatoire par l'admin
|
|
||||||
- Système de rôles : Admin / User
|
|
||||||
- Profil utilisateur (changement de mot de passe)
|
|
||||||
- Promotion / Rétrogradation des utilisateurs
|
|
||||||
|
|
||||||
### Dashboard
|
|
||||||
- Widget Climat (Température, Humidité, Pression, Altitude)
|
|
||||||
- Widget Sécurité (Mouvement, Distance)
|
|
||||||
- Widget Énergie (Puissance, Consommation)
|
|
||||||
- Widget Lumière (Lux)
|
|
||||||
- Graphiques Chart.js
|
|
||||||
- Widget Alertes
|
|
||||||
|
|
||||||
### Administration
|
|
||||||
- Gestion des utilisateurs (accepter, refuser, supprimer, changer le rôle)
|
|
||||||
- Paramètres du site (nom, tentatives max, durée session, message d'accueil)
|
|
||||||
- Logs du dashboard
|
|
||||||
|
|
||||||
### Interface
|
|
||||||
- Mode sombre / clair
|
|
||||||
- Design responsive (mobile, tablette, desktop)
|
|
||||||
- Page 404 personnalisée
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Structure des fichiers
|
|
||||||
|
|
||||||
smart-house---final-/
|
|
||||||
include/
|
|
||||||
header.php # En-tête HTML commun
|
|
||||||
footer.php # Pied de page commun
|
|
||||||
nav.php # Barre de navigation
|
|
||||||
session_check.php # Vérification de session
|
|
||||||
js/
|
|
||||||
chart.min.js # Chart.js local
|
|
||||||
index.php # Page d'accueil
|
|
||||||
login.php # Page de connexion
|
|
||||||
register.php # Page d'inscription
|
|
||||||
logout.php # Déconnexion
|
|
||||||
dashboard.php # Tableau de bord
|
|
||||||
profil.php # Profil utilisateur
|
|
||||||
admin_users.php # Gestion des utilisateurs (Admin)
|
|
||||||
admin_settings.php # Paramètres du site (Admin)
|
|
||||||
admin_logs.php # Logs (Admin)
|
|
||||||
404.php # Page d'erreur 404
|
|
||||||
dashboard.js # Scripts du dashboard
|
|
||||||
style.css # Styles CSS
|
|
||||||
users.json.php # Base de données utilisateurs
|
|
||||||
settings.json.php # Paramètres du site
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Installation
|
|
||||||
|
|
||||||
### Prérequis
|
|
||||||
- PHP 7.4 ou supérieur
|
|
||||||
- Serveur web (Apache, Nginx, ou serveur PHP intégré)
|
|
||||||
|
|
||||||
### Lancement avec le serveur PHP intégré
|
|
||||||
|
|
||||||
php -S localhost:8000
|
|
||||||
|
|
||||||
Puis ouvrir dans le navigateur :
|
|
||||||
|
|
||||||
http://localhost:8000/
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔐 Comptes et accès
|
|
||||||
|
|
||||||
### Compte Admin
|
|
||||||
- Nom d'utilisateur : Kari
|
|
||||||
- Mot de passe : Levasseur
|
|
||||||
- Rôle : Admin
|
|
||||||
|
|
||||||
### Compte Utilisateur
|
|
||||||
Les utilisateurs s'inscrivent via la page /register.php et doivent être validés par l'admin avant de pouvoir se connecter.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛡️ Sécurité
|
|
||||||
|
|
||||||
- Mots de passe hashés avec password_hash() (bcrypt)
|
|
||||||
- Protection contre les attaques par force brute (blocage 5 min après 3 échecs)
|
|
||||||
- Régénération de l'ID de session après connexion
|
|
||||||
- Vérification du rôle à chaque chargement de page
|
|
||||||
- Déconnexion automatique après inactivité
|
|
||||||
- Protection des pages admin (redirection si non Admin)
|
|
||||||
- Échappement des données avec htmlspecialchars()
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠️ Technologies utilisées
|
|
||||||
|
|
||||||
- PHP — Backend et gestion des sessions
|
|
||||||
- HTML / CSS — Interface utilisateur
|
|
||||||
- JavaScript — Interactions dynamiques
|
|
||||||
- Chart.js — Graphiques
|
|
||||||
- JSON — Stockage des données utilisateurs et paramètres
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📅 Année
|
|
||||||
|
|
||||||
2026
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require_once 'include/session_check.php';
|
|
||||||
if ($_SESSION['role'] !== 'Admin') {
|
|
||||||
header("Location: dashboard.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
<main>
|
|
||||||
<div class="logs-container">
|
|
||||||
<h2>Logs du Dashboard</h2>
|
|
||||||
<p>Bienvenue, <?php echo htmlspecialchars($_SESSION['user']); ?> (Admin)</p>
|
|
||||||
<h3>Modifications récentes</h3>
|
|
||||||
<ul id="modifications">
|
|
||||||
<li>Aucune modification pour l'instant.</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Alertes récentes</h3>
|
|
||||||
<ul id="alertes">
|
|
||||||
<li>Aucune alerte pour l'instant.</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<script>
|
|
||||||
function ajouterModification(msg) {
|
|
||||||
const ul = document.getElementById('modifications');
|
|
||||||
const li = document.createElement('li');
|
|
||||||
li.textContent = msg;
|
|
||||||
ul.prepend(li);
|
|
||||||
}
|
|
||||||
function ajouterAlerte(msg) {
|
|
||||||
const ul = document.getElementById('alertes');
|
|
||||||
const li = document.createElement('li');
|
|
||||||
li.textContent = msg;
|
|
||||||
ul.prepend(li);
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
ajouterModification("Utilisateur John a modifié le widget Climat");
|
|
||||||
ajouterAlerte("Température trop élevée détectée");
|
|
||||||
}, 2000);
|
|
||||||
</script>
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require_once 'include/session_check.php';
|
|
||||||
if ($_SESSION['role'] !== 'Admin') {
|
|
||||||
header("Location: dashboard.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$settingsFile = 'settings.json.php';
|
|
||||||
$settings = file_exists($settingsFile) ? json_decode(file_get_contents($settingsFile), true) : [
|
|
||||||
'site_name' => 'Smart House',
|
|
||||||
'max_attempts' => 3,
|
|
||||||
'session_timeout' => 900,
|
|
||||||
'welcome_message' => 'Bienvenue sur votre tableau de bord Smart House.'
|
|
||||||
];
|
|
||||||
$success = '';
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$settings['site_name'] = trim($_POST['site_name']);
|
|
||||||
$settings['max_attempts'] = (int)$_POST['max_attempts'];
|
|
||||||
$settings['session_timeout'] = (int)$_POST['session_timeout'] * 60;
|
|
||||||
$settings['welcome_message'] = trim($_POST['welcome_message']);
|
|
||||||
|
|
||||||
file_put_contents($settingsFile, json_encode($settings, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Paramètres sauvegardés avec succès !";
|
|
||||||
}
|
|
||||||
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="logs-container">
|
|
||||||
<h2>⚙️ Paramètres du site</h2>
|
|
||||||
|
|
||||||
<?php if ($success): ?>
|
|
||||||
<p class="form-success" style="margin-top: 10px;"><?php echo htmlspecialchars($success); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<form method="POST" action="admin_settings.php" style="margin-top: 20px;">
|
|
||||||
|
|
||||||
<label class="field-label" for="site_name">Nom du site</label>
|
|
||||||
<input type="text" id="site_name" name="site_name"
|
|
||||||
value="<?php echo htmlspecialchars($settings['site_name']); ?>"
|
|
||||||
style="width:100%; padding:10px; border-radius:8px; border:1px solid #444; background:#1e1e1e; color:#f0f0f0; margin-bottom:15px;">
|
|
||||||
|
|
||||||
<label class="field-label" for="max_attempts">Tentatives de connexion max</label>
|
|
||||||
<input type="number" id="max_attempts" name="max_attempts" min="1" max="10"
|
|
||||||
value="<?php echo $settings['max_attempts']; ?>"
|
|
||||||
style="width:100%; padding:10px; border-radius:8px; border:1px solid #444; background:#1e1e1e; color:#f0f0f0; margin-bottom:15px;">
|
|
||||||
|
|
||||||
<label class="field-label" for="session_timeout">Durée de session (en minutes)</label>
|
|
||||||
<input type="number" id="session_timeout" name="session_timeout" min="1" max="120"
|
|
||||||
value="<?php echo $settings['session_timeout'] / 60; ?>"
|
|
||||||
style="width:100%; padding:10px; border-radius:8px; border:1px solid #444; background:#1e1e1e; color:#f0f0f0; margin-bottom:15px;">
|
|
||||||
|
|
||||||
<label class="field-label" for="welcome_message">Message d'accueil</label>
|
|
||||||
<textarea id="welcome_message" name="welcome_message" rows="3"
|
|
||||||
style="width:100%; padding:10px; border-radius:8px; border:1px solid #444; background:#1e1e1e; color:#f0f0f0; margin-bottom:15px; resize:vertical;"><?php echo htmlspecialchars($settings['welcome_message']); ?></textarea>
|
|
||||||
|
|
||||||
<button type="submit"
|
|
||||||
style="padding:12px 30px; background-color:#3bc4e8; color:white; border:none; border-radius:25px; cursor:pointer; font-weight:bold; transition: background-color 0.3s;">
|
|
||||||
💾 Sauvegarder
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require_once 'include/session_check.php';
|
|
||||||
if ($_SESSION['role'] !== 'Admin') {
|
|
||||||
header("Location: dashboard.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$usersFile = 'users.json.php';
|
|
||||||
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
|
|
||||||
$message = '';
|
|
||||||
$success = '';
|
|
||||||
|
|
||||||
// Accepter un utilisateur
|
|
||||||
if (isset($_GET['accepter'])) {
|
|
||||||
$cible = $_GET['accepter'];
|
|
||||||
if (isset($users[$cible])) {
|
|
||||||
$users[$cible]['statut'] = 'actif';
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Utilisateur '$cible' accepté avec succès.";
|
|
||||||
$users = json_decode(file_get_contents($usersFile), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refuser un utilisateur
|
|
||||||
if (isset($_GET['refuser'])) {
|
|
||||||
$cible = $_GET['refuser'];
|
|
||||||
if (isset($users[$cible])) {
|
|
||||||
unset($users[$cible]);
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Utilisateur '$cible' refusé et supprimé.";
|
|
||||||
$users = json_decode(file_get_contents($usersFile), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Supprimer un utilisateur
|
|
||||||
if (isset($_GET['supprimer'])) {
|
|
||||||
$cible = $_GET['supprimer'];
|
|
||||||
if ($cible === $_SESSION['user']) {
|
|
||||||
$message = "Vous ne pouvez pas supprimer votre propre compte.";
|
|
||||||
} elseif (isset($users[$cible])) {
|
|
||||||
unset($users[$cible]);
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Utilisateur '$cible' supprimé avec succès.";
|
|
||||||
$users = json_decode(file_get_contents($usersFile), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Changer le rôle
|
|
||||||
if (isset($_GET['role'])) {
|
|
||||||
$cible = $_GET['role'];
|
|
||||||
if ($cible === $_SESSION['user']) {
|
|
||||||
$message = "Vous ne pouvez pas changer votre propre rôle.";
|
|
||||||
} elseif (isset($users[$cible])) {
|
|
||||||
$users[$cible]['role'] = ($users[$cible]['role'] === 'Admin') ? 'User' : 'Admin';
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Rôle de '$cible' modifié avec succès.";
|
|
||||||
$users = json_decode(file_get_contents($usersFile), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="logs-container">
|
|
||||||
<h2>👥 Gestion des utilisateurs</h2>
|
|
||||||
|
|
||||||
<?php if ($message): ?>
|
|
||||||
<p class="form-error" style="margin-top: 10px;"><?php echo htmlspecialchars($message); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($success): ?>
|
|
||||||
<p class="form-success" style="margin-top: 10px;"><?php echo htmlspecialchars($success); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<!-- Comptes en attente -->
|
|
||||||
<?php
|
|
||||||
$en_attente = array_filter($users, function($u) {
|
|
||||||
return isset($u['statut']) && $u['statut'] === 'en_attente';
|
|
||||||
});
|
|
||||||
?>
|
|
||||||
<?php if (!empty($en_attente)): ?>
|
|
||||||
<h3 style="margin-top: 20px; color: #f39c12;">⏳ Comptes en attente de validation</h3>
|
|
||||||
<table class="admin-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Nom d'utilisateur</th>
|
|
||||||
<th>Statut</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php foreach ($en_attente as $username => $data): ?>
|
|
||||||
<tr>
|
|
||||||
<td><?php echo htmlspecialchars($username); ?></td>
|
|
||||||
<td><span style="color: #f39c12;">En attente</span></td>
|
|
||||||
<td>
|
|
||||||
<a href="admin_users.php?accepter=<?php echo urlencode($username); ?>"
|
|
||||||
class="btn-action btn-warning">✅ Accepter</a>
|
|
||||||
<a href="admin_users.php?refuser=<?php echo urlencode($username); ?>"
|
|
||||||
class="btn-action btn-danger"
|
|
||||||
onclick="return confirm('Refuser <?php echo htmlspecialchars($username); ?> ?')">
|
|
||||||
❌ Refuser
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<!-- Comptes actifs -->
|
|
||||||
<h3 style="margin-top: 30px;">✅ Comptes actifs</h3>
|
|
||||||
<table class="admin-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Nom d'utilisateur</th>
|
|
||||||
<th>Rôle</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<?php foreach ($users as $username => $data):
|
|
||||||
if (isset($data['statut']) && $data['statut'] === 'en_attente') continue;
|
|
||||||
?>
|
|
||||||
<tr>
|
|
||||||
<td><?php echo htmlspecialchars($username); ?>
|
|
||||||
<?php if ($username === $_SESSION['user']): ?>
|
|
||||||
<span style="color: #3bc4e8; font-size: 0.8em;">(vous)</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span style="color: <?php echo $data['role'] === 'Admin' ? '#3bc4e8' : '#aaa'; ?>">
|
|
||||||
<?php echo htmlspecialchars($data['role']); ?>
|
|
||||||
</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?php if ($username !== $_SESSION['user']): ?>
|
|
||||||
<a href="admin_users.php?role=<?php echo urlencode($username); ?>"
|
|
||||||
class="btn-action btn-warning">
|
|
||||||
<?php echo $data['role'] === 'Admin' ? '⬇️ Rétrograder' : '⬆️ Promouvoir'; ?>
|
|
||||||
</a>
|
|
||||||
<a href="admin_users.php?supprimer=<?php echo urlencode($username); ?>"
|
|
||||||
class="btn-action btn-danger"
|
|
||||||
onclick="return confirm('Supprimer <?php echo htmlspecialchars($username); ?> ?')">
|
|
||||||
🗑️ Supprimer
|
|
||||||
</a>
|
|
||||||
<?php else: ?>
|
|
||||||
<span style="color: #666; font-size: 0.85em;">— compte actuel —</span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
/* global Chart */
|
|
||||||
|
|
||||||
const climat = document.querySelector('.widget.climat');
|
|
||||||
const securite = document.querySelector('.widget.securite');
|
|
||||||
const energie = document.querySelector('.widget.energie');
|
|
||||||
const lumiere = document.querySelector('.widget.lumiere');
|
|
||||||
const alertes = document.querySelector('.widget.alertes');
|
|
||||||
|
|
||||||
function setupHover(widget, colorNormal, colorHover) {
|
|
||||||
widget.addEventListener('mouseenter', () => {
|
|
||||||
widget.style.backgroundColor = colorHover;
|
|
||||||
});
|
|
||||||
widget.addEventListener('mouseleave', () => {
|
|
||||||
widget.style.backgroundColor = colorNormal;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setupHover(climat, '#ADD8E6', '#87CEEB');
|
|
||||||
setupHover(securite, '#D3D3D3', '#C0C0C0');
|
|
||||||
setupHover(energie, '#FFFACD', '#FAFAD2');
|
|
||||||
setupHover(lumiere, '#F5F5DC', '#FFF8DC');
|
|
||||||
|
|
||||||
function showAlert(widget) {
|
|
||||||
widget.classList.add('alert');
|
|
||||||
}
|
|
||||||
|
|
||||||
showAlert(climat);
|
|
||||||
alertes.style.display = 'block';
|
|
||||||
|
|
||||||
let monGraphique = null;
|
|
||||||
const canvasTemp = document.getElementById('graph-temp');
|
|
||||||
|
|
||||||
function creerGraphique(labels, valeurs) {
|
|
||||||
if (!canvasTemp) return;
|
|
||||||
const ctx = canvasTemp.getContext('2d');
|
|
||||||
|
|
||||||
monGraphique = new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: labels,
|
|
||||||
datasets: [{
|
|
||||||
label: 'Température',
|
|
||||||
data: valeurs,
|
|
||||||
borderColor: 'blue',
|
|
||||||
backgroundColor: 'rgba(173,216,230,0.2)',
|
|
||||||
tension: 0.4
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: true }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
x: { display: true, title: { display: true, text: 'Temps' } },
|
|
||||||
y: { display: true, title: { display: true, text: '°C' } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function chargerDonnees() {
|
|
||||||
try {
|
|
||||||
const res = await fetch('api/get_data.php');
|
|
||||||
const data = await res.json();
|
|
||||||
|
|
||||||
if (data.status === 'success') {
|
|
||||||
if (data.climate) {
|
|
||||||
document.getElementById("temperature").textContent = data.climate.temperature + " °C";
|
|
||||||
document.getElementById("humidity").textContent = data.climate.humidity + " %";
|
|
||||||
document.getElementById("pressure").textContent = data.climate.pressure + " hPa";
|
|
||||||
document.getElementById("luminosity").textContent = data.climate.luminosity + " lux";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.security) {
|
|
||||||
document.getElementById("event_type").textContent = data.security.event_type;
|
|
||||||
document.getElementById("location").textContent = data.security.location;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.graph && data.graph.length > 0) {
|
|
||||||
const labels = data.graph.map(point => {
|
|
||||||
const date = new Date(point.timestamp);
|
|
||||||
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
||||||
});
|
|
||||||
const temperatures = data.graph.map(point => point.temperature);
|
|
||||||
|
|
||||||
if (monGraphique) {
|
|
||||||
monGraphique.data.labels = labels;
|
|
||||||
monGraphique.data.datasets[0].data = temperatures;
|
|
||||||
monGraphique.update();
|
|
||||||
} else {
|
|
||||||
creerGraphique(labels, temperatures);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Erreur lors du chargement de l'API :", error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
await chargerDonnees();
|
|
||||||
setInterval(chargerDonnees, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
init();
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require_once 'include/session_check.php';
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
<main>
|
|
||||||
<div class="dashboard-header">
|
|
||||||
<h2>Dashboard Smart House</h2>
|
|
||||||
<p>
|
|
||||||
Bienvenue, <?php echo htmlspecialchars($_SESSION['user']); ?>
|
|
||||||
(<?php echo htmlspecialchars($_SESSION['role']); ?>)
|
|
||||||
</p>
|
|
||||||
<?php if ($_SESSION['role'] === 'Admin'): ?>
|
|
||||||
<p>Vous êtes Admin, vous pouvez gérer le site.</p>
|
|
||||||
<?php else: ?>
|
|
||||||
<p>Vous êtes Utilisateur, votre accès est limité.</p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="dashboard">
|
|
||||||
<div class="widget climat">
|
|
||||||
<span class="icone">🌡️</span>
|
|
||||||
<strong>Climat</strong>
|
|
||||||
<p>Température : <span id="temperature">–</span></p>
|
|
||||||
<p>Humidité : <span id="humidity">–</span></p>
|
|
||||||
<p>Pression : <span id="pressure">–</span></p>
|
|
||||||
<p>Luminosité : <span id="luminosity">–</span></p>
|
|
||||||
</div>
|
|
||||||
<div class="widget securite">
|
|
||||||
<span class="icone">🚨</span>
|
|
||||||
<strong>Sécurité</strong>
|
|
||||||
<p>Événement : <span id="event_type">–</span></p>
|
|
||||||
<p>Lieu : <span id="location">–</span></p>
|
|
||||||
</div>
|
|
||||||
<div class="widget energie">
|
|
||||||
<span class="icone">⚡</span>
|
|
||||||
<strong>Énergie</strong>
|
|
||||||
<p>Puissance : –</p>
|
|
||||||
<p>Consommation : –</p>
|
|
||||||
</div>
|
|
||||||
<div class="widget lumiere">
|
|
||||||
<span class="icone">💡</span>
|
|
||||||
<strong>Lumière</strong>
|
|
||||||
<p>Lux : –</p>
|
|
||||||
</div>
|
|
||||||
<div class="widget graphiques">
|
|
||||||
<span class="icone">📊</span>
|
|
||||||
<strong>Graphiques</strong>
|
|
||||||
<canvas id="graph-temp" width="400" height="150"></canvas>
|
|
||||||
</div>
|
|
||||||
<div class="widget alertes">
|
|
||||||
<span class="icone">⚠️</span>
|
|
||||||
<strong>Alertes</strong>
|
|
||||||
<p>– Aucune alerte pour l'instant –</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
<script src="/smart-house---final-/dashboard.js"></script>
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
<?php
|
|
||||||
// -----------------------------
|
|
||||||
// Fichier de formulaire commun
|
|
||||||
// Compatible PHP 5.x
|
|
||||||
// -----------------------------
|
|
||||||
|
|
||||||
// Définir les valeurs par défaut si elles ne sont pas définies
|
|
||||||
$message = isset($message) ? $message : '';
|
|
||||||
$action = isset($action) ? $action : '';
|
|
||||||
$buttonText = isset($buttonText) ? $buttonText : 'Envoyer';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<?php if($message != ''): ?>
|
|
||||||
<p><?php echo htmlspecialchars($message); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<form method="POST" class="form-box" action="<?php echo htmlspecialchars($action); ?>">
|
|
||||||
<label for="username" class="sr-only">Nom d'utilisateur</label>
|
|
||||||
<input id="username" type="text" name="username" placeholder="Nom d'utilisateur" required>
|
|
||||||
|
|
||||||
<label for="password" class="sr-only">Mot de passe</label>
|
|
||||||
<input id="password" type="password" name="password" placeholder="Mot de passe" required>
|
|
||||||
|
|
||||||
<button type="submit"><?php echo htmlspecialchars($buttonText); ?></button>
|
|
||||||
</form>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<?php
|
|
||||||
$hash = password_hash('Levasseur', PASSWORD_DEFAULT);
|
|
||||||
echo $hash;
|
|
||||||
var_dump(password_verify('Levasseur', $hash));
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
<footer>
|
|
||||||
<p>© 2026 Smart House</p>
|
|
||||||
</footer>
|
|
||||||
<script src="../dashboard.js"></script>
|
|
||||||
<script>
|
|
||||||
function toggleTheme() {
|
|
||||||
const body = document.body;
|
|
||||||
const btn = document.getElementById('toggle-theme');
|
|
||||||
body.classList.toggle('light-mode');
|
|
||||||
|
|
||||||
if (body.classList.contains('light-mode')) {
|
|
||||||
btn.textContent = '🌙';
|
|
||||||
localStorage.setItem('theme', 'light');
|
|
||||||
} else {
|
|
||||||
btn.textContent = '☀️';
|
|
||||||
localStorage.setItem('theme', 'dark');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
const theme = localStorage.getItem('theme');
|
|
||||||
const btn = document.getElementById('toggle-theme');
|
|
||||||
if (theme === 'light') {
|
|
||||||
document.body.classList.add('light-mode');
|
|
||||||
if (btn) btn.textContent = '🌙';
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Smart House</title>
|
|
||||||
<!-- CSS principal -->
|
|
||||||
<link rel="stylesheet" href="/smart-house---final-/style.css">
|
|
||||||
<!-- Chart.js local -->
|
|
||||||
<script src="/smart-house---final-/js/chart.min.js"></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<?php
|
|
||||||
// Inclure la navigation
|
|
||||||
require_once 'nav.php';
|
|
||||||
?>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
<nav>
|
|
||||||
<div class="nav-logo">
|
|
||||||
<span>🏠</span> Smart House
|
|
||||||
</div>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../dashboard.php">Dashboard</a></li>
|
|
||||||
<li><a href="../profil.php">👤 Profil</a></li>
|
|
||||||
<?php if(isset($_SESSION['role']) && $_SESSION['role'] === 'Admin'): ?>
|
|
||||||
<li><a href="../admin_users.php">Utilisateurs</a></li>
|
|
||||||
<li><a href="../admin_settings.php">Paramètres</a></li>
|
|
||||||
<li><a href="../admin_logs.php">Logs</a></li>
|
|
||||||
<?php endif; ?>
|
|
||||||
<li><a href="../logout.php" class="btn-red">Déconnexion</a></li>
|
|
||||||
<!-- suppress JSUnresolvedFunction -->
|
|
||||||
<li><button id="toggle-theme" onclick="toggleTheme()">☀️</button></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
$timeout = 900; // 15 minutes
|
|
||||||
|
|
||||||
$usersFile = __DIR__ . '/../users.json.php';
|
|
||||||
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
|
|
||||||
|
|
||||||
// Vérifier si connecté
|
|
||||||
if (!isset($_SESSION['user'])) {
|
|
||||||
header("Location: login.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si l'utilisateur existe toujours dans users.json.php
|
|
||||||
if (!isset($users[$_SESSION['user']])) {
|
|
||||||
session_destroy();
|
|
||||||
header("Location: login.php?timeout=1");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si le rôle en session correspond toujours au rôle dans users.json.php
|
|
||||||
if ($_SESSION['role'] !== $users[$_SESSION['user']]['role']) {
|
|
||||||
$_SESSION['role'] = $users[$_SESSION['user']]['role'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier l'inactivité
|
|
||||||
if (isset($_SESSION['last_activity'])) {
|
|
||||||
$inactif = time() - $_SESSION['last_activity'];
|
|
||||||
if ($inactif > $timeout) {
|
|
||||||
session_destroy();
|
|
||||||
header("Location: login.php?timeout=1");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mettre à jour le temps de dernière activité
|
|
||||||
$_SESSION['last_activity'] = time();
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="hero">
|
|
||||||
<h2>🏠 Bienvenue sur Smart House</h2>
|
|
||||||
<p>Gérez votre maison intelligente en toute simplicité.<br>Confort, sécurité et énergie au bout des doigts.</p>
|
|
||||||
<a href="dashboard.php" class="btn-primary">Accéder au dashboard</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="cards-home">
|
|
||||||
<div class="card-home">
|
|
||||||
<span class="icone">🌡️</span>
|
|
||||||
<h3>Climat</h3>
|
|
||||||
<p>Surveillez température, humidité et pression.</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-home">
|
|
||||||
<span class="icone">🚨</span>
|
|
||||||
<h3>Sécurité</h3>
|
|
||||||
<p>Gardez un œil sur votre maison en temps réel.</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-home">
|
|
||||||
<span class="icone">⚡</span>
|
|
||||||
<h3>Énergie</h3>
|
|
||||||
<p>Optimisez votre consommation électrique.</p>
|
|
||||||
</div>
|
|
||||||
<div class="card-home">
|
|
||||||
<span class="icone">💡</span>
|
|
||||||
<h3>Lumière</h3>
|
|
||||||
<p>Contrôlez l'éclairage intelligemment.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
0
smart-house---final-/js/chart.min.js
vendored
0
smart-house---final-/js/chart.min.js
vendored
@@ -1,106 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
$usersFile = 'users.json.php';
|
|
||||||
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
|
|
||||||
$message = '';
|
|
||||||
$success = '';
|
|
||||||
|
|
||||||
// Initialiser les tentatives
|
|
||||||
if (!isset($_SESSION['login_attempts'])) {
|
|
||||||
$_SESSION['login_attempts'] = 0;
|
|
||||||
}
|
|
||||||
if (!isset($_SESSION['login_time'])) {
|
|
||||||
$_SESSION['login_time'] = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Message session expirée
|
|
||||||
if (isset($_GET['timeout'])) {
|
|
||||||
$message = "Session expirée. Veuillez vous reconnecter.";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vérifier si bloqué
|
|
||||||
$bloque = false;
|
|
||||||
if ($_SESSION['login_attempts'] >= 3 && $_SESSION['login_time'] !== null) {
|
|
||||||
$temps_ecoule = time() - $_SESSION['login_time'];
|
|
||||||
if ($temps_ecoule < 300) {
|
|
||||||
$bloque = true;
|
|
||||||
$reste = 300 - $temps_ecoule;
|
|
||||||
$message = "Trop de tentatives. Réessayez dans " . ceil($reste / 60) . " minute(s).";
|
|
||||||
} else {
|
|
||||||
$_SESSION['login_attempts'] = 0;
|
|
||||||
$_SESSION['login_time'] = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['registered'])) {
|
|
||||||
$success = "Compte créé avec succès ! En attente de validation par l'administrateur.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$bloque && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$username = trim($_POST['username']);
|
|
||||||
$password = trim($_POST['password']);
|
|
||||||
|
|
||||||
if (isset($users[$username]) && password_verify($password, $users[$username]['password'])) {
|
|
||||||
// Vérifier si le compte est en attente
|
|
||||||
if (isset($users[$username]['statut']) && $users[$username]['statut'] === 'en_attente') {
|
|
||||||
$message = "Votre compte est en attente de validation par l'administrateur.";
|
|
||||||
} else {
|
|
||||||
$_SESSION['login_attempts'] = 0;
|
|
||||||
$_SESSION['login_time'] = null;
|
|
||||||
$_SESSION['user'] = $username;
|
|
||||||
$_SESSION['role'] = $users[$username]['role'];
|
|
||||||
$_SESSION['last_activity'] = time();
|
|
||||||
session_regenerate_id(true);
|
|
||||||
header("Location: dashboard.php");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$_SESSION['login_attempts']++;
|
|
||||||
$_SESSION['login_time'] = time();
|
|
||||||
$restants = 3 - $_SESSION['login_attempts'];
|
|
||||||
if ($restants > 0) {
|
|
||||||
$message = "Identifiants incorrects. Il vous reste $restants essai(s).";
|
|
||||||
} else {
|
|
||||||
$message = "Trop de tentatives. Réessayez dans 5 minutes.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="form-box">
|
|
||||||
<h2>Connexion</h2>
|
|
||||||
<?php if ($success): ?>
|
|
||||||
<p class="form-success"><?php echo htmlspecialchars($success); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($message): ?>
|
|
||||||
<p class="form-error"><?php echo htmlspecialchars($message); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<?php if (!$bloque): ?>
|
|
||||||
<form method="POST" action="login.php">
|
|
||||||
<label class="field-label" for="username">Nom d'utilisateur</label>
|
|
||||||
<input id="username" type="text" name="username" placeholder="Nom d'utilisateur" required>
|
|
||||||
|
|
||||||
<label class="field-label" for="password">Mot de passe</label>
|
|
||||||
<div class="password-wrapper">
|
|
||||||
<input id="password" type="password" name="password" placeholder="Mot de passe" required>
|
|
||||||
<button type="button" class="toggle-password" onclick="togglePassword()">👁️</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Se connecter</button>
|
|
||||||
</form>
|
|
||||||
<p class="form-link">Pas encore de compte ? <a href="register.php">S'inscrire</a></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function togglePassword() {
|
|
||||||
const input = document.getElementById('password');
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
session_destroy();
|
|
||||||
header("Location: login.php");
|
|
||||||
exit();
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<main>
|
|
||||||
<h2>Page principale</h2>
|
|
||||||
<p>Bienvenue sur le site Smart House.</p>
|
|
||||||
</main>
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
$personne1 = [
|
|
||||||
'nom' => 'Exemple',
|
|
||||||
'prenom' => 'Utilisateur',
|
|
||||||
'email' => 'exemple@site.com',
|
|
||||||
'role' => 'Utilisateur',
|
|
||||||
'classe' => 'BTS CIEL'
|
|
||||||
];
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
require_once 'include/session_check.php';
|
|
||||||
include 'include/header.php';
|
|
||||||
|
|
||||||
$usersFile = 'users.json.php';
|
|
||||||
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
|
|
||||||
$message = '';
|
|
||||||
$success = '';
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$ancien = trim($_POST['ancien_password']);
|
|
||||||
$nouveau = trim($_POST['nouveau_password']);
|
|
||||||
$confirm = trim($_POST['confirm_password']);
|
|
||||||
|
|
||||||
if (empty($ancien) || empty($nouveau) || empty($confirm)) {
|
|
||||||
$message = "Veuillez remplir tous les champs.";
|
|
||||||
} elseif (!password_verify($ancien, $users[$_SESSION['user']]['password'])) {
|
|
||||||
$message = "Ancien mot de passe incorrect.";
|
|
||||||
} elseif (strlen($nouveau) < 6) {
|
|
||||||
$message = "Le nouveau mot de passe doit faire au moins 6 caractères.";
|
|
||||||
} elseif ($nouveau !== $confirm) {
|
|
||||||
$message = "Les mots de passe ne correspondent pas.";
|
|
||||||
} else {
|
|
||||||
$users[$_SESSION['user']]['password'] = password_hash($nouveau, PASSWORD_DEFAULT);
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
$success = "Mot de passe modifié avec succès !";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="form-box" style="margin-top: 40px;">
|
|
||||||
<h2>👤 Mon Profil</h2>
|
|
||||||
|
|
||||||
<div class="profil-info">
|
|
||||||
<p><strong>Nom d'utilisateur :</strong> <?php echo htmlspecialchars($_SESSION['user']); ?></p>
|
|
||||||
<p><strong>Rôle :</strong> <?php echo htmlspecialchars($_SESSION['role']); ?></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr style="border-color: #444; margin: 20px 0;">
|
|
||||||
|
|
||||||
<h3 style="margin-bottom: 15px; font-size: 1em;">Changer le mot de passe</h3>
|
|
||||||
|
|
||||||
<?php if ($message): ?>
|
|
||||||
<p class="form-error"><?php echo htmlspecialchars($message); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if ($success): ?>
|
|
||||||
<p class="form-success"><?php echo htmlspecialchars($success); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
|
|
||||||
<form method="POST" action="profil.php">
|
|
||||||
<label class="field-label" for="ancien_password">Ancien mot de passe</label>
|
|
||||||
<div class="password-wrapper">
|
|
||||||
<input id="ancien_password" type="password" name="ancien_password" placeholder="Ancien mot de passe" required>
|
|
||||||
<button type="button" class="toggle-password" onclick="togglePass('ancien_password')">👁️</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="field-label" for="nouveau_password">Nouveau mot de passe</label>
|
|
||||||
<div class="password-wrapper">
|
|
||||||
<input id="nouveau_password" type="password" name="nouveau_password" placeholder="Nouveau mot de passe (6 car. min.)" required>
|
|
||||||
<button type="button" class="toggle-password" onclick="togglePass('nouveau_password')">👁️</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="field-label" for="confirm_password">Confirmer le mot de passe</label>
|
|
||||||
<div class="password-wrapper">
|
|
||||||
<input id="confirm_password" type="password" name="confirm_password" placeholder="Confirmer le mot de passe" required>
|
|
||||||
<button type="button" class="toggle-password" onclick="togglePass('confirm_password')">👁️</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">Changer le mot de passe</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function togglePass(id) {
|
|
||||||
const input = document.getElementById(id);
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
session_start();
|
|
||||||
$usersFile = 'users.json.php';
|
|
||||||
$users = file_exists($usersFile) ? json_decode(file_get_contents($usersFile), true) : [];
|
|
||||||
$message = '';
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|
||||||
$username = trim($_POST['username']);
|
|
||||||
$password = trim($_POST['password']);
|
|
||||||
|
|
||||||
if (empty($username) || empty($password)) {
|
|
||||||
$message = "Veuillez remplir tous les champs.";
|
|
||||||
} elseif (strlen($password) < 6) {
|
|
||||||
$message = "Le mot de passe doit faire au moins 6 caractères.";
|
|
||||||
} elseif (isset($users[$username])) {
|
|
||||||
$message = "Cet utilisateur existe déjà !";
|
|
||||||
} else {
|
|
||||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
|
||||||
$users[$username] = [
|
|
||||||
'password' => $hash,
|
|
||||||
'role' => 'User',
|
|
||||||
'statut' => 'en_attente'
|
|
||||||
];
|
|
||||||
file_put_contents($usersFile, json_encode($users, JSON_PRETTY_PRINT));
|
|
||||||
header("Location: login.php?registered=1");
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
include 'include/header.php';
|
|
||||||
?>
|
|
||||||
|
|
||||||
<div class="form-box">
|
|
||||||
<h2>Créer un compte</h2>
|
|
||||||
<?php if ($message): ?>
|
|
||||||
<p class="form-error"><?php echo htmlspecialchars($message); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<form method="POST" action="register.php">
|
|
||||||
<label class="field-label" for="username">Nom d'utilisateur</label>
|
|
||||||
<input id="username" type="text" name="username" placeholder="Nom d'utilisateur" required>
|
|
||||||
|
|
||||||
<label class="field-label" for="password">Mot de passe</label>
|
|
||||||
<div class="password-wrapper">
|
|
||||||
<input id="password" type="password" name="password" placeholder="Mot de passe (6 car. min.)" required>
|
|
||||||
<button type="button" class="toggle-password" onclick="togglePassword()">👁️</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button type="submit">S'inscrire</button>
|
|
||||||
</form>
|
|
||||||
<p class="form-link">Déjà un compte ? <a href="login.php">Se connecter</a></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function togglePassword() {
|
|
||||||
const input = document.getElementById('password');
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<?php include 'include/footer.php'; ?>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"site_name": "Smart House",
|
|
||||||
"max_attempts": 3,
|
|
||||||
"session_timeout": 900,
|
|
||||||
"welcome_message": "Bienvenue sur votre tableau de bord Smart House."
|
|
||||||
}
|
|
||||||
@@ -1,747 +0,0 @@
|
|||||||
/* ===========================
|
|
||||||
GLOBAL
|
|
||||||
=========================== */
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
color: #f0f0f0;
|
|
||||||
min-height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
main {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
NAVBAR
|
|
||||||
=========================== */
|
|
||||||
nav {
|
|
||||||
background-color: #1a2332;
|
|
||||||
padding: 0 30px;
|
|
||||||
height: 60px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-logo {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 1.2em;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-logo span {
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul {
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul li a {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #ccd6e0;
|
|
||||||
font-size: 0.95em;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul li a:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: rgba(255,255,255,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul li a.btn-red {
|
|
||||||
color: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul li a.btn-red:hover {
|
|
||||||
background-color: #e74c3c;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
#toggle-theme {
|
|
||||||
background: none;
|
|
||||||
border: 1px solid #ccd6e0;
|
|
||||||
color: #ccd6e0;
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.95em;
|
|
||||||
transition: all 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
#toggle-theme:hover {
|
|
||||||
background-color: rgba(255,255,255,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
PAGE ACCUEIL
|
|
||||||
=========================== */
|
|
||||||
.hero {
|
|
||||||
text-align: center;
|
|
||||||
padding: 80px 20px 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero h2 {
|
|
||||||
font-size: 2em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #f0f0f0;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero p {
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 1em;
|
|
||||||
margin-bottom: 25px;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #3bc4e8;
|
|
||||||
color: white;
|
|
||||||
padding: 12px 30px;
|
|
||||||
border-radius: 25px;
|
|
||||||
text-decoration: none;
|
|
||||||
font-weight: bold;
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-primary:hover {
|
|
||||||
background-color: #2aafd0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cards-home {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
gap: 20px;
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: 40px auto;
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-home {
|
|
||||||
background-color: #2c3e50;
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 30px 20px;
|
|
||||||
text-align: center;
|
|
||||||
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-home .icone {
|
|
||||||
font-size: 2em;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-home h3 {
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-home p {
|
|
||||||
font-size: 0.85em;
|
|
||||||
color: #aaa;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
FOOTER
|
|
||||||
=========================== */
|
|
||||||
footer {
|
|
||||||
border-top: 1px solid #333;
|
|
||||||
padding: 15px 30px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 0.85em;
|
|
||||||
color: #888;
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
margin-top: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
footer hr {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
FORMULAIRE LOGIN / REGISTER
|
|
||||||
=========================== */
|
|
||||||
.form-box {
|
|
||||||
width: 360px;
|
|
||||||
margin: 60px auto;
|
|
||||||
padding: 30px;
|
|
||||||
background-color: #2c3e50;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0,0,0,0.4);
|
|
||||||
text-align: center;
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box h2 {
|
|
||||||
margin-bottom: 25px;
|
|
||||||
font-size: 1.3em;
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box h3 {
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box label.field-label {
|
|
||||||
display: block;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 0.85em;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #ccc;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
margin-top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px 12px;
|
|
||||||
border: 1px solid #444;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 0.95em;
|
|
||||||
color: #f0f0f0;
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
transition: border 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #3bc4e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box input::placeholder {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-wrapper {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.password-wrapper input {
|
|
||||||
padding-right: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toggle-password {
|
|
||||||
position: absolute;
|
|
||||||
right: 10px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1em;
|
|
||||||
color: #888;
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box button[type="submit"] {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px;
|
|
||||||
background-color: #3bc4e8;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
border-radius: 25px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-top: 20px;
|
|
||||||
transition: background-color 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box button[type="submit"]:hover {
|
|
||||||
background-color: #2aafd0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-error {
|
|
||||||
color: #e74c3c;
|
|
||||||
font-size: 0.88em;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-success {
|
|
||||||
color: #2ecc71;
|
|
||||||
font-size: 0.88em;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-link {
|
|
||||||
margin-top: 15px;
|
|
||||||
font-size: 0.88em;
|
|
||||||
color: #aaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-link a {
|
|
||||||
color: #3bc4e8;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-link a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
ACCESSIBILITÉ
|
|
||||||
=========================== */
|
|
||||||
.sr-only {
|
|
||||||
position: absolute;
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
padding: 0;
|
|
||||||
margin: -1px;
|
|
||||||
overflow: hidden;
|
|
||||||
clip: rect(0,0,0,0);
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
DASHBOARD
|
|
||||||
=========================== */
|
|
||||||
.dashboard-header {
|
|
||||||
padding: 30px 30px 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-header h2 {
|
|
||||||
color: #f0f0f0;
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-header p {
|
|
||||||
color: #aaa;
|
|
||||||
font-size: 0.95em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(4, 1fr);
|
|
||||||
gap: 15px;
|
|
||||||
padding: 20px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
WIDGETS
|
|
||||||
=========================== */
|
|
||||||
.widget {
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 12px;
|
|
||||||
text-align: center;
|
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
||||||
background-color: #2c3e50;
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.widget strong {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.widget p {
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.climat { background-color: #34495e; }
|
|
||||||
.securite { background-color: #7f8c8d; }
|
|
||||||
.energie { background-color: #f39c12; }
|
|
||||||
.lumiere { background-color: #8e44ad; }
|
|
||||||
|
|
||||||
.graphiques {
|
|
||||||
grid-column: span 4;
|
|
||||||
background-color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alertes {
|
|
||||||
grid-column: span 4;
|
|
||||||
background-color: #c0392b;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
ICONES
|
|
||||||
=========================== */
|
|
||||||
.icone {
|
|
||||||
font-size: 2em;
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
ALERTE ACTIVE
|
|
||||||
=========================== */
|
|
||||||
.alert {
|
|
||||||
border: 2px solid #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
LOGS / ADMIN
|
|
||||||
=========================== */
|
|
||||||
.logs-container {
|
|
||||||
padding: 20px 30px;
|
|
||||||
background-color: #2c3e50;
|
|
||||||
margin: 20px 30px;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logs-container h2 {
|
|
||||||
color: #f0f0f0;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logs-container h3 {
|
|
||||||
color: #f0f0f0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logs-container ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logs-container ul li {
|
|
||||||
padding: 8px 0;
|
|
||||||
border-bottom: 1px solid #3d5166;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
PROFIL
|
|
||||||
=========================== */
|
|
||||||
.profil-info {
|
|
||||||
text-align: left;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profil-info p {
|
|
||||||
padding: 8px 0;
|
|
||||||
border-bottom: 1px solid #3d5166;
|
|
||||||
font-size: 0.95em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profil-info p strong {
|
|
||||||
color: #f0f0f0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
TABLEAU ADMIN
|
|
||||||
=========================== */
|
|
||||||
.admin-table {
|
|
||||||
width: 100%;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-table th {
|
|
||||||
background-color: #1a2332;
|
|
||||||
color: #f0f0f0;
|
|
||||||
padding: 12px 15px;
|
|
||||||
text-align: left;
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-table td {
|
|
||||||
padding: 10px 15px;
|
|
||||||
border-bottom: 1px solid #3d5166;
|
|
||||||
font-size: 0.9em;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-table tr:hover td {
|
|
||||||
background-color: #34495e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-action {
|
|
||||||
padding: 5px 12px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 0.85em;
|
|
||||||
margin-right: 5px;
|
|
||||||
transition: all 0.3s;
|
|
||||||
text-decoration: none;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-danger {
|
|
||||||
background-color: #e74c3c;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-danger:hover {
|
|
||||||
background-color: #c0392b;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-warning {
|
|
||||||
background-color: #f39c12;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-warning:hover {
|
|
||||||
background-color: #d68910;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
SKELETON LOADING
|
|
||||||
=========================== */
|
|
||||||
@keyframes skeleton-pulse {
|
|
||||||
0% { opacity: 1; }
|
|
||||||
50% { opacity: 0.4; }
|
|
||||||
100% { opacity: 1; }
|
|
||||||
}
|
|
||||||
|
|
||||||
.skeleton {
|
|
||||||
background-color: #3d5166;
|
|
||||||
border-radius: 5px;
|
|
||||||
height: 14px;
|
|
||||||
margin: 8px auto;
|
|
||||||
width: 70%;
|
|
||||||
animation: skeleton-pulse 1.5s ease-in-out infinite;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
MODE CLAIR
|
|
||||||
=========================== */
|
|
||||||
body.light-mode {
|
|
||||||
background-color: #f0f2f5;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode nav {
|
|
||||||
background-color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .card-home {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .card-home h3 {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .card-home p {
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .hero h2 {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .hero p {
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .form-box {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
box-shadow: 0 4px 20px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .form-box h2,
|
|
||||||
body.light-mode .form-box h3 {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .form-box label.field-label {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .form-box input {
|
|
||||||
background-color: #f0f2f5;
|
|
||||||
color: #333;
|
|
||||||
border-color: #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .form-box input::placeholder {
|
|
||||||
color: #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .widget {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .widget strong {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .widget p {
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .climat { background-color: #e8f4fd; }
|
|
||||||
body.light-mode .securite { background-color: #f0f0f0; }
|
|
||||||
body.light-mode .energie { background-color: #fff8e1; }
|
|
||||||
body.light-mode .lumiere { background-color: #f3e8ff; }
|
|
||||||
|
|
||||||
body.light-mode .graphiques {
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .alertes {
|
|
||||||
background-color: #fdecea;
|
|
||||||
color: #c0392b;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .logs-container {
|
|
||||||
background-color: #fff;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .logs-container h2,
|
|
||||||
body.light-mode .logs-container h3 {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .logs-container ul li {
|
|
||||||
color: #555;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode footer {
|
|
||||||
background-color: #f0f2f5;
|
|
||||||
border-top: 1px solid #ddd;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode #toggle-theme {
|
|
||||||
border-color: #ccd6e0;
|
|
||||||
color: #ccd6e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .profil-info p {
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
color: #555;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .profil-info p strong {
|
|
||||||
color: #1a2332;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .admin-table th {
|
|
||||||
background-color: #1a2332;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .admin-table td {
|
|
||||||
color: #333;
|
|
||||||
border-bottom: 1px solid #ddd;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .admin-table tr:hover td {
|
|
||||||
background-color: #e8f4fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.light-mode .skeleton {
|
|
||||||
background-color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================
|
|
||||||
RESPONSIVE MOBILE
|
|
||||||
=========================== */
|
|
||||||
|
|
||||||
/* Tablette (max 900px) */
|
|
||||||
@media (max-width: 900px) {
|
|
||||||
.dashboard {
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
.graphiques {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alertes {
|
|
||||||
grid-column: span 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cards-home {
|
|
||||||
grid-template-columns: repeat(2, 1fr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mobile (max 600px) */
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
nav {
|
|
||||||
padding: 10px 15px;
|
|
||||||
height: auto;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul {
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
padding: 10px 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.graphiques {
|
|
||||||
grid-column: span 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.alertes {
|
|
||||||
grid-column: span 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cards-home {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-box {
|
|
||||||
width: 90%;
|
|
||||||
margin: 30px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero {
|
|
||||||
padding: 40px 15px 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hero h2 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logs-container {
|
|
||||||
margin: 10px 15px;
|
|
||||||
padding: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.admin-table {
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-action {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
$usersFile = 'users.json';
|
|
||||||
$users = json_decode(file_get_contents($usersFile), true);
|
|
||||||
|
|
||||||
$username = 'Kari';
|
|
||||||
$password = 'Levasseur';
|
|
||||||
|
|
||||||
echo "Utilisateur existe : ";
|
|
||||||
var_dump(isset($users[$username]));
|
|
||||||
|
|
||||||
echo "Hash stocké : " . $users[$username]['password'] . "<br>";
|
|
||||||
|
|
||||||
echo "Vérification : ";
|
|
||||||
var_dump(password_verify($password, $users[$username]['password']));
|
|
||||||
?>
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"Kari": {
|
|
||||||
"password": "$2y$10$ocJtd5vNxlaQfzBRiueP6.JBNkxNEjh2UviGLXL4aEyXAKuWxBW0.",
|
|
||||||
"role": "Admin"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user