PHP: Cookies e Sessões Programação de Servidores Marx Gomes Van der Linden Protocolo HTTP O protocolo HTTP não tem conceito de sessões. Modelo simples de Requisição e Resposta. http://marx.vanderlinden.com.br/ 2 Protocolo HTTP Tipicamente, vários usuários estão acessando o servidor web ao mesmo tempo. HTTP não define uma maneira direta de se rastrear cada usuário e dar continuidade individual às atividades de requisições anteriores. http://marx.vanderlinden.com.br/ 3 Cookies Um Cookie é um arquivo de texto que pode ser criado pelo navegador, a pedido do servidor web. Cada cookie tem um conjunto de variáveis: nome=valor Todo cookie é necessariamente associado ao um site (ou domínio) que o criou e, teoricamente, não pode ser acessado por outros sites. http://marx.vanderlinden.com.br/ 4 Cookies O cookie é reenviado automaticamente ao servidor a cada nova visita à mesma página. Um cookie pode conter uma data de expiração (opcional) Default: Cookie é apagado ao se fechar o navegador. http://marx.vanderlinden.com.br/ 5 Cookies http://marx.vanderlinden.com.br/ 6 Cookies http://marx.vanderlinden.com.br/ 7 Cookies http://marx.vanderlinden.com.br/ 8 Usos de Cookies Armazenar itens no "carrinho de compras". Armazenar informações de autenticação. Guardar configurações do usuário. Permitir continuidade no uso de uma aplicação web. http://marx.vanderlinden.com.br/ 9 setcookie Para incluir na resposta HTTP uma solicitação para que o navegador crie um cookie, basta utilizar a função setcookie. Sintaxe (simplificada): setcookie($nome, $valor) Returna true em caso de sucesso, false em caso de erro. http://marx.vanderlinden.com.br/ 10 setcookie Deve ser usado antes de enviar qualquer dado pertencente ao corpo da mensagem! (inclusive espaços em branco). Não há garantias de que o navegador vai aceitar o cookie. http://marx.vanderlinden.com.br/ 11 pagina1.php <?php $b = setcookie('nome', 'Milhouse Van Houten'); ?> <html> <head> <title>Cookies, página 1</title> </head> <body><?php if($b) echo "Cookie enviado com sucesso"; else echo "Erro ao enviar o cookie."; ?></body> http://marx.vanderlinden.com.br/ </html> 12 Requisição HTTP GET /exemplo/pagina1.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 Accept: text/html,application/xhtml+xml,application/x ml;q=0.9,*/*;q=0.8 Accept-Language: pt-br,pt;q=0.8,enus;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 http://marx.vanderlinden.com.br/ 13 Connection: keep-alive Resposta HTTP (Cabeçalho) HTTP/1.x 200 OK Date: Fri, 19 Sep 2008 21:01:36 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch X-Powered-By: PHP/5.2.4-2ubuntu5.3 Set-Cookie: nome=Milhouse+Van+Houten Content-Length: 107 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html http://marx.vanderlinden.com.br/ 14 Saída <html> <head> <title>Cookies, página 1</title> </head> <body>Cookie enviado com sucesso</body> </html> http://marx.vanderlinden.com.br/ 15 $_COOKIE O interpretador PHP automaticamente organiza os cookies enviados pelo usuário ao servidor, através do array $_COOKIE. Formato: $_COOKIE[$nome] // retorna $valor http://marx.vanderlinden.com.br/ 16 pagina2.php <html> <head> <title>Cookies, página 2</title> </head> <body> <?php if(isset($_COOKIE['nome'])) echo "Seu nome é $_COOKIE[nome]."; else echo "Eu não sei o seu nome."; ?> </body></html> http://marx.vanderlinden.com.br/ 17 RequisiçãoHTTP/1.1 HTTP GET /exemplo/pagina2.php Host: localhost User-Agent: Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 Accept: text/html,application/xhtml+xml,application/x ml;q=0.9,*/*;q=0.8 Accept-Language: pt-br,pt;q=0.8,enus;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Cookie: nome=Milhouse+Van+Houten http://marx.vanderlinden.com.br/ 18 Cache-Control: max-age=0 Resposta HTTP (Cabeçalho) HTTP/1.x 200 OK Date: Fri, 19 Sep 2008 21:07:02 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch X-Powered-By: PHP/5.2.4-2ubuntu5.3 Content-Length: 112 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html http://marx.vanderlinden.com.br/ 19 Saída <html> <head> <title>Cookies, página 2</title> </head> <body> Seu nome é Milhouse Van Houten.</body></html> http://marx.vanderlinden.com.br/ 20 Cookies como arrays Para armazenar no cliente um cookie que será lido como um array, basta utilizar a notação de arrays. setcookie("valor[nome]", "Bill"); setcookie("valor[sobrenome]", "Gates"); setcookie("valor[empresa]", "Microsoft"); http://marx.vanderlinden.com.br/ 21 Cookies como arrays Depois, é possível usar o resultado do cookie recebido de volta como um array comum. if (isset($_COOKIE['valor'])) { foreach ( $_COOKIE['valor'] as $indice => $valor ) echo "$indice: $valor <br>\n"; } nome: Bill <br> sobrenome: Gates <br> empresa: Microsoft <br> http://marx.vanderlinden.com.br/ 22 Tempo de expiração Para evitar que o cookie seja excluído quando o navegador for fechado, é necessário especificar um tempo de expiração. Sintaxe completa: setcookie($nome, $valor, [$dataexpira], [$caminho], [$domínio]) Se $dataexpira não for especificado ou igual a 0, será excluído quando se fechar o navegador http://marx.vanderlinden.com.br/ 23 Tempo de expiração Cookie que expira em 1 hora: setcookie( 'login','milhouse', time() + 60*60 Cookie que expira em 1 dia: setcookie( 'login','krusty', time() + 60*60*24 ); ); Cookie que expira do dia 12 de outubro de 2010 setcookie( 'login','flanders', http://marx.vanderlinden.com.br/ mktime(12,0,0, 10,12,2010) ); 24 Diretório de aplicação do Cookie O terceiro parâmetro de setcookie serve para especificar a partir de que diretório, na estrutura de arquivos do servidor web, o cookie deve ser aplicado. Padrão: apenas diretório atual '/' → Domínio inteiro http://marx.vanderlinden.com.br/ 25 Diretório de aplicação do Cookie Cookie válido para todo o domínio setcookie('login','burns', 0, '/' ); www.exemplo.com www.exemplo.com/dir1/springfield Cookie válido para um diretório setcookie('login','barney', time()+60*60, '/moe' ); www.exemplo.com/moe http://marx.vanderlinden.com.br/ www.exemplo.com/moe/tavern 26 Domínio de aplicação do Cookie Por padrão os cookies só são enviados para sites que tenham exatamente o mesmo domínio (incluindo subdomínio) www.exemplo.com ≠ meusite.exemplo.com O quarto parâmetro indica para que partes do domínio da URL o cookie deverá ser enviado. Não é possível especificar um domínio diferente daquele do site que registra o cookie! http://marx.vanderlinden.com.br/ 27 Domínio de aplicação do Cookie Cookie válido para todo o domínio setcookie('login','burns', 0, '/', '.exemplo.com' ); www.exemplo.com www.exemplo.com/dir1/springfield meusite.exemplo.com/shelbyville http://marx.vanderlinden.com.br/ 28 Excluindo um cookie Para excluir um cookie, basta passar um novo cookie com exatamente os mesmos parâmetros já passados, mas valor igual à string vazia. Criando: setcookie('login','burns', 0, '/' ); Excluindo: setcookie('login','', 0, '/' ); http://marx.vanderlinden.com.br/ 29 Características dos Cookies Todas as informações ficam armazenadas no cliente. O servidor não tem um controle preciso de que cookies estão armazenados para cada usuário. Todas os dados precisam ser repassados novamente a cada requisição HTTP feita pelo cliente. Cookies podem ser desativados, excluídos e modificados pelo cliente. http://marx.vanderlinden.com.br/ 30 Sessões PHP fornece um mecanismo de sessões. Quase todos os dados ficam armazenados no servidor. http://marx.vanderlinden.com.br/ 31 Sessões Quando a sessão inicia, o servidor gera um ID, que é uma string alfanumérica aleatória única (PHPSESSID) para identificar o cliente. O cliente armazena a ID como um cookie. Em todas as requisições seguintes, o cliente envia ao servidor apenas o cookie referente ao seu ID. A partir dos IDs, o servidor identifica e diferencia cada cliente. http://marx.vanderlinden.com.br/ 32 session_start() Para iniciar (ou continuar) uma sessão, basta usar a função session_start Sintaxe: session_start() Deve ser usado antes de qualquer saída do corpo da mensagem Sempre returna true http://marx.vanderlinden.com.br/ 33 $_SESSION Para ler e configurar variáveis de sessões, utiliza-se o array $_SESSION. Não há análogo em sessões à função setcookie. http://marx.vanderlinden.com.br/ 34 exemplo.php <?php session_start(); ?> <html> <head> <title>Sessões</title> </head> <body> <?php if(!isset($_SESSION['visitas'])) $_SESSION['visitas'] = 0; ?> Esta é a sua visita número <?php echo $_SESSION['visitas']++ ?>. </body> </html> http://marx.vanderlinden.com.br/ 35 1a Requisição HTTP GET /delme/exemplo.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 Accept: text/html,application/xhtml+xml,application/x ml;q=0.9,*/*;q=0.8 Accept-Language: pt-br,pt;q=0.8,enus;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 http://marx.vanderlinden.com.br/ 36 Connection: keep-alive 1a Resposta HTTP (Cabeçalho) HTTP/1.x 200 OK Date: Fri, 19 Sep 2008 22:17:44 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch X-Powered-By: PHP/5.2.4-2ubuntu5.3 Set-Cookie: PHPSESSID=c7abd60716ef5c9df79f3788767aaec5; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, mustrevalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 110 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive http://marx.vanderlinden.com.br/ 37 Content-Type: text/html 2a Requisição HTTP GET /delme/exemplo.php HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (X11; U; Linux i686; ptBR; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1 Accept: text/html,application/xhtml+xml,application/xml; q=0.9,*/*;q=0.8 Accept-Language: pt-br,pt;q=0.8,enus;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Cookie: PHPSESSID=c7abd60716ef5c9df79f3788767aaec5 http://marx.vanderlinden.com.br/ 38 Cache-Control: max-age=0 2a Resposta HTTP HTTP/1.x 200 OK Date: Fri, 19 Sep 2008 22:19:46 GMT Server: Apache/2.2.8 (Ubuntu) PHP/5.2.4-2ubuntu5.3 with Suhosin-Patch X-Powered-By: PHP/5.2.4-2ubuntu5.3 Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, mustrevalidate, post-check=0, pre-check=0 Pragma: no-cache Content-Length: 110 Keep-Alive: timeout=15, max=100 Connection: Keep-Alive Content-Type: text/html http://marx.vanderlinden.com.br/ 39 session_set_cookie_params É possível configurar os parâmetros do cookie usado para armazenar o ID da sessão. Sintaxe: session_set_cookie_params( $dataexpira, [$caminho], [$domínio]) A sintaxe dos parâmetros é similar às da função setcookie. http://marx.vanderlinden.com.br/ 40 session_name A função session_name muda o nome do cookie que identifica o código da sessão. Deve ser chamado antes de session_start. Sintaxe: session_name($novonome) Return true em caso de sucesso; false em erro. http://marx.vanderlinden.com.br/ 41 session_id Sintaxe: session_id() Retorna o ID da seção atual, ou '', caso não haja sessão aberta. http://marx.vanderlinden.com.br/ 42 session_regenerate_id Sintaxe: session_regenerate_id() Gera um novo ID para a sessão atual. Envia uma novo requisição de Cookie ao cliente, sem quebrar a sessão. Precisa ser chamado antes de qualquer saída no corpo da resposta HTTP. Return true em caso de sucesso; false em erro. http://marx.vanderlinden.com.br/ 43 Configurando sessões Por padrão: Uma sessão continua ativa caso seja acessada pelo usuário ao menos 1 vez a cada 24 minutos. Sessões não servem para armazenar dados permanentes! Cada vez que session_start é chamada, há uma probabilidade de 1% de que o PHP vai varrer todas as sessões ativas, e excluir as que expiraram. http://marx.vanderlinden.com.br/ 44 ini_set A função ini_set serve para mudar temporariamente alguma configuração do PHP. Sintaxe: ini_set($variável, $novovalor) Return true em caso de sucesso; false em erro. http://marx.vanderlinden.com.br/ 45 session.gc_maxlifetime Especifica o tempo (em segundos) máximo que uma sessão deve durar, esperando pelo usuário. Padrão: 1440 (24 minutos). Deve ser modificada antes de session_start() ini_set('session.gc_maxlifetime', 600); session_start( ); http://marx.vanderlinden.com.br/ 46 session.gc_probability Especifica a probabilidade (em %) de que o PHP vai fazer a verificação e limpeza das sessões expiradas, a cada chamada de session_start. Padrão: 1 Também deve ser modificada antes de session_start ini_set('session.gc_probability', 100); session_start( ); http://marx.vanderlinden.com.br/ 47 Segurança Problema de segurança: A ID da sessão pode ser interceptada por alguém que esteja monitorando a rede. Se outra pessoa usar a mesma ID para fazer requisições ao servidor, pode fazer se passar por outro usuário. http://marx.vanderlinden.com.br/ 48 Funções de Hash http://marx.vanderlinden.com.br/ 49 Funções de Hash PHP implementa as funções de hash mais comuns: md5($string) sha1($string) hash($algoritmo, $string) (Função genérica que implementa vários algoritmos) http://marx.vanderlinden.com.br/ 50 md5 echo md5("The book is on the table"), " <br>\n"; echo md5("The book is on the table."), " <br>\n"; 0c29bf0f928decfbf91070fa4affb0c4 <br> 1f683fe1cd7977cdd056ddc25d6bd8f8 <br> http://marx.vanderlinden.com.br/ 51 $_SERVER O array $_SERVER contém informações fornecidas pelo servidor web, como cabeçalhos, caminhos de arquivo e configurações. Os índices do array são fixos e seus valores não podem ser modificados. http://marx.vanderlinden.com.br/ 52 $_SERVER Exemplos: 'PHP_SELF' → Nome do script atual 'SERVER_ADDR' → Endereço IP do servidor 'SERVER_NAME' → Nome do servidor 'HTTP_USER_AGENT' → Configurações do cliente 'REMOTE_ADDR' → Endereço IP do cliente http://marx.vanderlinden.com.br/ 53 $_SERVER $keys = array( 'PHP_SELF', 'SERVER_ADDR', 'SERVER_NAME', 'HTTP_USER_AGENT', 'REMOTE_ADDR', ); foreach($keys as $k) echo "$k: $_SERVER[$k]<br>\n"; PHP_SELF: /exemplo/exemplo.php<br> SERVER_ADDR: 127.0.0.1<br> SERVER_NAME: localhost<br> HTTP_USER_AGENT: Mozilla/5.0 (X11; U; Linux i686; pt-BR; rv:1.9.0.1) Gecko/2008072820 Firefox/3.0.1<br>http://marx.vanderlinden.com.br/ 54 REMOTE_ADDR: 127.0.0.1<br> Sessão Segura (1/2) <?php session_start(); $md5 = md5( $_SERVER['HTTP_USER_AGENT'] . $_SERVER['REMOTE_ADDR'] ); if (!isset($_SESSION['md5'])) { session_regenerate_id(); $_SESSION['md5'] = $md5; $msg = "Bem-vindo!<br>\n"; } if ($_SESSION['md5'] != $md5) { $_SESSION = array(); $_SESSION['md5'] = $md5; $msg = "Erro! Por favor, faça o login novamente.<br>\n"; } else http://marx.vanderlinden.com.br/ $msg .= "Continuando..."; ?> 55 Sessão Segura <html> <head><title>Sessões</title></head> <body> <?php echo $msg ?> </body> </html> http://marx.vanderlinden.com.br/ 56 Saída Primeira execução: OK!<br> Continuando sessão Execuções seguintes: Continuando sessão Tentativa de ataque: Erro! Por favor, faça o login novamente. http://marx.vanderlinden.com.br/ 57