Ves al contingut principal

Les cookies

Les cookies en PHP són una eina fonamental per gestionar l'estat en el protocol HTTP (que és sense estat). Una cookie és un petit fragment de dades (un parell clau-valor) que un servidor envia al navegador web de l'usuari. El navegador l'emmagatzema i la retorna al servidor amb cada petició posterior, permetent que el servidor "recordi" l'usuari o les seves preferències.

Funcionament de les Cookies en PHP

El procés de creació i ús d'una cookie amb PHP es basa en la comunicació mitjançant capçaleres HTTP:

  1. Creació (Servidor a Client): Quan un script PHP vol crear o modificar una cookie, utilitza la funció setcookie(). Aquesta funció no escriu immediatament la cookie al navegador, sinó que afegeix una capçalera HTTP anomenada Set-Cookie a la resposta del servidor.

    • Restricció Crítica: La capçalera Set-Cookie (i per tant la funció setcookie()) ha de ser enviada abans que qualsevol sortida (output) de l'script (HTML, espais en blanc, etc.). Si PHP ja ha començat a enviar el cos de la pàgina, no pot enviar capçaleres addicionals, i la funció fallarà, provocant un error de tipus "Headers already sent".

  2. Emmagatzematge (Client): El navegador web de l'usuari rep la capçalera Set-Cookie i desa el parell clau-valor de manera local.

  3. Transmissió (Client a Servidor): En cada petició posterior que l'usuari faci al domini corresponent, el navegador inclou automàticament la cookie en la capçalera HTTP de la petició, anomenada simplement Cookie.

  4. Lectura (Servidor amb PHP): PHP llegeix la capçalera Cookie rebuda i omple automàticament la variable superglobal $_COOKIE. El script pot accedir a les dades de la cookie com si fos un array associatiu ($_COOKIE['nom_cookie']).


Exemple d'Ús amb PHP

Per manipular les cookies utilitzem principalment dues eines en PHP: la funció setcookie() per crear-les i la variable $_COOKIE per llegir-les.

- Establir una Cookie

La sintaxi bàsica de setcookie() és:

PHP

// Ha d'estar abans de <html> o echo!

// Cookie de sessió (expira al tancar el navegador)
setcookie("usuari", "JordiCatalà"); 

// Cookie persistent (expira en 30 dies)
$expiracio = time() + (86400 * 30); // 86400 segons = 1 dia
setcookie("preferencia_idioma", "ca", $expiracio, "/"); 
// Els paràmetres addicionals (path, secure, httponly) són opcionals i clau per la seguretat.

- Llegir i Eliminar una Cookie

PHP

<?php
// Llegir una cookie
if (isset($_COOKIE['preferencia_idioma'])) {
    $idioma_seleccionat = $_COOKIE['preferencia_idioma'];
    echo "L'usuari prefereix l'idioma: " . $idioma_seleccionat;
} else {
    echo "No s'ha trobat cap preferència d'idioma.";
}

// Eliminar una cookie
// Per eliminar-la, es crida setcookie() amb una data d'expiració en el passat.
setcookie("usuari", "", time() - 3600); // El valor i la data d'expiració es mouen cap enrere

Avantatges de les Cookies

Avantatge Descripció Detallada
Persistència d'Estat Permeten mantenir la informació d'una petició a l'altra, simulant una "memòria" en HTTP.
Empremta Lleugera Són petits fitxers de text que no requereixen recursos del servidor per emmagatzemar la dada.
Identificació d'Usuari Són essencials per a funcions de "Recorda'm" (autologin) i per a la implementació de sessions (la cookie de sessió només conté l'identificador de la sessió).
Personalització Permeten desar preferències d'usuari (idioma, tema, tipus de lletra) sense haver de passar per una base de dades.

Inconvenients de les Cookies

Inconvenient Descripció Detallada
Límit de Mida La majoria de navegadors limiten la mida a 4 KB per cookie i a unes 20-50 cookies per domini. No són aptes per emmagatzemar grans quantitats de dades.
Riscos de Seguretat Si s'emmagatzema informació sensible (com una contrasenya) sense xifrar, pot ser compromesa fàcilment, ja que es transmeten en cada petició. Això es mitiga usant els atributs Secure i HttpOnly.
Control del Client Les cookies s'emmagatzemen al costat del client, cosa que significa que l'usuari pot esborrar-les, modificar-les o directament deshabilitar-les al seu navegador.
Regulació (GDPR/LSSI) A causa de la seva funció de rastreig, les cookies (especialment les de tercers) estan subjectes a estrictes normatives de privacitat i requereixen el consentiment explícit de l'usuari abans de ser establertes.
Retard de Latència Com que es reenvien amb cada petició HTTP (fins i tot per a imatges o fitxers estàtics), poden afegir un petit overhead de latència, especialment si són moltes i grans.

