abril 2008
D S T Q Q S S
    mai »
 12345
6789101112
13141516171819
20212223242526
27282930  

Interface de sessões do PHP em MySQL

Conforme visto no artigo Funcionamento de sessões no PHP, o sistema de arquivamento em disco é inseguro. Este artigo implementa uma classe que armazena os dados em banco de dados MySQL. Isto além de possibilitar uma maior segurança dos dados de sessão, permite que uma aplicação seja portada para um sistema de balanceamento de cargas muito mais facilmente, pois independentemente de qual servidor a requisição for processada, terá acesso as variáveis de sessão de forma transparente.

Esta classe nasceu da idéia postada em um comentário nas páginas do manual do PHP, mais especificamente na página do comando session_set_save_handler(). O exemplo original foi criado por maria (arroba) junkies (ponto) jp, melhorado por klose (arroba) openriverbed (ponto) de e algumas mudanças feitas por mim.

Este comando permite que sejam especificadas funções para o processamento de sessões do PHP, informadas como parâmetros, sendo elas:

  1. open: Executada quando é iniciada a sessão através da chamada da função session_start() ou automaticamente;
  2. close: Executada ao término da execução do script, normalmente após a gravação das informações da sessão através da função write() (veja abaixo), ou da destruição da sessão através da função destroy() (veja abaixo);
  3. read: Executada sempre que a sessão for inicializada para recuperar uma string com as informações da sessão;
  4. write: Executada sempre ao término da execução do script, antes da chamada da função close() (veja acima), para arquivar as mudanças efetuadas nas variáveis de sessão. Ocorre sempre que a execução do script termina ou através da chamada da função session_write_close();
  5. destroy: Executada quando uma sessão é destruída através do comando session_destroy(), eliminando os dados da sessão e encerrando o sistema de sessões através da chamada da função close() (veja acima);
  6. gc: É executada sempre que o PHP deseja limpar as variáveis com tempo de vida expirado. É chamado de “garbage cleanup”, e é executada automaticamente pelo servidor.

Seguindo as especificações desta função, podemos implementar a classe conforme segue:

<?php
/**
 * PHP session handling with MySQL-DB
 *
 * Created on 12.03.2008
 * @license    http://www.opensource.org/licenses/cpl.php Common Public License 1.0
 */

class MySQL_Session
{
  /**
   * A database connection resource and configuration.
   * @var resource
   */
  private static $_sess_id;
  private static $_sess_host;
  private static $_sess_user;
  private static $_sess_pass;
  private static $_sess_db;
  private static $_sess_table;

  /**
   * Open the session
   * @return bool
   */
  public static function open ()
  {
    if ( self::$_sess_id = @mysql_connect ( self::$_sess_host, self::$_sess_user, self::$_sess_pass))
    {
      return @mysql_select_db ( self::$_sess_db, self::$_sess_id);
    }

    return false;
  }

  /**
   * Close the session
   * @return bool
   */
  public static function close ()
  {
    return @mysql_close ( self::$_sess_id);
  }

  /**
   * Read the session
   * @param string session id
   * @return string string of the session
   */
  public static function read ( $id)
  {
    if ($result = @mysql_query ( "SELECT `data` FROM `" . mysql_real_escape_string ( self::$_sess_table, self::$_sess_id) . "` WHERE `handler` = '" . mysql_real_escape_string ( $id, self::$_sess_id) . "'", self::$_sess_id))
    {
      if ( mysql_num_rows ( $result))
      {
        $record = mysql_fetch_assoc ( $result);
        return $record["data"];
      }
    }

    return "";
  }

  /**
   * Write the session
   * @param string session id
   * @param string data of the session
   */
  public static function write ( $id, $data)
  {
    return @mysql_query ( "REPLACE INTO `" . mysql_real_escape_string ( self::$_sess_table, self::$_sess_id) . "` VALUES ('" . mysql_real_escape_string ( $id, self::$_sess_id) . "', " . time () . ", '" . mysql_real_escape_string ( $data, self::$_sess_id) . "')", self::$_sess_id);
  }

  /**
   * Destroy the session
   * @param string session id
   * @return bool
   */
  public static function destroy ( $id)
  {
    return @mysql_query ( "DELETE FROM `" . mysql_real_escape_string ( self::$_sess_table, self::$_sess_id) . "` WHERE `handler` = '" . mysql_real_escape_string ( $id, self::$_sess_id) . "'", self::$_sess_id);
  }

  /**
   * Garbage Collector
   * @param int life time (sec.)
   * @return bool
   * @see session.gc_divisor      100
   * @see session.gc_maxlifetime 1440
   * @see session.gc_probability    1
   * @usage execution rate 1/100
   *        (session.gc_probability/session.gc_divisor)
   */
  public static function gc ( $max)
  {
    return @mysql_query ( "DELETE FROM `" . mysql_real_escape_string ( self::$_sess_table, self::$_sess_id) . "` WHERE `expires` < " . (int) ( time () - $max), self::$_sess_id);
  }

  /**
   * Class constructor function
   * @param string MySQL server hostname
   * @param string username
   * @param string password
   * @param string database name
   * @param string table name
   */
  function __construct ( $hostname = "localhost", $username = "root", $password = "", $database = "", $table = "sessions")
  {
    // Change the database configurations:
    self::$_sess_host = $hostname;
    self::$_sess_user = $username;
    self::$_sess_pass = $password;
    self::$_sess_db = $database;
    self::$_sess_table = $table;

    // Change the session handler type:
    ini_set ( "session.save_handler", "user");

    // Change the session handler functions:
    session_set_save_handler ( array ( &$this, "open"), array ( &$this, "close"), array ( &$this, "read"), array ( &$this, "write"), array ( &$this, "destroy"), array ( &$this, "gc"));

    // Be nice, return true.
    return true;
  }
}
?>

Não devemos esquecer também a estrutura da tabela MySQL necessária para o funcionamento:

CREATE TABLE IF NOT EXISTS `sessions` (
  `handler`   char(26) NOT NULL,
  `expires`   int unsigned NOT NULL default '0',
  `data`      blob,
  PRIMARY KEY (`handler`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

A ativação da classe é extremamente simples, basta se incluir o arquivo contendo a classe e instanciar um novo objeto MySQL_Session, passando como parâmetros:

  1. hostname: Endereço do servidor MySQL;
  2. username: Usuário para autenticação no banco de dados;
  3. password: Senha para autenticação;
  4. database: Nome da base de dados a ser selecionada;
  5. table: Nome da tabela a ser utilizada. Normalmente (se utilizado a estrutura SQL acima descrita sem alterações) é a tabela “sessions”.

Podemos testar a classe com o seguinte exemplo:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en_US" lang="en_US">
<head>
  <title>MySQL Session Handling Class - Example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>

<?php
// Include class file:
require_once ( "mysql-session.class.php");

// Instance new class:
$session = new MySQL_Session ( "hostname", "username", "password", "database", "table");

if ( session_id () == "")
{
  session_start ();
}

if ( isset ( $_SESSION["counter"]))
{
  $_SESSION["counter"]++;
} else {
  $_SESSION["counter"] = 1;
}
echo "Session ID: " . session_id () . "<br />\n";
echo "Counter: " . $_SESSION["counter"] . "<br />\n";
?>

</body>
</html>

Este exemplo pode ser facilmente portado para outros bancos de dados, assim como implementado funções de criptografia, etc.

Caso você deseje, pode fazer o download do conteúdo deste artigo aqui.

Envie uma resposta

 

 

 

Você pode utilizar estas tags HTML

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>