Foros del Web » Programando para Internet » PHP »

[APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Estas en el tema de [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL en el foro de PHP en Foros del Web. Hola gente, como le va... Hace rato que no entraba a Foros del Web, y decidi hacer un posteo con un aporte por primera vez, ...
  #1 (permalink)  
Antiguo 15/02/2010, 06:45
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
[APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Hola gente, como le va... Hace rato que no entraba a Foros del Web, y decidi hacer un posteo con un aporte por primera vez, además me gustaría que me ayuden a mejorar y ver si lo que hice es seguro o no, etc... He hecho un sistema de sesiones y autentificacion de usuario para un portal en el que estoy trabajando, y me gustaría que dejen su comentario para ver si lo que hice realmente sirve y como dije, si es seguro... ¡Espero que les sirva!

Nota: Está documentado en Inglés ya que más que nada lo hice para guiarme yo mismo, el inglés siempre me pareció más simple y corto de escribir comparado al español :p

Antes de empezar, les pido que lean todo el posteo antes de probala en su servidor XAMPP, o el que tengan...

Tablas MySQL:
Código MySQL:
Ver original
  1. -- Tabla para las sesiones
  2. CREATE TABLE IF NOT EXISTS `_sessions` (
  3.   `session_id` varchar(64) NOT NULL DEFAULT '',
  4.   `session_data` longtext NOT NULL,
  5.   `session_touched` bigint(20) unsigned NOT NULL,
  6.   UNIQUE KEY `session_id` (`session_id`)
  7. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  8.  
  9. -- Tabla para usuarios
  10. CREATE TABLE IF NOT EXISTS `_users` (
  11.   `account_name` varchar(16) NOT NULL DEFAULT '',
  12.   `account_pass` varchar(32) NOT NULL DEFAULT '',
  13.   `account_email` varchar(96) NOT NULL DEFAULT '',
  14.   `account_type` tinyint(1) unsigned NOT NULL DEFAULT '1',
  15.   `account_status` tinyint(1) NOT NULL DEFAULT '0',
  16.   `account_validation_key` varchar(32) NOT NULL DEFAULT '',
  17.   `account_registered_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  18.   PRIMARY KEY (`id`),
  19.   UNIQUE KEY `account_name` (`account_name`),
  20.   KEY `account_email` (`account_email`)
  21. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
  22.  
  23. -- Insertamos un usuario de prueba...
  24. -- Usuario: demo
  25. -- Clave: demo
  26. INSERT INTO `_users` (`id`, `account_name`, `account_pass`, `account_email`, `account_type`, `account_status`, `account_validation_key`, `account_registered_date`) VALUES
  27. (1, 'demo', '$1$CZ..jd4.$/zsff1Id4S9h3gylYr/6R/', '[email protected]', 0, 1, '', '2010-01-01 16:00:00');

Nora: la clave fue encryptada con crypt() utilizando como salt: $1$CZ..jd4.$XUyjB06VQ7K.E3yKw7hXh/ En una de las clases que verán a continuación, van a notar que ya les puse el salt en una variable...

Bueno, a continuacion la clase de Sessiones y Autentificación:

Última edición por Nisrokh; 16/02/2010 a las 17:27
  #2 (permalink)  
Antiguo 15/02/2010, 06:48
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

SimpleSession.php
Código PHP:
Ver original
  1. <?php
  2.  
  3. /**
  4.  * @author estilodg.com <[email protected]>
  5.  * @copyright 2010
  6.  */
  7.  
  8. // Error code constants
  9. define('LOGIN_ACCESS_NO_ATTEMPT', -1);
  10. define('LOGIN_ACCESS_GRANTED', 0);
  11. define('LOGIN_ACCESS_ERROR_ATTEMPT_FAILED', 1);
  12. define('LOGIN_ACCESS_ERROR_NONEXISTENT_ACCOUNT', 2);
  13. define('LOGIN_ACCESS_ERROR_UNAUTHORIZED_ACCOUNT', 3);
  14. define('LOGIN_ACCESS_ERROR_UNVALIDATED_ACCOUNT', 4);
  15. define('LOGIN_ACCESS_ERROR_BLOCKED_ACCOUNT', 5);
  16. define('LOGIN_ACCESS_ERROR_MISSING_USERNAME', 6);
  17. define('LOGIN_ACCESS_ERROR_MISSING_PASSWORD', 7);
  18. define('LOGIN_ACCESS_ERROR_UNKNOWN_ERROR', 8);
  19.  
  20. // Session data encryption keys
  21. define('SESSION_DATA_ENCRYPTION_KEY_1', '944672318');
  22. define('SESSION_DATA_ENCRYPTION_KEY_2', '410344323');
  23.  
  24. /**
  25.  * Simple Login Management
  26.  *
  27.  * @package SimpleSession
  28.  * @subpackage SimpleLogin
  29.  * @author Diego P. M. Baltar <[email protected]>
  30.  * @copyright 2010
  31.  * @version 0.1
  32.  */
  33. abstract class SimpleLogin {
  34.    
  35.     /**
  36.      * Authentification salt
  37.      *
  38.      * @access private
  39.      * @var string
  40.      */
  41.     private $auth_salt = '$1$CZ..jd4.$XUyjB06VQ7K.E3yKw7hXh/';
  42.    
  43.     /**
  44.      * Login status
  45.      *
  46.      * @access public
  47.      * @var integer
  48.      */
  49.     public $status = LOGIN_ACCESS_NO_ATTEMPT;
  50.    
  51.     /**
  52.      * Login
  53.      *
  54.      * @access public
  55.      * @return void
  56.      */
  57.     public function login($username = '', $password = '') {
  58.        
  59.         if ($this->logged_in())
  60.             return;
  61.        
  62.         $username = trim($username);
  63.         $password = trim($password);
  64.        
  65.         if (!$username or empty($username)) {
  66.             $this->status = LOGIN_ACCESS_ERROR_MISSING_USERNAME;
  67.             return;
  68.         } else if (!$password or empty($password)) {
  69.             $this->status = LOGIN_ACCESS_ERROR_MISSING_PASSWORD;
  70.             return;
  71.         }
  72.        
  73.         // Encrypt password
  74.         $password = crypt($password, $this->auth_salt);
  75.        
  76.         // Build and execute query
  77.         $query_sentence = "
  78.             SELECT
  79.                 id, account_name, account_pass, account_type, account_status
  80.             FROM
  81.                 {$this->mysql->tables['users']}
  82.             WHERE
  83.                 account_name = '%s'
  84.         ";
  85.         $this->mysql->query(sprintf($query_sentence, $this->mysql->escape($username)));
  86.        
  87.         // If user exists...
  88.         if ($this->mysql->affected_rows > 0) {
  89.             $row = $this->mysql->query_result[0];
  90.             $this->mysql->clean();
  91.            
  92.             // 0 => Administrator, 1 => Moderator, 2 => User
  93.             // Allow administrators and moderators only
  94.             if ((int)$row->account_type > 1) {
  95.                 $this->status = LOGIN_ACCESS_ERROR_UNAUTHORIZED_ACCOUNT;
  96.                 return;
  97.             }
  98.            
  99.             // Check whether the user account is unvalidated
  100.             if ((int)$row->account_status == 0) {
  101.                 $this->status = LOGIN_ACCESS_ERROR_UNVALIDATED_ACCOUNT;
  102.                 return;
  103.             }
  104.            
  105.             // Check user password
  106.             if (substr($password, 0, 32) == $row->account_pass) {
  107.                
  108.                 // Now we check if the user account has been blocked
  109.                 if ((int)$row->account_status == -1) {
  110.                     $this->status = LOGIN_ACCESS_ERROR_BLOCKED_ACCOUNT;
  111.                     return;
  112.                 } else if ((int)$row->account_status == 1) {
  113.                     $this->status = LOGIN_ACCESS_GRANTED;
  114.                     $this->data->account_id = (int)$row->id;
  115.                     $this->data->account_name = $row->account_name;
  116.                     $this->data->account_type = (int)$row->account_type;
  117.                     $this->data->access = true;
  118.                     $this->regenerate_id(true);
  119.                     return;
  120.                 }
  121.             } else {
  122.                 $this->status = LOGIN_ACCESS_ERROR_ATTEMPT_FAILED;
  123.                 return;
  124.             }
  125.         } else {
  126.             $this->status = LOGIN_ACCESS_ERROR_NONEXISTENT_ACCOUNT;
  127.             return;
  128.         }
  129.     }
  130.    
  131.     public function logout() {
  132.         if ($this->logged_in())
  133.             $this->destroy();
  134.     }
  135.    
  136.     /**
  137.      * Check if user is logged in
  138.      *
  139.      * @access public
  140.      * @return boolean
  141.      */
  142.     public function logged_in() {
  143.         if (!isset($this->data->account_name))
  144.             unset($this->data->access);
  145.         else {
  146.             $username = trim($this->data->account_name);
  147.             if (!$username or empty($username)) {
  148.                 unset($this->data->account_id);
  149.                 unset($this->data->account_name);
  150.                 unset($this->data->account_type);
  151.                 unset($this->data->access);
  152.             }
  153.         } return $this->data->access;
  154.     }
  155. }
  156.  
  157. // Continua...
  158.  
  159. ?>
  #3 (permalink)  
Antiguo 15/02/2010, 06:49
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Continuacion de SimpleSession.php
Código PHP:
Ver original
  1. <?php
  2.  
  3. /**
  4.  * Simple Session
  5.  *
  6.  * @package SimpleSession
  7.  * @author Diego P. M. Baltar <[email protected]>
  8.  * @copyright 2010
  9.  * @version 0.2
  10.  */
  11. class SimpleSession extends SimpleLogin {
  12.    
  13.     /**
  14.      * Session garbage collector divisor
  15.      *
  16.      * @access private
  17.      * @var integer
  18.      */
  19.     private $gc_divisor = 100;
  20.    
  21.     /**
  22.      * Session garbage collector lifetime
  23.      *
  24.      * @access private
  25.      * @var integer
  26.      */
  27.     private $gc_maxlifetime = 3600;
  28.    
  29.     /**
  30.      * Session garbage collector probability
  31.      *
  32.      * @access private
  33.      * @var integer
  34.      */
  35.     private $gc_probability = 10;
  36.    
  37.     /**
  38.      * Encryption available
  39.      *
  40.      * @access private
  41.      * @var boolean
  42.      */
  43.     private $encryption;
  44.    
  45.     /**
  46.      * Encryption key
  47.      *
  48.      * @access private
  49.      * @var string
  50.      */
  51.     private $encryption_key;
  52.    
  53.     /**
  54.      * SimpleMySQL object
  55.      *
  56.      * @access protected
  57.      * @var object
  58.      */
  59.     protected $mysql = null;
  60.    
  61.     /**
  62.      * Session name
  63.      *
  64.      * @access protected
  65.      * @var string
  66.      */
  67.     protected $name = '__SESSID';
  68.    
  69.     /**
  70.      * Session lifetime
  71.      *
  72.      * @access protected
  73.      * @var integer
  74.      */
  75.     protected $lifetime = 1800;
  76.    
  77.     /**
  78.      * Session cookie path
  79.      *
  80.      * @access protected
  81.      * @var string
  82.      */
  83.     protected $cookie_path = '/';
  84.    
  85.     /**
  86.      * SimpleSessionVars object
  87.      *
  88.      * @access private
  89.      * @var object
  90.      */
  91.     public $data = null;
  92.    
  93.     /**
  94.      * Session ID
  95.      *
  96.      * @access public
  97.      * @var string
  98.      */
  99.     public $id;
  100.    
  101.     /**
  102.      * SimpleSession object constructor
  103.      *
  104.      * @access public
  105.      * @param object SimpleMySQL instance
  106.      * @return void
  107.      *
  108.      * @see SimpleSessionVars
  109.      */
  110.     public function __construct(SimpleMySQL $MySQL) {
  111.        
  112.         if (!extension_loaded('mcrypt'))
  113.             $this->encryption = false;
  114.         else if (!function_exists('mcrypt_module_open'))
  115.             $this->encryption = false;
  116.         else {
  117.             $this->encryption = true;
  118.            
  119.             $key_1 = md5(SESSION_DATA_ENCRYPTION_KEY_1);
  120.             $key_2 = md5(SESSION_DATA_ENCRYPTION_KEY_2);
  121.            
  122.             $this->encryption_key = $key_1.$key_2;
  123.         }
  124.        
  125.         // Save MySQL object and clean its previous results if any
  126.         $this->mysql = $MySQL;
  127.         $this->mysql->clean();
  128.        
  129.         // Set session garbage collector properties
  130.         ini_set('session.gc_divisor', $this->gc_divisor);
  131.         ini_set('session.gc_probability', $this->gc_probability);
  132.         ini_set('session.gc_maxlifetime', $this->gc_maxlifetime);
  133.        
  134.         // Set session id hashing options
  135.         ini_set('session.hash_function', 1);
  136.         ini_set('session.hash_bits_per_character', 5);
  137.        
  138.         // Set handler functions
  139.             array(&$this, '__open'),
  140.             array(&$this, '__close'),
  141.             array(&$this, '__read'),
  142.             array(&$this, '__write'),
  143.             array(&$this, '__destroy'),
  144.             array(&$this, '__gc')
  145.         );
  146.        
  147.         // Call session_write_close() from the object destructor
  148.         @register_shutdown_function(array(&$this, '__destruct'));
  149.     }
  150.    
  151.     /**
  152.      * SimpleSession object destructor
  153.      *
  154.      * @access public
  155.      * @return boolean
  156.      */
  157.     public function __destruct() {
  158.        
  159.         // Call session_write_close() then return true
  160.         session_write_close();
  161.         return true;
  162.     }
  163.    
  164.     public function __open($save_path, $session_name) {
  165.         return true;
  166.     }
  167.    
  168.     public function __close() {
  169.         return true;
  170.     }
  171.    
  172.     public function __read($session_id) {
  173.        
  174.         $session_id = $this->mysql->escape($session_id);
  175.         $session_data = '';
  176.        
  177.         // Build query to retrieve current session data
  178.         $query_sentence = "
  179.             SELECT
  180.                 session_data
  181.             FROM
  182.                 {$this->mysql->tables['sessions']}
  183.             WHERE
  184.                 session_id = '%s'
  185.         ";
  186.         $this->mysql->query(sprintf($query_sentence, $session_id));
  187.        
  188.         // Check if session data is available
  189.         if ($this->mysql->affected_rows > 0) {
  190.             $session_data = $this->mysql->query_result[0]->session_data;
  191.             $session_data = $this->decrypt($session_data);
  192.             $this->mysql->clean();
  193.         }
  194.        
  195.         // If no session data was found, return an empty string
  196.         return (string)$session_data;
  197.     }
  198.    
  199.     public function __write($session_id, $session_data) {
  200.        
  201.         $session_id = $this->mysql->escape($session_id);
  202.         $session_data = $this->encrypt($session_data);
  203.        
  204.         // Build query to write/rewrite current session data into database
  205.         $query_sentence = "
  206.             REPLACE INTO
  207.                 {$this->mysql->tables['sessions']}
  208.                 (session_id, session_data, session_touched)
  209.             VALUES
  210.                 ('%s', '%s', UNIX_TIMESTAMP())
  211.         ";
  212.         $this->mysql->query(sprintf($query_sentence, $session_id, $session_data));
  213.         $this->mysql->clean();
  214.        
  215.         return true;
  216.     }
  217.    
  218.     public function __destroy($session_id) {
  219.        
  220.         $session_id = $this->mysql->escape($session_id);
  221.        
  222.         // Build query to delete the current session from database
  223.         $query_sentence = "
  224.             DELETE FROM
  225.                 {$this->mysql->tables['sessions']}
  226.             WHERE
  227.                 session_id = '%s'
  228.         ";
  229.         $this->mysql->query(sprintf($query_sentence, $session_id));
  230.        
  231.         return true;
  232.     }
  233.    
  234.     public function __gc($session_max_lifetime) {
  235.         $query_sentence = "
  236.             DELETE FROM
  237.                 {$this->mysql->tables['sessions']}
  238.             WHERE
  239.                 session_touched + {$session_max_lifetime} < UNIX_TIMESTAMP()
  240.         ";
  241.         $this->mysql->query($query_sentence);
  242.         return true;
  243.     }
  244.    
  245.     /**
  246.      * Session start
  247.      *
  248.      * @access public
  249.      * @return unknown
  250.      */
  251.     public function start() {
  252.        
  253.         session_name($this->name);
  254.         session_set_cookie_params($this->lifetime, $this->cookie_path);
  255.         session_cache_limiter('nocache');
  256.        
  257.         header("Pragma: no-cache");
  258.         header("Expires: Mon, 28 Aug 1989 02:22:00 GMT");
  259.         header("Last-Modified: " .gmdate("D, d M Y H:i:s"). " GMT");
  260.         header("Cache-Control: no-store, no-cache, must-revalidate");
  261.         header("Cache-Control: post-check=0, pre-check=0", false);
  262.        
  263.         session_start();
  264.        
  265.         $this->id = session_id();
  266.        
  267.         // Create SimpleSessionData object to manipulate session data
  268.         // I.e.: $SimpleSession->data->foo = 'bar' => ($_SESSION['foo'] = 'bar')
  269.         $this->data = new SimpleSessionData;
  270.     }
  271.    
  272.     /**
  273.      * Session destroy
  274.      *
  275.      * @access public
  276.      * @return boolean
  277.      */
  278.     public function destroy() {
  279.        
  280.         // Unset all session variables
  281.         $this->id = null;
  282.         session_unset();
  283.        
  284.         // Delete session cookie, if found
  285.         if (isset($_COOKIE[$this->name]))
  286.             @setcookie($this->name, '', time() - $this->lifetime, $this->cookie_path);
  287.        
  288.         // Destroy the current session
  289.         return session_destroy();
  290.     }
  291.    
  292.     /**
  293.      * Session regenerate ID
  294.      *
  295.      * @access public
  296.      * @param boolean $delete_old_session
  297.      * @return boolean
  298.      */
  299.     public function regenerate_id($delete_old_session = false) {
  300.         if (session_regenerate_id($delete_old_session))
  301.             $this->id = session_id();
  302.         else return false;
  303.     }
  304.    
  305.     /**
  306.      * Session data encrypter
  307.      *
  308.      * @access public
  309.      * @param string $session_data
  310.      * @return string
  311.      */
  312.     private function encrypt($session_data = '') {
  313.        
  314.         if (empty($session_data))
  315.             return $session_data;
  316.        
  317.         if (!$this->encryption)
  318.             return base64_encode($session_data);
  319.        
  320.         $td = mcrypt_module_open('rijndael-256', '', 'ecb', '');
  321.         $ks = mcrypt_enc_get_key_size($td);
  322.        
  323.         $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  324.         $key = substr($this->encryption_key, 0, $ks);
  325.        
  326.         mcrypt_generic_init($td, $key, $iv);
  327.        
  328.         // Encrypt data
  329.         $encrypted_data = mcrypt_generic($td, $session_data);
  330.        
  331.         mcrypt_generic_deinit($td);
  332.         mcrypt_module_close($td);
  333.        
  334.         return base64_encode($encrypted_data);
  335.     }
  336.    
  337.     /**
  338.      * Session data decrypter
  339.      *
  340.      * @access public
  341.      * @param string $session_data
  342.      * @return string
  343.      */
  344.     private function decrypt($session_data = '') {
  345.        
  346.         if (empty($session_data))
  347.             return $session_data;
  348.        
  349.         $session_data = base64_decode($session_data);
  350.        
  351.         if (!$this->encryption)
  352.             return $session_data;
  353.        
  354.         $td = mcrypt_module_open('rijndael-256', '', 'ecb', '');
  355.         $ks = mcrypt_enc_get_key_size($td);
  356.        
  357.         $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
  358.         $key = substr($this->encryption_key, 0, $ks);
  359.        
  360.         mcrypt_generic_init($td, $key, $iv);
  361.        
  362.         // Decrypt data
  363.         $decrypted_data = mdecrypt_generic($td, $session_data);
  364.        
  365.         mcrypt_generic_deinit($td);
  366.         mcrypt_module_close($td);
  367.        
  368.         $decrypted_data = rtrim($decrypted_data);
  369.        
  370.         return (string)$decrypted_data;
  371.     }
  372. }
  373.  
  374. /**
  375.  * Simple Session Data
  376.  *
  377.  * @package SimpleSession
  378.  * @subpackage SimpleSessionData
  379.  * @author Diego P. M. Baltar <[email protected]>
  380.  * @copyright 2010
  381.  * @version 0.1
  382.  */
  383. class SimpleSessionData {
  384.    
  385.     public function __set($var, $value) {
  386.         $_SESSION[$var] = $value;
  387.     }
  388.    
  389.     public function __get($var) {
  390.         if (!isset($_SESSION[$var]))
  391.             return null;
  392.         else return $_SESSION[$var];
  393.     }
  394.    
  395.     public function __isset($var) {
  396.         return isset($_SESSION[$var]);
  397.     }
  398.    
  399.     public function __unset($var) {
  400.         unset($_SESSION[$var]);
  401.     }
  402. }
  403.  
  404. ?>
  #4 (permalink)  
Antiguo 15/02/2010, 06:49
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Nota: Para poder utilizar las clases de alli arriba, deben utilizar una para MySQL que yo mismo he hecho... Si despues quiren pueden adaptarlo a la suya... Pero el codigo fue hecho con la utilizacion de la siguiente clase para MySQL... Bien "Simple".

SimpleMySQL.php
Código PHP:
Ver original
  1. <?php
  2.  
  3. /**
  4.  * @author estilodg.com <[email protected]>
  5.  * @copyright 2009
  6.  */
  7.  
  8. /**
  9.  * MySQL Management Class
  10.  *
  11.  * @author Diego P. M. Baltar <www.estilodg.com>
  12.  * @package SimpleMySQL
  13.  */
  14. class SimpleMySQL
  15. {
  16.     /**
  17.      * Link identifier
  18.      *
  19.      * @access public
  20.      * @var resource
  21.      */
  22.     public $link = null;
  23.    
  24.     /**
  25.      * Selected database
  26.      *
  27.      * @access public
  28.      * @var string
  29.      */
  30.     public $database = null;
  31.    
  32.     /**
  33.      * Query result resource
  34.      *
  35.      * @access public
  36.      * @var resource
  37.      */
  38.     public $result = null;
  39.    
  40.     /**
  41.      * Query result data
  42.      *
  43.      * @access public
  44.      * @var array
  45.      */
  46.     public $query_result = array();
  47.    
  48.     /**
  49.      * Query error
  50.      *
  51.      * @access public
  52.      * @var boolean
  53.      */
  54.     public $query_error = false;
  55.    
  56.     /**
  57.      * Selected rows
  58.      *
  59.      * @access public
  60.      * @var integer
  61.      */
  62.     public $rows = null;
  63.    
  64.     /**
  65.      * Number of affected rows
  66.      *
  67.      * @access public
  68.      * @var integer
  69.      */
  70.     public $affected_rows = null;
  71.    
  72.     /**
  73.      * Last inserted id
  74.      *
  75.      * @access public
  76.      * @var integer
  77.      */
  78.     public $last_id = null;
  79.    
  80.     /**
  81.      * MySQL connection state
  82.      *
  83.      * @access public
  84.      * @var boolean
  85.      */
  86.     public $ready = false;
  87.    
  88.     /**
  89.      * Database tables
  90.      */
  91.     public $tables = array();
  92.    
  93.     public function __construct($hostname = 'localhost', $username = 'root', $password = '')
  94.     {
  95.         return $this->connect($hostname, $username, $password);
  96.     }
  97.    
  98.     public function __destruct()
  99.     {
  100.         return true;
  101.     }
  102.    
  103.     /**
  104.      * MySQL connect
  105.      *
  106.      * @param string $hostname MySQL server address/ip(port)
  107.      * @param string $username MySQL username
  108.      * @param string $password MySQL password
  109.      * @return boolean
  110.      */
  111.     private function connect($hostname,$username,$password)
  112.     {
  113.         $this->link = @mysql_connect($hostname, $username, $password, true);
  114.         if (!$this->link) return exit(mysql_error($this->link));
  115.         else return $this->ready = true;
  116.     }
  117.    
  118.     /**
  119.      * MySQL select database
  120.      *
  121.      * @param string $database MySQL database name to use
  122.      * @return boolean
  123.      */
  124.     public function select_db($database = '')
  125.     {
  126.         if (!$this->link) return exit(mysql_error($this->link));
  127.         else if (!@mysql_select_db($database)) {
  128.             $this->ready = false;
  129.             return exit(mysql_error($this->link));
  130.         }
  131.         else $this->database = $database;
  132.         return true;
  133.     }
  134.    
  135.     /**
  136.      * MySQL query
  137.      *
  138.      * @param string $sentence MySQL query sentence
  139.      * @return integer Number of selected rows
  140.      */
  141.     public function query($sentence = '')
  142.     {
  143.         if (!$this->link) return exit(mysql_error($this->link));
  144.         $this->result = @mysql_query($sentence, $this->link);
  145.         if (!$this->result) {
  146.             $this->query_error = true;
  147.             return exit(mysql_error($this->link));
  148.         }
  149.        
  150.         $this->affected_rows = mysql_affected_rows($this->link);
  151.        
  152.         if (preg_match('/^\s*(insert|replace)(.+)/is',$sentence))
  153.             $this->last_id = mysql_insert_id($this->link);
  154.        
  155.         if (preg_match('/^\s*(select)(.+)/is', $sentence)) {
  156.             if ($this->affected_rows > 0) {
  157.                 $rows = 0;
  158.                 while ($row = mysql_fetch_object($this->result)) {
  159.                     $this->query_result[$rows] = $row;
  160.                     $rows++;
  161.                 }
  162.             }
  163.         }
  164.        
  165.         @mysql_free_result($this->result);
  166.        
  167.         if ($this->query_error) $this->query_error = false;
  168.        
  169.         $this->rows = $rows;
  170.         return true;
  171.     }
  172.    
  173.     /**
  174.      * Clean cached query result
  175.      *
  176.      * @access public
  177.      * @return void
  178.      */
  179.     public function clean()
  180.     {
  181.         $this->query_error = false;
  182.         $this->query_result = array();
  183.         $this->affected_rows = null;
  184.     }
  185.    
  186.     /**
  187.      * Espaces a string
  188.      *
  189.      * @access public
  190.      * @param string $string
  191.      * @return string
  192.      */
  193.     public function escape($string)
  194.     {
  195.         if (!$this->link) return exit(mysql_error($this->link));
  196.         $string = stripslashes($string);
  197.         return @mysql_real_escape_string($string, $this->link) ;
  198.     }
  199. }
  200.  
  201. ?>
  #5 (permalink)  
Antiguo 15/02/2010, 06:51
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Cosas que deberán modificar:

1) La variable SimpleLogin::$auth_salt, en el archivo SimpleSession.php tienen que poner su propio salt, si desean encryptar las claves con crypt(), si quieren utilizar otro metodo sientanse libres de ir al metodo SimpleLogin::login() y cambiar este detalle...
2) En las consultas MySQL, los nombres de las tablas "_sessions" y "_users" se toman desde el arreglo (array) SimpleMySQL::$tables Solo deben armar ese arreglo de la siguiente manera para no tener que modificar todas las consultas... (Al menos para probarlo...)

Código PHP:
Ver original
  1. <?php
  2.  
  3. // Tablas
  4. $_TABLES = array(
  5.     'users' => '_users',
  6.     'sessions' => '_sessions'
  7. );
  8.  
  9. $MySQL = new SimpleMySQL('mysql_server', 'mysql_user', 'mysql_pass');
  10. $MySQL->select_db('mysql_db_name');
  11. $MySQL->tables = $_TABLES;
  12.  
  13. ?>

3) Modifiquen a su gusto las llaves para utilizar mcrypt, para encryptar los datos de la sesion... En el archivo SimpleSession.php, al principio van a ver la definicion de estas dos constantes: SESSION_DATA_ENCRYPTION_KEY_1 y SESSION_DATA_ENCRYPTION_KEY_2

4) Pueden modificar el nombre del COOKIE enviado para las sesiones y la duracion:
SimpleSession::$name // Default: __SESSID
SimpleSession::$lifetime // Default: 1800 (30 minutos)

Una ves creado la base de datos con las tablas, ya podemos probar todo:
test.php
Código PHP:
Ver original
  1. <?php
  2.  
  3. include 'SimpleMySQL.php';
  4. include 'SimpleSession.php';
  5.  
  6. // Creamos instancia de SimpleMySQL
  7. $SimpleMySQL = new SimpleMySQL('localhost', 'root', 'pass');
  8. $SimpleMySQL->select_db('test');
  9. $SimpleMySQL->tables = array(
  10.     'users' => '_users',
  11.     'sessions' => '_sessions'
  12. );
  13.  
  14. // Creamos instancia de SimpleSession, pasando como unico argumento,
  15. // la instancia de SimpleMySQL
  16. $SimpleSession = new SimpleSession($SimpleMySQL);
  17. $SimpleSession->start();
  18.  
  19. if ((bool)$_POST['login'])
  20.     $SimpleSession->login($_POST['username'], $_POST['password']);
  21.  
  22. if (isset($_GET['logout']))
  23.     $SimpleSession->logout();
  24.  
  25. $_SESSION_ERROR = array(
  26.     1 => 'La contraseña no coincide con el nombre de usuario ingresado.',
  27.     2 => 'El nombre de usuario ingresado es inexistente.',
  28.     3 => 'La cuenta con la que usted está tratando de ingresar, no está autorizada para acceder al área de administración.',
  29.     4 => 'La cuenta con la que usted está tratando de ingresar, aún no ha sido validada. <br />Si usted es el dueño de esta cuenta, puede validarla haciendo clic <a href="#" class="blue">aquí</a>.',
  30.     5 => 'La cuenta con la que usted está tratando de ingresar ha sido bloqueada por un administrador.',
  31.     6 => 'No ha ingresado su nombre de usuario.',
  32.     7 => 'No ha ingresado su contraseña.',
  33.     8 => 'Se ha producido un error interno desconocido. Por favor, intente más tarde.'
  34. );
  35.  
  36. // Si hay un error lo imprimimos
  37. if ($SimpleSession->status > 0) {
  38.     print '<p style="color: red;">' .$_SESSION_ERROR[$SimpleSession->status]. '</p>';
  39. }
  40.  
  41. if ($SimpleSession->logged_in()) {
  42. ?>
  43. <h4>Bienvenido, <span style="color: red;"><?php print $SimpleSession->data->account_name ?></span></h4>
  44. <p>ID de sesión: <strong><?php print $SimpleSession->id ?></strong><br />ID de usuario: <strong><?php print $SimpleSession->data->account_id ?></strong><br /><a href="?logout">Cerrar sesi&oacute;n</a></p>
  45. <h4>Datos almacenados en la superglobal $_SESSION</h4>
  46. <pre>
  47. <?php print_r($_SESSION) ?>
  48. </pre>
  49. <p><strong>Nota</strong>: Se pueden llamar y almacenar dato en $_SESSION a travé del objeto SimpleSessionData de la siguiente manera:</p>
  50. <pre>
  51. $SimpleSession->data->foo = 'bar';
  52.  
  53. // Lo cual es lo mismo a hacer:
  54.  
  55. $_SESSION['foo'] = 'bar';
  56.  
  57. // Por ahi les paresca tonto pero al menos ami
  58. // Siempre me parecio mas facil manejar variables
  59. // en forma de objeto que arreglos...
  60. </pre>
  61. <?php
  62. } else {
  63. ?>
  64. <fieldset style="display: inline-block;">
  65.     <legend>Prueba de SimpleSession</legend>
  66.     <form method="post">
  67.         <input type="hidden" name="login" value="1" />
  68.         <table>
  69.             <tr>
  70.                 <td><label for="username">Usuario</label></td>
  71.                 <td><input type="text" id="username" name="username" maxlength="16" /></td>
  72.             </tr>
  73.             <tr>
  74.                 <td><label for="password">Contrase&ntilde;a</label></td>
  75.                 <td><input type="password" id="password" name="password" maxlength="16" /></td>
  76.             </tr>
  77.             <tr>
  78.                 <td>&nbsp;</td>
  79.                 <td><input type="submit" value="Iniciar sesi&oacute;n" /></td>
  80.             </tr>
  81.         </table>
  82.     </form>
  83. </fieldset>
  84. <?php
  85. }
  86.  
  87. ?>

Como van a ver en el archivo test.php, explico que pueden llamar variables de $_SESSION a traves del objeto SimpleSessionData... Por ahi les parece inutil, pero a mi siempre me parecio mas facil utilizar variables en forma de objeto, en vez de arreglos...

Asi que pueden hacer de las dos maneras:
Código PHP:
Ver original
  1. <?php
  2.  
  3. // Esto:
  4. $SimpleSession->data->foo = 'bar';
  5. print $SimpleSession->data->foo;
  6.  
  7. // Es igual a esto:
  8. $_SESSION['foo'] = 'bar';
  9. print $_SESSION['foo'] ;
  10.  
  11. // Otro ejemplo...
  12. if (isset($SimpleSession->data->foo)) {
  13.     print 'Existe foo';
  14.     unset($SimpleSession->data->foo);
  15. }
  16.  
  17.  
  18. ?>

Simplemente acuerdense de usar este metodo despues de $SimpleSession->start();

Bueno... Espero que les sirva y comenten... ¡Si ven que algo anda mal avisen! De seguro yo mismo tambien tratare de mejorarlo...

¡Saludos a todos!

Última edición por Nisrokh; 15/02/2010 a las 08:09
  #6 (permalink)  
Antiguo 15/02/2010, 07:20
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Otras cosas que deben saber es que al autentificar un usuario, se guardan los siguientes datos en la sesion:

Código PHP:
Ver original
  1. <?php
  2.  
  3. // ID del la cuenta
  4. $_SESSION['account_id'];
  5.  
  6. // Nombre de la cuenta
  7. $_SESSION['account_name'];
  8.  
  9. // Tipo de la cuenta
  10. // En mi caso lo utilize asi:
  11. // 0 => Administrador, 1 => Moderador, 2 o mas => Usuario normal
  12. // Pueden cambiar o sacar esto cambiando la tabla _users y modificando
  13. // el metodo SimpleSession::login() y eliminando/cambiando la constante:
  14. // LOGIN_ACCESS_ERROR_UNAUTHORIZED_ACCOUNT
  15. $_SESSION['account_type'];
  16.  
  17. // Al estar logueado esto queda como true, pero ojo...
  18. // Al checkear si alguien esta logueado con SimpleSession::logged_in()
  19. // Se fija si existe el nombre usuario ($_SESSION['account_name'])
  20. // Sino existe o esta vacio, se cierra la session del usuario
  21. // eliminando todas las variables mencionadas aqui, incluso esta misma
  22. $_SESSION['access'];
  23.  
  24. ?>

Nota: Para determinar si el usuario esta logueado, se comprueba que:

* $_SESSION['account_name'] exista y no este vacia
* $_SESSION['access'] que como booleano siempre de true

¡Si les parece inseguro sugieran otro metodo para mejorarlo!

Al intentar un usuario loguearse, login se encarga de setear los errores utilizando las constantes definidas en SimpleSession.php

Código PHP:
Ver original
  1. <?php
  2.  
  3. define('LOGIN_ACCESS_NO_ATTEMPT', -1); // Solo para una referencia de que no se intento loguear...
  4. define('LOGIN_ACCESS_GRANTED', 0); // Usuario se logue correctamente (no hay error)
  5.  
  6. // Error de login: contraseña incorrecta
  7. define('LOGIN_ACCESS_ERROR_ATTEMPT_FAILED', 1);
  8.  
  9. // Error de login: cuenta inexistente
  10. define('LOGIN_ACCESS_ERROR_NONEXISTENT_ACCOUNT', 2);
  11.  
  12. // Error de login: cuenta no autorizada
  13. // Deben modificar el metodo SimpleLogin::login() y cambiar la parte en q solo deja entrar
  14. // a usuarios con account_type = 0 || 1
  15. // Ya que en mi caso solo keria dejar entrar admins y mods
  16. // Si tienen dudas pregunten
  17. define('LOGIN_ACCESS_ERROR_UNAUTHORIZED_ACCOUNT', 3);
  18.  
  19. // Error de login: cuenta sin validar
  20. // De nuevo: modifiquen si kieren, el metodo SimpleLogin::login()
  21. // Ya que solo deja entrar a usuarios validados
  22. // con account_status = 1 (validado) || 0 (sin validar)
  23. define('LOGIN_ACCESS_ERROR_UNVALIDATED_ACCOUNT', 4);
  24.  
  25. // Error de login: cuenta bloqueada
  26. // cuando account_status < 0
  27. define('LOGIN_ACCESS_ERROR_BLOCKED_ACCOUNT', 5);
  28.  
  29. // Error de login: no se ingreso usuario en el form
  30. define('LOGIN_ACCESS_ERROR_MISSING_USERNAME', 6);
  31.  
  32. // Error de login: no se ingreso clave en el form
  33. define('LOGIN_ACCESS_ERROR_MISSING_PASSWORD', 7);
  34.  
  35. ?>

Si el logueo falla, podemos imprimir los errores de una menera muy simple, de acorde a los errores dados en las constantes:

Código PHP:
Ver original
  1. <?php
  2.  
  3. $SimpleSession = new SimpleSession($MySQL);
  4. $SimpleSession ->start();
  5. $SimpleSession->login('test', 'test');
  6.  
  7. $_SESSION_ERROR = array(
  8.     1 => 'La contraseña no coincide con el nombre de usuario ingresado.',
  9.     2 => 'El nombre de usuario ingresado es inexistente.',
  10.     3 => 'La cuenta con la que usted está tratando de ingresar, no está autorizada para acceder al área de administración.',
  11.     4 => 'La cuenta con la que usted está tratando de ingresar, aún no ha sido validada. <br />Si usted es el dueño de esta cuenta, puede validarla haciendo clic <a href="#" class="blue">aquí</a>.',
  12.     5 => 'La cuenta con la que usted está tratando de ingresar ha sido bloqueada por un administrador.',
  13.     6 => 'No ha ingresado su nombre de usuario.',
  14.     7 => 'No ha ingresado su contraseña.',
  15.     8 => 'Se ha producido un error interno desconocido. Por favor, intente más tarde.'
  16. );
  17.  
  18. // Si hay un error lo imprimimos
  19. if ($SimpleSession->status > 0) {
  20.     print '<p>' .$_SESSION_ERROR[$SimpleSession->status]. '</p>';
  21. }
  22.  
  23. ?>

Y por último... Al utilizar el metodo SimpleLogin::logout() se destruyen TODAS las variables de la sesion... Si desean mantener datos aun despues de que un usuario cierre sesion, cambian el metodo SimpleLogin::logout() para que solo destruya las variables de las que hablamos anteriormente:

Código PHP:
Ver original
  1. $_SESSION['account_id'];
  2. $_SESSION['account_name'];
  3. $_SESSION['account_type'];
  4. $_SESSION['access'];

Si tienen dudas, ya saben... ¡Pregunten!

Última edición por Nisrokh; 15/02/2010 a las 12:27
  #7 (permalink)  
Antiguo 16/02/2010, 17:25
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Bueno, si llegué a la página 6 sin ninguna respuesta, creo que a nadie le sirvio... xD Mi primer aporte ha fallado...

Saludos...
  #8 (permalink)  
Antiguo 23/02/2010, 02:53
Avatar de genuine_carlosV2  
Fecha de Ingreso: noviembre-2008
Ubicación: 127.0.0.1
Mensajes: 296
Antigüedad: 15 años, 5 meses
Puntos: 6
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

Buenas,

No he llegado a implementarlo pero me lo he mirado por encima. Si me permites, te haré una sugerencia:
No cifres los passwords, eso es un fallo de seguridad en tu web. Si por lo que sea, alguien lograse acceder a tu BD, haciendo la operación inversa obtendría los passwords (das la contraseña) de todos tus usuarios (incluyendo, si existen, administradores). Además, si no dieses la contraseña, alguien con mala leche, también podría sacarla por fuerza bruta (nunca creas que a ti no te va a pasar porque la gente se aburre mucho). Finalmente, desde un punto de vista moral y de confianza a tus usuarios, tu no deberías saber los passwords de éstos ya que eres el administrador de la web y, por tanto, ya tienes acceso a lo que quieras, saber los passwords de la gente te puede dar acceso a otros sitios web/ordenadores donde hayan puesto el mismo password (si, fallo de los usuarios, pero dime, seguro que tienes passwords distintos para TODO? si la respuesta es si, enhorabuena, eres de los pocos que le importan sus datos. En caso contrario, piensa que si a tu ya pones varias contraseñas iguales, imagínate la gente que no le gusta o no tiene curiosidad por la informática).

Que deberías hacer para solucionar esto? Usa un sistema de una sola dirección como, por ejemplo, los HASH. Basa tu sistema de passwords en MD5. Por ejemplo:
Si mi password fuese 'Nisrokh', guarda en tu base de datos 'a2aa89f25ae1392526ebf99e1e6bed01' de modo que no hay forma de saber si esa cadena proviene de 'Nisrokh' o de vete tu a saber donde.
Para verificar que un password sea correcto, tan solo haz:
Código PHP:
if( md5$campo_formulario ) == $password_guardado ) {
echo 
'Aplicar un mismo hash dos veces a un mismo texto da el mismo resultado';
} else {
echo 
'Si los hashes no son iguales, significa que no provienen del mismo texto';

Si alguien pierde su password, tienes que verificar sus datos como sea y solicitarle un nuevo password o poner un password predefinido como md5( 'predefinido' ) o, incluso, una cadena aleatoria que ya le enviarás vía e-mail o como sea.

Finalmente, quiero hacer una reflexión sobre los sitios web en general y este tema. NUNCA y repito, NUNCA te fíes de una web en la cual, si te olvidas tu password, sean capaces de devolvertelo porque eso significa que ellos SABEN cual es tu password (no son correctos moralmente hablando) y, por tanto, si sufren un ataque, el atacante tiene una posibilidad de saber también tu password (no son correctos hablando de seguridad). De quien te puedes fiar pues? Pues de todas esas webs que, si olvidas tu password, te dan un período de X días para que introduzcas un password nuevo o cosas así.

P.D.: Según la actual ley española, revelar datos de una BD está castigado para el programador con 30.000 € por cada dato. Si uno entra en tu web y coge los passwords de 100 personas que tengas registradas, multiplica...

Saludos
__________________
Carlos

Recoger datos es solo el primer paso hacia la sabiduría. Pero compartir información es el primer paso hacia la comunidad. - IBM
  #9 (permalink)  
Antiguo 23/02/2010, 03:18
 
Fecha de Ingreso: enero-2008
Ubicación: /España/Galicia
Mensajes: 928
Antigüedad: 16 años, 3 meses
Puntos: 21
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

otro fallo que veo es que tienes en la db bigint20 en el campo id

99.999.999.999.999.999.999

tendrás tantos usuarios?

999.999.999.999

yo siempre pongo esos int 12.

ya es demasiado, pero por si las moscas ;)

también se complica demasiado para hacer un simple login
__________________
Compra y Vender artículos en https://www.losredactores.com o una comunidad de webmasters ? https://webeamos.com
  #10 (permalink)  
Antiguo 24/02/2010, 04:17
Avatar de genuine_carlosV2  
Fecha de Ingreso: noviembre-2008
Ubicación: 127.0.0.1
Mensajes: 296
Antigüedad: 15 años, 5 meses
Puntos: 6
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

SainT90,

Según tengo entendido, el valor numérico después de 'int' no indica la cantidad de dígitos que acepta el número (esto si es así en el formato DECIMAL). Igualmente, coincido contigo en que usar un BIGINT es un poco excesivo.

Corrígeme si me equivoco.

Saludos
__________________
Carlos

Recoger datos es solo el primer paso hacia la sabiduría. Pero compartir información es el primer paso hacia la comunidad. - IBM
  #11 (permalink)  
Antiguo 28/02/2010, 08:52
 
Fecha de Ingreso: septiembre-2009
Ubicación: Neuquén
Mensajes: 142
Antigüedad: 14 años, 6 meses
Puntos: 12
Respuesta: [APORTE] Sistema de Sesiones y Autentificación de usuario con MySQL

genuine_carlosV2, me has informado bastante bien, gracias.

SainT90, el BIGINT no lo veo que sea un fallo, si esto es un aporte se supone que cada uno lo ajuste a su manera...

genuine_carlosV2, gracias por tu aporte...

Igualmente yo mismo me he dado cuenta de varias cosas que son necesarias modificar...

¡Saludos a todos y gracias por su ayuda!

Última edición por Nisrokh; 28/02/2010 a las 08:57

Etiquetas: mysql, sesiones, sitemap, aportes, usuarios
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 10:10.