La funció setcookie()

La funció setcookie() de PHP és l'eina primària per crear i gestionar cookies. S'encarrega d'enviar la capçalera HTTP Set-Cookie des del servidor al navegador de l'usuari, que és l'encarregat d'emmagatzemar la dada.

Per protocol, setcookie() ha de ser cridada abans que qualsevol output (sortida) es generi a l'script (com ara HTML, echo, print, o fins i tot espais en blanc abans de l'etiqueta <?php).

- Paràmetres de setcookie()

La funció accepta fins a set paràmetres (o vuit a PHP 7.3+ si s'utilitza l'array d'opcions):

Posició Nom del Paràmetre Requerit Descripció
1 name Sí El nom de la cookie. Aquest nom s'utilitzarà per accedir a la dada a través de $_COOKIE['name'].
2 value No El valor de la cookie. La dada que es vol emmagatzemar (ex: un ID d'usuari). Aquest valor es codifica automàticament a URL.
3 expire No El temps d'expiració de la cookie com a timestamp UNIX. Si s'estableix a 0 (per defecte), la cookie expirarà quan l'usuari tanqui el navegador (és a dir, serà una cookie de sessió).
4 path No El camí del servidor on la cookie estarà disponible. Utilitzar "/" la fa accessible a tot el domini. El valor per defecte és el directori actual on es crida setcookie().
5 domain No El domini pel qual la cookie està disponible (ex: "exemple.cat"). Per fer-la accessible també als subdominis (ex: blog.exemple.cat), s'ha d'anteposar un punt (ex: ".exemple.cat").
6 secure No Booleà. Si es posa a true, la cookie només s'enviarà a través de connexions HTTPS segures. És una bona pràctica de seguretat.
7 httponly No Booleà. Si es posa a true, la cookie serà inaccessible per llenguatges de scripting del costat del client (com JavaScript). Ajuda a mitigar atacs de Cross-Site Scripting (XSS).

Aquesta cookie només existirà mentre el navegador estigui obert.

PHP

<?php
// Usuari ha iniciat sessió. 
// La cookie expira quan es tanca el navegador (expire = 0 per defecte).
setcookie("session_id", "abc12345def67890", 0, "/");

echo "Cookie de sessió establerta.";
// L'usuari veurà la cookie la propera vegada que carregui una pàgina.

PHP
<?php
// Temps d'expiració: ara + (segons en un dia * 7 dies)
$expiracio_7_dies = time() + (86400 * 7); 
$path_total = "/"; 
$domini = "exemple.cat"; // La cookie és vàlida per a exemple.cat

setcookie(
    "tema_preferit", // name
    "foscur",        // value
    $expiracio_7_dies, // expire
    $path_total,     // path
    $domini,         // domain
    true,            // secure (Només HTTPS)
    true             // httponly (No accessible per JS)
);

echo "Cookie persistent establerta per 7 dies.";

Exemple 3: Eliminar una Cookie

Per eliminar una cookie, s'ha de cridar setcookie() amb el mateix nom, el mateix path i el mateix domain, i establir el temps d'expiració a una data passada.

PHP

<?php
// Només cal establir l'expiració en el passat i igualar el path i el domini si es van utilitzar
setcookie("tema_preferit", "", time() - 3600, "/", "exemple.cat");

echo "Cookie 'tema_preferit' eliminada.";

// La cookie desapareixerà del navegador de l'usuari després d'aquesta petició.

- Ús de l'Array d'Opcions (PHP 7.3+)

A partir de PHP 7.3, es pot utilitzar una sintaxi més llegible passant un array d'opcions com a tercer paràmetre, en lloc de passar tots els valors individuals. Això permet incloure opcions avançades com l'atribut SameSite (crític per la seguretat web moderna).

Clau de l'Array Equival a Paràmetre
'expires' expire (timestamp)
'path' path
'domain' domain
'secure' secure (booleà)
'httponly' httponly (booleà)
'samesite' Nou. Pot ser 'Strict', 'Lax' o 'None'.
PHP

<?php
$opcions = [
    'expires'  => time() + 3600, // Expira en 1 hora
    'path'     => '/',
    'domain'   => '.aplicacio.com',
    'secure'   => true, 
    'httponly' => true,
    'samesite' => 'Lax' // Millora la seguretat contra CSRF
];

// setcookie(name, value, array $options)
setcookie('token_remember', 'abcdef123456', $opcions);

echo "Cookie amb opcions de seguretat modernes establerta.";

- El paràmetre samesite (PHP 7.3+)

El paràmetre SameSite és un atribut de seguretat fonamental per a les cookies que va ser introduït per mitigar un tipus de vulnerabilitat web molt comú: els atacs de Falsificació de Peticions en Llocs Creuats (Cross-Site Request Forgery o CSRF).

Aquest paràmetre controla si una cookie ha de ser enviada automàticament pel navegador quan la petició s'origina des d'un lloc web diferent al que va establir la cookie.

Funcionament i Tipus de Valors

L'atribut SameSite es configura en la capçalera Set-Cookie enviada pel servidor i accepta tres valors principals: Lax, Strict i None.

1. SameSite=Lax (Recomanat per Defecte)

Aquest és el mode d'equilibri, i el valor recomanat per la majoria d'aplicacions:

  • Com funciona: La cookie NO s'envia quan la petició es fa des d'un lloc extern (tercer) mitjançant mètodes insegurs com POST.

  • Excepció: La cookie SÍ s'envia si la navegació des del lloc extern es fa a través d'un mètode segur (GET), com en el cas d'un clic en un enllaç o la càrrega d'una imatge.

  • Ús: És ideal per a cookies que mantenen la sessió (com les de PHP, si no s'utilitza Strict), ja que permet que els usuaris puguin arribar al vostre lloc a través d'enllaços externs sense perdre la sessió immediatament, alhora que ofereix protecció contra CSRF bàsic.

2. SameSite=Strict (Màxima Seguretat)

Aquest mode ofereix la màxima protecció contra atacs CSRF.

  • Com funciona: La cookie MAI s'envia si la petició es fa des d'un context de lloc creuat (cross-site), independentment del mètode HTTP utilitzat.

  • Ús: S'ha d'utilitzar per a cookies que gestionen estats d'alta seguretat o accions molt sensibles (per exemple, les cookies que s'utilitzen per confirmar una operació financera o canvis de contrasenya).

  • Inconvenient: Si un usuari inicia sessió i després fa clic en un enllaç al vostre propi lloc web des d'un correu electrònic o una altra aplicació, la cookie de sessió no s'enviarà, i l'usuari semblarà que no ha iniciat sessió.

3. SameSite=None (Sense Protecció)

Aquest valor inhabilita completament la protecció i permet l'enviament de la cookie en totes les peticions de lloc creuat.

  • Com funciona: La cookie S'envia sempre amb les peticions de lloc creuat.

  • Requeriment: Quan s'utilitza SameSite=None, la cookie HA D'incloure obligatòriament l'atribut Secure (és a dir, només es pot enviar a través de HTTPS).

  • Ús: Només s'ha d'utilitzar quan la cookie és estrictament necessària per a la funcionalitat d'un tercer (per exemple, widgets incrustats, píxels de seguiment o serveis publicitaris).


Exemple d'Implementació amb PHP

A partir de PHP 7.3, l'atribut SameSite es configura millor mitjançant l'array d'opcions a la funció setcookie():

PHP

Importància en la Seguretat (CSRF)

Sense l'atribut SameSite, un atacant podria fer que un usuari iniciat en una aplicació (per exemple, un banc) fes clic en un enllaç o carregués una imatge en un lloc web maliciós. Aquest lloc web maliciós podria enviar una petició amagada al banc (per exemple, de transferència de fons).

Com que el navegador de la víctima automàticament adjuntaria la cookie de sessió del banc a aquesta petició (perquè els navegadors antigament feien això per defecte), el banc la processaria com una acció legítima.

L'atribut SameSite impedeix aquest comportament en la majoria de casos, ja que instruccions com Lax o Strict fan que la cookie no s'adjunti a la petició iniciada des del lloc maliciós, neutralitzant l'atac.