nicolas2-dev / npds-cookie
Complete cookie management library with Cookie and CookieJar classes
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/nicolas2-dev/npds-cookie
Requires
- php: ^8.0
Requires (Dev)
- phpstan/phpstan: ^1.0
- phpunit/phpunit: ^10.0
- squizlabs/php_codesniffer: ^3.0
Suggests
- ext-mbstring: For multibyte string support
This package is auto-updated.
Last update: 2025-12-19 18:09:14 UTC
README
Une bibliothèque PHP complète pour la gestion des cookies HTTP avec une API orientée objet, respectant les standards de sécurité modernes.
Installation
composer require npds/cookie
Table des matières
- Introduction
- Classes principales
- La classe Cookie
- La classe CookieJar
- Exemples complets
- Bonnes pratiques
- API complète
Introduction
Cette bibliothèque fournit une interface orientée objet pour gérer les cookies HTTP en PHP. Elle supporte toutes les fonctionnalités modernes des cookies, y compris SameSite, HttpOnly, Secure, et offre une gestion centralisée via une collection de cookies (CookieJar).
Classes principales
Npds\Cookie\Cookie
Représente un cookie HTTP individuel avec toutes ses propriétés.
Npds\Cookie\CookieJar
Gère une collection de cookies avec des valeurs par défaut et facilite l'envoi des cookies au navigateur.
La classe Cookie
Création d'un cookie simple
use Npds\Cookie\Cookie; // Cookie de session (expire à la fin de la session) $cookie = new Cookie('nom_du_cookie', 'valeur_du_cookie'); // Cookie avec expiration en secondes $cookie = new Cookie('remember_me', 'yes', 3600); // Expire dans 1 heure // Cookie avec tous les paramètres $cookie = new Cookie( 'session_id', 'abc123def456', 3600, // Expire dans 1 heure '/admin', // Chemin 'example.com', // Domaine true, // Secure (HTTPS uniquement) true, // HttpOnly (inaccessible en JavaScript) 'Strict', // SameSite false // Raw (non-encodé) );
Méthodes de fabrication
use Npds\Cookie\Cookie; // Cookie de session (expire à la fin de la session) $sessionCookie = Cookie::createSessionCookie('session', '12345'); // Cookie qui expire dans un délai spécifique $expiringCookie = Cookie::createExpiringCookie('remember', 'yes', 7200); // 2 heures // Cookie qui expire à une date précise $date = new DateTime('+1 day'); $dateCookie = Cookie::createFromDate('newsletter', 'subscribed', $date);
Getters et vérifications
$cookie = new Cookie('test', 'value', 3600); // Récupérer les propriétés $name = $cookie->getName(); // 'test' $value = $cookie->getValue(); // 'value' $expires = $cookie->getExpires(); // Timestamp $path = $cookie->getPath(); // '/' $domain = $cookie->getDomain(); // null $isSecure = $cookie->isSecure(); // false $isHttpOnly = $cookie->isHttpOnly(); // true $sameSite = $cookie->getSameSite(); // 'Lax' // Vérifications $isExpired = $cookie->isExpired(); // false si pas encore expiré $isRaw = $cookie->isRaw(); // false // Vérifier si le cookie correspond à une requête $matches = $cookie->matches('/admin', 'example.com', true);
Méthodes d'immutabilité
$original = new Cookie('test', 'old', 3600); // Créer une copie avec une nouvelle valeur $newCookie = $original->withValue('new'); // Créer une copie avec une nouvelle date d'expiration $newExpiry = $original->withExpires(time() + 7200); // Créer une copie avec un nouveau chemin $newPath = $original->withPath('/api'); // Créer une copie avec un nouveau domaine $newDomain = $original->withDomain('api.example.com'); // Créer une copie avec Secure activé $newSecure = $original->withSecure(true); // Créer une copie avec HttpOnly désactivé $newHttpOnly = $original->withHttpOnly(false); // Créer une copie avec une nouvelle politique SameSite $newSameSite = $original->withSameSite('None'); // Note: nécessite Secure=true
Validation et exceptions
use Npds\Cookie\Cookie; use InvalidArgumentException; try { // Nom invalide (contient des espaces) $cookie = new Cookie('nom invalide', 'value'); } catch (InvalidArgumentException $e) { echo $e->getMessage(); // Le nom du cookie "nom invalide" contient des caractères invalides. } try { // SameSite=None sans Secure $cookie = new Cookie('test', 'value', 3600, null, null, false, null, 'None'); } catch (InvalidArgumentException $e) { echo $e->getMessage(); // Les cookies avec SameSite=None doivent être définis avec secure=true }
La classe CookieJar
Initialisation
use Npds\Cookie\CookieJar; // Avec les valeurs par défaut $jar = new CookieJar(); // Avec des valeurs par défaut personnalisées $jar = new CookieJar( '/api', // Chemin par défaut 'api.example.com', // Domaine par défaut true, // Secure par défaut false, // HttpOnly par défaut 'None' // SameSite par défaut ); // Modifier les valeurs par défaut après création $jar->setDefaultPath('/admin') ->setDefaultDomain('admin.example.com') ->setDefaultSecure(true) ->setDefaultHttpOnly(true) ->setDefaultSameSite('Strict');
Ajouter des cookies
$jar = new CookieJar(); // Méthode générique $jar->set('user_id', '12345', 3600); // Cookie de session $jar->setSessionCookie('session_token', 'abc123def456'); // Cookie qui expire dans un délai $jar->setExpiringCookie('remember_me', 'yes', 86400); // 24 heures // Avec tous les paramètres (écrase les valeurs par défaut) $jar->set( 'preferences', 'dark_mode:true', 31536000, // 1 an '/settings', // Chemin spécifique 'app.example.com', // Domaine spécifique true, // Secure true, // HttpOnly 'Lax', // SameSite false // Raw );
Récupérer et vérifier les cookies
$jar = new CookieJar(); $jar->set('test', 'value'); // Récupérer un cookie $cookie = $jar->get('test'); if ($cookie) { echo $cookie->getValue(); // 'value' } // Vérifier l'existence $hasCookie = $jar->has('test'); // true // Récupérer tous les cookies $allCookies = $jar->all(); // array<string, Cookie> // Compter les cookies $count = $jar->count(); // 1 // Vérifier si le jar est vide $isEmpty = $jar->isEmpty(); // false
Supprimer des cookies
$jar = new CookieJar(); $jar->set('test', 'value', time() + 3600); // Supprimer un cookie (le marque comme expiré) $jar->remove('test'); // Vérifier que le cookie est maintenant expiré $cookie = $jar->get('test'); if ($cookie && $cookie->isExpired()) { echo 'Cookie expiré avec succès'; } // Vider tous les cookies $jar->clear();
Filtrer et rechercher
$jar = new CookieJar(); $jar->set('valid', 'value1', time() + 3600); $jar->set('expired', 'value2', time() - 3600); // Filtrer les cookies expirés $validCookies = $jar->filterExpired(); echo $validCookies->count(); // 1 // Trouver les cookies correspondant à une requête $jar = new CookieJar('/admin', 'example.com'); $jar->set('admin_session', 'abc123'); $jar->set('user_prefs', 'theme:dark'); $matched = $jar->match('/admin/dashboard', 'example.com', true); // Retourne: ['admin_session' => 'abc123', 'user_prefs' => 'theme:dark']
Gestion des en-têtes HTTP
$jar = new CookieJar(); // Ajouter des cookies $jar->set('session', 'abc123', time() + 3600); $jar->set('preferences', 'theme:dark', time() + 86400); // Envoyer tous les cookies au navigateur $jar->send(); // Les cookies sont maintenant envoyés via les en-têtes Set-Cookie // Charger des cookies depuis la requête HTTP $requestCookies = CookieJar::fromRequest(); // $requestCookies contient un tableau associatif des cookies reçus // Charger des cookies dans le jar $jar->load([ 'existing_cookie' => 'value', 'another_cookie' => 'another_value' ]);
Exemples complets
Exemple 1 : Gestion d'une session utilisateur
use Npds\Cookie\CookieJar; class UserSession { private CookieJar $cookieJar; public function __construct() { $this->cookieJar = new CookieJar( '/', // Chemin par défaut $_SERVER['HTTP_HOST'], // Domaine actuel isset($_SERVER['HTTPS']), // Secure si HTTPS true, // HttpOnly pour la sécurité 'Lax' // SameSite par défaut ); } public function login(int $userId, bool $remember = false): void { // Créer un token de session $sessionToken = bin2hex(random_bytes(32)); if ($remember) { // Cookie qui dure 30 jours $this->cookieJar->setExpiringCookie( 'remember_token', $sessionToken, 30 * 24 * 3600, // 30 jours en secondes null, // Utilise le chemin par défaut null, // Utilise le domaine par défaut null, // Utilise Secure par défaut true, // HttpOnly pour la sécurité 'Strict' // SameSite Strict pour plus de sécurité ); } else { // Cookie de session $this->cookieJar->setSessionCookie( 'session_token', $sessionToken ); } // Stocker aussi l'ID utilisateur $this->cookieJar->set( 'user_id', (string) $userId, $remember ? time() + (30 * 24 * 3600) : 0 ); // Envoyer les cookies $this->cookieJar->send(); } public function logout(): void { // Supprimer tous les cookies de session $this->cookieJar->remove('session_token'); $this->cookieJar->remove('remember_token'); $this->cookieJar->remove('user_id'); // Envoyer les cookies supprimés $this->cookieJar->send(); } public function getCurrentUser(): ?int { // Récupérer les cookies de la requête $cookies = CookieJar::fromRequest(); if (isset($cookies['user_id'])) { return (int) $cookies['user_id']; } return null; } }
Exemple 2 : Gestion des préférences utilisateur
use Npds\Cookie\CookieJar; class UserPreferences { private CookieJar $cookieJar; public function __construct() { $this->cookieJar = new CookieJar(); // Configurer pour les préférences $this->cookieJar ->setDefaultPath('/') ->setDefaultHttpOnly(false) // Accessible en JavaScript ->setDefaultSameSite('Lax'); } public function setTheme(string $theme): void { $this->cookieJar->setExpiringCookie( 'theme', $theme, 365 * 24 * 3600, // 1 an null, null, null, false, // Non HttpOnly pour permettre un accès JS 'Lax' ); $this->cookieJar->send(); } public function setLanguage(string $language): void { $this->cookieJar->setExpiringCookie( 'language', $language, 365 * 24 * 3600, null, null, null, false, 'Lax' ); $this->cookieJar->send(); } public function getPreferences(): array { $cookies = CookieJar::fromRequest(); return [ 'theme' => $cookies['theme'] ?? 'light', 'language' => $cookies['language'] ?? 'en', ]; } }
Exemple 3 : Cookies pour une API REST
use Npds\Cookie\CookieJar; class ApiAuth { private CookieJar $cookieJar; public function __construct() { $this->cookieJar = new CookieJar( '/api', 'api.example.com', true, // Toujours Secure pour les APIs true, // HttpOnly pour la sécurité 'None' // SameSite=None pour les requêtes cross-site ); } public function setAuthToken(string $token): void { // Token JWT avec expiration $this->cookieJar->setExpiringCookie( 'auth_token', $token, 3600, // 1 heure '/api/v1', 'api.example.com', true, true, 'None' ); $this->cookieJar->send(); } public function setCsrfToken(string $token): void { // CSRF token accessible en JavaScript $this->cookieJar->setSessionCookie( 'csrf_token', $token, '/api', 'api.example.com', true, false, // Non HttpOnly pour permettre l'accès JS 'Strict' ); $this->cookieJar->send(); } }
Exemple 4 : Gestion des cookies dans un middleware
use Npds\Cookie\CookieJar; class CookieMiddleware { public function handle(Request $request, Closure $next) { // Créer un CookieJar avec les bonnes valeurs par défaut $cookieJar = new CookieJar( '/', $request->getHost(), $request->isSecure(), true, 'Lax' ); // Charger les cookies existants $cookieJar->load($request->cookies->all()); // Ajouter le CookieJar à la requête $request->attributes->set('cookies', $cookieJar); $response = $next($request); // Envoyer les cookies dans la réponse $cookieJar->send(); return $response; } }
Bonnes pratiques
1. Sécurité des cookies de session
// BON - Cookie sécurisé $secureCookie = new Cookie( 'session', $token, time() + 3600, '/', 'example.com', true, // Secure (HTTPS uniquement) true, // HttpOnly (inaccessible en JS) 'Strict' // SameSite Strict ); // MAUVAIS - Cookie non sécurisé $insecureCookie = new Cookie( 'session', $token, time() + 3600, '/', 'example.com', false, // Non Secure false, // Accessible en JS 'Lax' );
2. Gestion des cookies cross-site
// Pour les APIs qui reçoivent des requêtes cross-site $crossSiteCookie = new Cookie( 'api_token', $token, time() + 3600, '/api', 'api.example.com', true, // Doit être Secure true, // HttpOnly recommandé 'None' // SameSite=None pour cross-site ); // Note: SameSite=None nécessite toujours Secure=true
3. Expiration appropriée
// Cookies de session - expirent à la fin du navigateur $sessionCookie = Cookie::createSessionCookie('temp_data', 'value'); // Cookies de préférence - longue durée $prefCookie = Cookie::createExpiringCookie('theme', 'dark', 365 * 24 * 3600); // Cookies d'authentification - durée limitée $authCookie = Cookie::createExpiringCookie('auth_token', $token, 2 * 3600); // 2 heures
4. Validation des entrées
try { $cookie = new Cookie( $_POST['cookie_name'], $_POST['cookie_value'], time() + 3600 ); } catch (InvalidArgumentException $e) { // Gérer l'erreur - nom de cookie invalide throw new Exception('Nom de cookie invalide: ' . $e->getMessage()); } // Pour les valeurs utilisateur, utiliser rawurlencode() $userValue = rawurlencode($_POST['user_data']); $cookie = new Cookie('user_data', $userValue, time() + 3600); // Ou utiliser un cookie Raw (attention aux caractères spéciaux) $rawCookie = new Cookie( 'raw_data', $_POST['data'], time() + 3600, null, null, null, null, null, true );
API complète
Classe Cookie
Constructeur
public function __construct( string $name, string $value = '', $expires = 0, ?string $path = null, ?string $domain = null, ?bool $secure = null, ?bool $httpOnly = null, ?string $sameSite = null, bool $raw = false )
Méthodes de fabrication statiques
createSessionCookie()- Crée un cookie de sessioncreateExpiringCookie()- Crée un cookie avec expiration relativecreateFromDate()- Crée un cookie avec expiration absolue
Getters
getName(): stringgetValue(): stringgetExpires(): intgetPath(): stringgetDomain(): ?stringisSecure(): boolisHttpOnly(): boolgetSameSite(): stringisRaw(): bool
Vérifications
isExpired(): boolmatches(string $path, string $domain, bool $secure): bool
Méthodes immuables
withValue(string $value): selfwithExpires($expires): selfwithPath(string $path): selfwithDomain(?string $domain): selfwithSecure(bool $secure): selfwithHttpOnly(bool $httpOnly): selfwithSameSite(?string $sameSite): self
Conversion
__toString(): string- Format pour l'en-tête Set-Cookie
Classe CookieJar
Constructeur
public function __construct( string $defaultPath = '/', ?string $defaultDomain = null, bool $defaultSecure = false, bool $defaultHttpOnly = true, string $defaultSameSite = Cookie::SAMESITE_LAX )
Gestion des cookies
set()- Ajoute ou modifie un cookiesetSessionCookie()- Ajoute un cookie de sessionsetExpiringCookie()- Ajoute un cookie avec expiration relativeget()- Récupère un cookie par son nomhas()- Vérifie si un cookie existeremove()- Marque un cookie comme expiréclear()- Supprime tous les cookiesall()- Récupère tous les cookies
Information
count(): intisEmpty(): bool
Filtrage et recherche
filterExpired(): self- Retourne un nouveau CookieJar sans les cookies expirésmatch()- Trouve les cookies correspondant à une requêteload()- Charge des cookies depuis un tableau
Gestion des en-têtes
send(): void- Envoie tous les cookies au navigateurfromRequest(): array- Récupère les cookies de la requête actuelle
Configuration des valeurs par défaut
setDefaultPath()- Définit le chemin par défautsetDefaultDomain()- Définit le domaine par défautsetDefaultSecure()- Définit Secure par défautsetDefaultHttpOnly()- Définit HttpOnly par défautsetDefaultSameSite()- Définit SameSite par défaut
Conclusion
Ce package offre une solution complète et sécurisée pour la gestion des cookies en PHP. Avec son API orientée objet, il facilite la création, la manipulation et l'envoi de cookies tout en respectant les meilleures pratiques de sécurité.
Les principales fonctionnalités incluent :
- Support complet des attributs de cookies modernes
- Gestion centralisée avec CookieJar
- Validation robuste des données
- API immuable pour une programmation plus sûre
- Compatibilité avec les standards HTTP
Pour toute question ou problème, consultez la documentation ou ouvrez une issue sur le repository du projet.