Huymada

Cookie

Aug 22nd, 2019 (edited)
447
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 4.81 KB | None | 0 0
  1. <?php
  2. /**
  3.  * Cookie - Controle de cookies com segurança e boas práticas
  4.  * @version 2.0
  5.  */
  6. class Cookie {
  7.  
  8.     /**
  9.      * Nome do cookie
  10.      */
  11.     public string $name = '';
  12.  
  13.     /**
  14.      * Tempo de vida em segundos (padrão: 7 dias)
  15.      */
  16.     public int $ttl = 3600 * 24 * 7;
  17.  
  18.     /**
  19.      * Opções de segurança do cookie
  20.      * secure   → só trafega via HTTPS
  21.      * httponly → inacessível via JavaScript (protege contra XSS)
  22.      * samesite → protege contra CSRF (Lax cobre a maioria dos casos)
  23.      */
  24.     public array $options = [
  25.         'path'     => '/',
  26.         'secure'   => true,
  27.         'httponly' => true,
  28.         'samesite' => 'Lax',
  29.     ];
  30.  
  31.     /**
  32.      * Dados armazenados no cookie
  33.      */
  34.     private array $data = [];
  35.  
  36.     // -------------------------------------------------------------------------
  37.  
  38.     /**
  39.      * Lê o cookie existente ou cria um novo vazio
  40.      *
  41.      * O JSON vindo do cliente é validado — se vier adulterado ou inválido,
  42.      * o cookie é resetado para um array vazio.
  43.      */
  44.     public function __construct() {
  45.         if (!empty($this->name) && isset($_COOKIE[$this->name])) {
  46.             $decoded    = json_decode($_COOKIE[$this->name], true);
  47.             $this->data = is_array($decoded) ? $decoded : [];
  48.         }
  49.     }
  50.  
  51.     // -------------------------------------------------------------------------
  52.     // LEITURA
  53.     // -------------------------------------------------------------------------
  54.  
  55.     /**
  56.      * Verifica se uma chave existe no cookie
  57.      *
  58.      * @example
  59.      *   if ($cookie->has('user_id')) { ... }
  60.      */
  61.     public function has(string $key): bool {
  62.         return isset($this->data[$key]);
  63.     }
  64.  
  65.     /**
  66.      * Retorna o valor de uma chave, ou um valor padrão se não existir
  67.      *
  68.      * @param  string $key      Chave a buscar
  69.      * @param  mixed  $default  Valor retornado se a chave não existir (padrão: null)
  70.      * @return mixed
  71.      *
  72.      * @example
  73.      *   $theme = $cookie->get('theme', 'light');
  74.      */
  75.     public function get(string $key, mixed $default = null): mixed {
  76.         return $this->data[$key] ?? $default;
  77.     }
  78.  
  79.     /**
  80.      * Retorna todos os dados do cookie como array associativo
  81.      *
  82.      * @example
  83.      *   $all = $cookie->all();
  84.      *   foreach ($all as $key => $value) { ... }
  85.      */
  86.     public function all(): array {
  87.         return $this->data;
  88.     }
  89.  
  90.     // -------------------------------------------------------------------------
  91.     // ESCRITA
  92.     // -------------------------------------------------------------------------
  93.  
  94.     /**
  95.      * Adiciona ou atualiza um valor no cookie
  96.      *
  97.      * @throws RuntimeException se headers já foram enviados
  98.      *
  99.      * @example
  100.      *   $cookie->add('theme', 'dark');
  101.      *   $cookie->add('user_id', 42);
  102.      */
  103.     public function add(string $key, mixed $value): void {
  104.         $this->data[$key] = $value;
  105.         $this->update();
  106.     }
  107.  
  108.     /**
  109.      * Remove uma chave do cookie
  110.      * Não lança erro se a chave não existir
  111.      *
  112.      * @throws RuntimeException se headers já foram enviados
  113.      *
  114.      * @example
  115.      *   $cookie->del('theme');
  116.      */
  117.     public function del(string $key): void {
  118.         unset($this->data[$key]);
  119.         $this->update();
  120.     }
  121.  
  122.     /**
  123.      * Persiste o estado atual do cookie no browser
  124.      * Chamado automaticamente por add() e del()
  125.      *
  126.      * @throws RuntimeException se headers já foram enviados
  127.      */
  128.     public function update(): void {
  129.         $this->send($this->name, json_encode($this->data), time() + $this->ttl);
  130.     }
  131.  
  132.     /**
  133.      * Remove todos os dados e apaga o cookie do browser
  134.      * Para apagar um cookie é necessário setar expires no passado
  135.      *
  136.      * @throws RuntimeException se headers já foram enviados
  137.      *
  138.      * @example
  139.      *   $cookie->logout();
  140.      */
  141.     public function logout(): void {
  142.         $this->data = [];
  143.         $this->send($this->name, '', time() - 3600);
  144.     }
  145.  
  146.     // -------------------------------------------------------------------------
  147.     // INTERNO
  148.     // -------------------------------------------------------------------------
  149.  
  150.     /**
  151.      * Envia o cookie com as opções de segurança configuradas
  152.      * Verifica se os headers já foram enviados antes de tentar
  153.      *
  154.      * @throws RuntimeException
  155.      */
  156.     private function send(string $name, string $value, int $expires): void {
  157.         if (headers_sent($file, $line)) {
  158.             throw new RuntimeException(
  159.                 "Não é possível definir o cookie '{$name}' — "
  160.                 . "headers já enviados em {$file}:{$line}"
  161.             );
  162.         }
  163.  
  164.         setcookie($name, $value, array_merge($this->options, [
  165.             'expires' => $expires,
  166.         ]));
  167.     }
  168.  
  169. }
Advertisement
Add Comment
Please, Sign In to add comment