Système PHP complet pour gérer le consentement des cookies avec catégories, granularité, journal des modifications et conformité RGPD.
<?php
// config.php - configuration base de données et catégories de cookies
return [
'db' => [
'host' => 'localhost',
'dbname' => 'cookie_consent',
'user' => 'dbuser',
'pass' => 'dbpassword',
'charset' => 'utf8mb4'
],
'cookie_categories' => [
'necessari' => 'Cookies nécessaires au fonctionnement du site',
'funzionali' => 'Cookies améliorant l\'expérience utilisateur',
'analitici' => 'Cookies pour analyses statistiques anonymes',
'marketing' => 'Cookies pour campagnes publicitaires personnalisées'
]
];
// db.php - classe pour gestion de la connexion PDO
class Database {
private static ?\PDO $pdo = null;
public static function getConnection(): \PDO {
if (self::$pdo === null) {
$config = require __DIR__ . '/config.php';
$db = $config['db'];
$dsn = "mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}";
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
try {
self::$pdo = new \PDO($dsn, $db['user'], $db['pass'], $options);
} catch (\PDOException $e) {
// Gestion erreur de connexion
die('Erreur de connexion DB : ' . $e->getMessage());
}
}
return self::$pdo;
}
}
// consent_manager.php - classe pour gestion des consentements et journal
class ConsentManager {
private \PDO $pdo;
private array $categories;
public function __construct() {
$this->pdo = Database::getConnection();
$config = require __DIR__ . '/config.php';
$this->categories = $config['cookie_categories'];
session_start(); // pour gestion utilisateur
}
/**
* Récupère les consentements actuels pour l'utilisateur
* @param int|null $userId
* @return array
*/
public function getUserConsents(?int $userId): array {
if ($userId === null) {
return [];
}
$stmt = $this->pdo->prepare('SELECT categoria, accettato FROM consensi_cookie WHERE user_id = ?');
$stmt->execute([$userId]);
$result = $stmt->fetchAll();
$consents = [];
foreach ($result as $row) {
$consents[$row['categoria']] = (bool)$row['accettato'];
}
return $consents;
}
/**
* Sauvegarde les consentements fournis par l'utilisateur et enregistre le journal
* @param int $userId
* @param array $consents tableau associatif catégorie => bool
* @return bool
*/
public function saveUserConsents(int $userId, array $consents): bool {
// Validation des catégories
foreach ($consents as $cat => $val) {
if (!array_key_exists($cat, $this->categories)) {
throw new InvalidArgumentException("Catégorie de cookie non valide : $cat");
}
}
try {
$this->pdo->beginTransaction();
// Récupère les consentements actuels pour comparaison
$oldConsents = $this->getUserConsents($userId);
// Insertion ou mise à jour des consentements
$stmtInsert = $this->pdo->prepare(
'INSERT INTO consensi_cookie (user_id, categoria, accettato) VALUES (?, ?, ?)'
. ' ON DUPLICATE KEY UPDATE accettato = VALUES(accettato)'
);
foreach ($this->categories as $cat => $_) {
$accepted = isset($consents[$cat]) ? (bool)$consents[$cat] : false;
$stmtInsert->execute([$userId, $cat, $accepted ? 1 : 0]);
// Si le consentement a changé, enregistrer le log
$oldVal = $oldConsents[$cat] ?? null;
if ($oldVal !== $accepted) {
$this->logChange($userId, $cat, $oldVal, $accepted);
}
}
$this->pdo->commit();
return true;
} catch (\Exception $e) {
$this->pdo->rollBack();
error_log('Erreur sauvegarde consentements : ' . $e->getMessage());
return false;
}
}
/**
* Enregistre une modification de consentement dans le journal
* @param int $userId
* @param string $categoria
* @param bool|null $oldValue
* @param bool $newValue
* @return void
*/
private function logChange(int $userId, string $categoria, ?bool $oldValue, bool $newValue): void {
$stmt = $this->pdo->prepare('INSERT INTO log_consensi (user_id, categoria, vecchio_valore, nuovo_valore, ip, timestamp) VALUES (?, ?, ?, ?, ?, NOW())');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$stmt->execute([
$userId,
$categoria,
$oldValue === null ? null : ($oldValue ? 1 : 0),
$newValue ? 1 : 0,
$ip
]);
}
}
// Exemple d'utilisation dans un endpoint API (save_consent.php)
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
header('Content-Type: application/json');
// Simulation d'utilisateur authentifié avec ID en session
session_start();
$userId = $_SESSION['user_id'] ?? null;
if ($userId === null) {
http_response_code(401);
echo json_encode(['error' => 'Utilisateur non authentifié']);
exit;
}
$input = json_decode(file_get_contents('php://input'), true);
if (!is_array($input)) {
http_response_code(400);
echo json_encode(['error' => 'Entrée non valide']);
exit;
}
$consentManager = new ConsentManager();
try {
$success = $consentManager->saveUserConsents($userId, $input);
if ($success) {
echo json_encode(['success' => true]);
} else {
http_response_code(500);
echo json_encode(['error' => 'Erreur sauvegarde consentements']);
}
} catch (InvalidArgumentException $e) {
http_response_code(400);
echo json_encode(['error' => $e->getMessage()]);
}
}
// Schéma des tables SQL (à exécuter une fois)
/*
CREATE TABLE utenti (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE consensi_cookie (
user_id INT NOT NULL,
categoria VARCHAR(50) NOT NULL,
accettato TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (user_id, categoria),
FOREIGN KEY (user_id) REFERENCES utenti(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE log_consensi (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
categoria VARCHAR(50) NOT NULL,
vecchio_valore TINYINT(1) NULL,
nuovo_valore TINYINT(1) NOT NULL,
ip VARCHAR(45) NOT NULL,
timestamp DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES utenti(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
*/
?><?php
// Exemple complet minimal pour tester le système de gestion du consentement des cookies
// Inclure le code original tel quel
// config.php
file_put_contents(__DIR__ . '/config.php', <<<'CONFIG'
<?php
return [
'db' => [
'host' => 'localhost',
'dbname' => 'cookie_consent',
'user' => 'dbuser',
'pass' => 'dbpassword',
'charset' => 'utf8mb4'
],
'cookie_categories' => [
'necessari' => 'Cookies nécessaires au fonctionnement du site',
'funzionali' => 'Cookies améliorant l\'expérience utilisateur',
'analitici' => 'Cookies pour analyses statistiques anonymes',
'marketing' => 'Cookies pour campagnes publicitaires personnalisées'
]
];
CONFIG
);
// db.php
file_put_contents(__DIR__ . '/db.php', <<<'DB'
<?php
class Database {
private static ?\PDO $pdo = null;
public static function getConnection(): \PDO {
if (self::$pdo === null) {
$config = require __DIR__ . '/config.php';
$db = $config['db'];
$dsn = "mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}";
$options = [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_EMULATE_PREPARES => false,
];
try {
self::$pdo = new \PDO($dsn, $db['user'], $db['pass'], $options);
} catch (\PDOException $e) {
die('Erreur de connexion DB : ' . $e->getMessage());
}
}
return self::$pdo;
}
}
DB
);
// consent_manager.php
file_put_contents(__DIR__ . '/consent_manager.php', <<<'CONSENT'
<?php
class ConsentManager {
private \PDO $pdo;
private array $categories;
public function __construct() {
$this->pdo = Database::getConnection();
$config = require __DIR__ . '/config.php';
$this->categories = $config['cookie_categories'];
if(session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
}
public function getUserConsents(?int $userId): array {
if ($userId === null) {
return [];
}
$stmt = $this->pdo->prepare('SELECT categoria, accettato FROM consensi_cookie WHERE user_id = ?');
$stmt->execute([$userId]);
$result = $stmt->fetchAll();
$consents = [];
foreach ($result as $row) {
$consents[$row['categoria']] = (bool)$row['accettato'];
}
return $consents;
}
public function saveUserConsents(int $userId, array $consents): bool {
foreach ($consents as $cat => $val) {
if (!array_key_exists($cat, $this->categories)) {
throw new InvalidArgumentException("Catégorie de cookie non valide : $cat");
}
}
try {
$this->pdo->beginTransaction();
$oldConsents = $this->getUserConsents($userId);
$stmtInsert = $this->pdo->prepare(
'INSERT INTO consensi_cookie (user_id, categoria, accettato) VALUES (?, ?, ?)'
. ' ON DUPLICATE KEY UPDATE accettato = VALUES(accettato)'
);
foreach ($this->categories as $cat => $_) {
$accepted = isset($consents[$cat]) ? (bool)$consents[$cat] : false;
$stmtInsert->execute([$userId, $cat, $accepted ? 1 : 0]);
$oldVal = $oldConsents[$cat] ?? null;
if ($oldVal !== $accepted) {
$this->logChange($userId, $cat, $oldVal, $accepted);
}
}
$this->pdo->commit();
return true;
} catch (\Exception $e) {
$this->pdo->rollBack();
error_log('Erreur sauvegarde consentements : ' . $e->getMessage());
return false;
}
}
private function logChange(int $userId, string $categoria, ?bool $oldValue, bool $newValue): void {
$stmt = $this->pdo->prepare('INSERT INTO log_consensi (user_id, categoria, vecchio_valore, nuovo_valore, ip, timestamp) VALUES (?, ?, ?, ?, ?, NOW())');
$ip = $_SERVER['REMOTE_ADDR'] ?? 'unknown';
$stmt->execute([
$userId,
$categoria,
$oldValue === null ? null : ($oldValue ? 1 : 0),
$newValue ? 1 : 0,
$ip
]);
}
}
CONSENT
);
// Création des tables SQL pour test (exécuter une seule fois)
// Ici on suppose que la base de données 'cookie_consent' existe et que l'utilisateur a les droits
try {
$pdo = Database::getConnection();
$pdo->exec("CREATE TABLE IF NOT EXISTS utenti (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(100) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
$pdo->exec("CREATE TABLE IF NOT EXISTS consensi_cookie (
user_id INT NOT NULL,
categoria VARCHAR(50) NOT NULL,
accettato TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (user_id, categoria),
FOREIGN KEY (user_id) REFERENCES utenti(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
$pdo->exec("CREATE TABLE IF NOT EXISTS log_consensi (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
categoria VARCHAR(50) NOT NULL,
vecchio_valore TINYINT(1) NULL,
nuovo_valore TINYINT(1) NOT NULL,
ip VARCHAR(45) NOT NULL,
timestamp DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES utenti(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
// Insérer un utilisateur de test si pas existant
$stmt = $pdo->prepare('SELECT id FROM utenti WHERE username = ?');
$stmt->execute(['testuser']);
$user = $stmt->fetch();
if (!$user) {
$passwordHash = password_hash('testpass', PASSWORD_DEFAULT);
$stmtInsert = $pdo->prepare('INSERT INTO utenti (username, password_hash) VALUES (?, ?)');
$stmtInsert->execute(['testuser', $passwordHash]);
$userId = $pdo->lastInsertId();
} else {
$userId = $user['id'];
}
} catch (\PDOException $e) {
die('Erreur lors de la création des tables ou insertion utilisateur : ' . $e->getMessage());
}
// Simulation d'une session utilisateur
if(session_status() !== PHP_SESSION_ACTIVE) {
session_start();
}
$_SESSION['user_id'] = (int)$userId;
// Test de sauvegarde des consentements
$consentManager = new ConsentManager();
// Exemple de consentements à sauvegarder
$consents = [
'necessari' => true,
'funzionali' => false,
'analitici' => true,
'marketing' => false
];
$success = $consentManager->saveUserConsents($userId, $consents);
if ($success) {
echo "Consentements sauvegardés avec succès.\n";
$savedConsents = $consentManager->getUserConsents($userId);
echo "Consentements actuels pour l'utilisateur :\n";
print_r($savedConsents);
} else {
echo "Erreur lors de la sauvegarde des consentements.\n";
}
?>Backend PHP 8+ avec PDO pour un accès sécurisé à la base de données MySQL/MariaDB
Base de données MySQL avec tables : utilisateurs, consensi_cookie, log_consensi
Frontend HTML5 + JavaScript pour interface utilisateur de sélection des catégories de cookies
Fichier de configuration PHP pour définition des catégories de cookies et paramètres DB
Système de journalisation personnalisé pour tracer les modifications des consentements
Dépendances logicielles : extension PDO activée, session PHP active
Configuration base de données : hôte, nom db, utilisateur, mot de passe dans le fichier config.php
Aucun matériel Arduino requis pour ce projet