Tu primera WebApp en CodeIgniter + Bootstrap casi desde Cero (Formulario de Registro, Login, Base de Datos y cifrado de Contraseña)

La animación que estás viendo describe el producto final de este tutorial. Tras completarlo habrás aprendido lo siguiente:

  • Instalar XAMPP.
  • Hacer uso de una instancia de CodeIgniter.
  • Aprovechar las capacidades de Bootstrap.
  • Manejo de sesión de usuario con CodeIgniter.
  • Validación de formularios con CodeIgniter.
  • Uso de base datos con CodeIgniter.
  • Manejo y almacenamiento seguro de contraseñas con PHP.

Si bien este tutorial es bastante sencillo, es deseable tener conocimientos básicos de PHP, SQL, HTML, CSS, JavaScript y jQuery. Si consideras que me falta explicar algo, por favor hazme la pregunta en la sección de comentarios que yo amablemente respondo rápido.

Ingredientes

Para este tutorial vamos a necesitar un entorno de desarrollo web con PHP, CodeIgniter y Bootstrap. Siéntete libre de cómo armarlo, puedes usar npm o haces una instalación práctica, sin tanta cosa adicional, como te lo describo a continuación.

  • XAMPP: Yo que programo mas en Windows que en Linux, uso XAMPP, aunque existen otros como WAMP y LAMP. Estos entornos traen todo lo que un desarrollador de webapps necesita: un servidor web, PHP, un servidor de base de datos, entre otras herramientas.
  • CodeIgniter: No es CakePHP, no es Lavarel, es CodeIgniter porque es súper sencillo para iniciarse en el mundo de las webapps con PHP.
  • Bootstrap: Porque Bootstrap es una libería de clases CSS popular, sencilla y hermosa.

Manos a la obra

Instalando XAMPP

Tras descargar XAMPP desde este enlace, procede a instalarlo. Es tan sencillo como ejecutar y puro Siguiente, Siguiente, Siguiente. Necesitarás recordar en qué directorio lo instalarás, mi recomendación es que sea en la raíz (C:\). Si quieres una instalación con justo lo necesario, no instales python, ni tomcat ni mercury. Sí vamos a necesitar Apache, PHP, MariaDB (es la versión open source de Mysql) y phpMyAdmin. Tras finalizar la instalación en tu barra de tareas de Windows deberías poder observar el ícono del panel de administración de XAMPP.

Este ícono confirma que tienes XAMPP instalado. Si no lo ves tras la instalación, búscalo en el menú inicio de Windows. Has doble clic sobre el ícono para abrir el panel de conrol de XAMPP

Para poder probar tu código, tendrás que iniciar tanto el servidor web Apache, como el servidor de base de datos MariaDB (MySQL). Pesiona ambos botones de Start para iniciar estos servicios.

Es probable que Windows te pregunte si deseas añadir alguna regla al firewall de Windows pues éstas aplicaciones suponen que esperas recibir tráfico entrante; si tienes una laptop y conmutas con frecuencia entre redes públicas y privadas, dale permiso a todas.

Panel de control de XAMPP

Si todo anda bien, tanto Apache como MySQL se colocarán en verde.

Indicación de que los servicios iniciaron correctamente

Finalmente, si tras abrir el siguiente enlace http://localhost ves la pantalla siguiente, tu entorno de trabajo está listo.

Página de bienvenida de XAMPP tras su instalación e inicio del servicio Apache

Preparando la Base de Datos

Para poder almacenar la información de registro, y para poder consultar de nuevo si una combinación de usuario y contraseña es válida, requerimos crear una base de datos y la tabla correspondiente que almacenará la información del usuario.

Esta base de datos y tabla la vamos a crear haciendo uso de phpMyAdmin, webapp que instaló XAMPP por tí para hacerte la vida fácil con MariaDB.

Creando la Base de Datos

Para crear la base de datos, abre phpMyAdmin escribiendo la siguiente ruta en tu navegador: http://localhost/phpmyadmin/.

Debes definir el nombre con el cual bautizarás la base de datos y recordarlo porque lo vas a necesitar mas adelante. Para esto, tal como se refleja en la imágen siguiente, presiona el botón ‘New’, en la ventana que aparecerá escribe ‘codeigniter’ y finaliza presionando el botón ‘Create’.

Pasos para crear una base de datos con nombre ‘codeigniter’ en phpMyAdmin

Tras crear la base de datos, la verás reflejada en el árbol del área izquierda de la página y del lado derecho phpMyAdmin te dirá que aún no tienes una tabla creada y te dará la opción de crear una.

Creando la Tabla de Registro de Usuario

Para almacenar la información de registro vas a requerir preparar una tabla con los campos necesarios para identificar inequívocamente a un usuario. En el extracto siguiente escrito en SQL puedes ver la definición de una tabla llamada ‘user_login’ con las columnas que vamos a necesitar por los momentos:

-- Los dos guiones indican que el texto contiguo es un comentario en SQL
-- y por lo tanto MySQL no lo toma como parte del script

CREATE TABLE user_login (
-- La columna user_id va a ser nuestra clave primaria, por eso no
-- permite valores nulos y queremos que se establezca por si sola
user_id int(11) NOT NULL AUTO_INCREMENT,
user_name varchar(20) NOT NULL,
user_email varchar(50) NOT NULL,
user_password varchar(100) NOT NULL,
PRIMARY KEY (user_id),
-- De igual manera queremos que no se repitan nombres de usuario
UNIQUE KEY user_name (user_name),
-- Ni correos electrónicos
UNIQUE KEY user_email (user_email)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

Para crear la tabla en MySQL a través de phpMyAdmin, como se muestra en la siguiente imagen, selecciona la base de datos que creaste anteriormente; en el menú de opciones que observas a la derecha, selecciona ‘SQL’ e introduce el codigo anterior.

Editor de sentencias SQL de phpMyAdmin. Los cambios que aca realizas afectan o se aplican la base de datos seleccionada

Tras presionar ‘Go’, un mensaje te confirmará que la tabla se ha creado de manera exitosa. Puedes ver su estructura navegando en el árbol del panel izquierdo, o a través de este enlace.

Visualización de la estructura de la tabla user_login en phpMyAdmin

Instalando CodeIgniter

A diferencia de otros frameworks de PHP, CodeIgniter hace honor a su nombre siendo un framework fácil de instalar y de empezar a utilizar.

Cada vez que desees crear una nueva webapp lo único que necesitarás es crear una copia limpia del directorio que descargarás de este enlace y descomprimirás en el directorio ‘htdocs’ de XAMPP como se observa en la siguiente imagen. Date cuenta de que también renombré el directorio quitándole el ‘-3.1.9’ que posee el archivo descargado.

El directorio ‘htdocs’ es el directorio que XAMPP tiene configurado como la raíz del servidor web Apache, normalmente acá crearías una carpeta por cada aplicación que desees hospedar.

Directorio ‘htdocs’ de XAMPP con CodeIgniter instalado

Para probar que todo anda bien hasta el momento, abre el enlace http://localhost/codeigniter en tu navegador y deberías visualizar la imagen siguiente.

Página de bienvenida tras una instalación limpia de CodeIgniter 3.1.9

Configuración Inicial de CodeIgniter

El abanico de configuraciones que ofrece CodeIgniter (CI en lo sucesivo) es bastante amplio. Los archivos de configuración los consigues en el directorio ‘application\config’ dentro de una instalación de CI.

Archivo config.php de CodeIgniter

Comenzamos con el archivo ‘config.php’, este permite definir configuraciones varias para nuestra webapp sin especializarse en algún tipo en particular. Para los propósitos de este tutorial, de acá nos va a interesar ajustar las variables ‘base_url’ y ‘encryption_key’.

La variable ‘base_url’ debe apuntar a la URL raíz de la webapp. Podrás ver la utilidad de esto mas adelante.

 $config['base_url'] = 'http://localhost/codeigniter';

La variable ‘encryption_key’ la vamos a necesitar para maximizar la robustez de funciones de cifrado de contraseñas que verás mas adelante. Esta debe ser una palabra o frase, mientras mas compleja mejor. Por ejemplo, una sencilla:

$config['encryption_key'] = 'intoMyITLife';

Archivo autoload.php de CodeIgniter

El archivo ‘autoload.php’ define las clases que esperamos que CI prepare de una vez para hacer uso mas adelante. Recordemos que PHP es un lenguaje interpretado y no compilado por lo que se espera que tanto variables como definición de funciones esten declaradas antes de su uso. Si no está la clase precargada, entonces a nivel de código deberás hacerlo empleando la funciones ‘load->library()’ o ‘load->helper()’ de CI.

Para propósitos de este tutorial, donde vamos a necesitar hacer uso de sesión de usuario y trabajar con base de datos, acá nos va a interesar ajustar la variable ‘libraries’ de la siguiente manera:

$autoload['libraries'] = array('database','session');

Por su parte, también haremos uso de funciones de CI que nos ayuden a generar URLs para cargar ficheros adicionales, como las definiciones de Bootstrap, y proteger nuestros formularios contra ataques de scripts maliciosos, para eso ajustaremos la variable ‘helper’ de la siguiente manera:

$autoload['helper'] = array('url','security');

Archivo database.php de CodeIgniter

Anteriormente, ya habíamos creado la base de datos que almacena la tabla que nos permitirá manejar el registro de usuarios y su respectivo control de acceso. Para que CI sepa a cual base de datos acceder, debemos ajustar la propiedad ‘username’ con el nombre de usuario que espera MySQL para permitir conexiones y la propiedad ‘database’ con el nombre que le dimos a nuestra base de datos. Si no has cambiado ninguna propiedad adicional de MySQL, puedes dejar el resto de los atributos tal cual están en el archivo.

$db['default'] = array(
...
'username' => 'root',
...
'database' => 'codeigniter',
...
);

Archivo routes.php de CodeIgniter

Normalmente CI interpreta una URI como la clase y el metodo al cual apuntar cuando se hace una solicitud a través de una URL. El archivo ‘routes.php’ permite alterar el comportamiento de una URI para hacer referencia a páginas y funciones distintas a las que explicitamente dice la URL. De manera adicional, tiene rutas reservadas, una de estas es el método que esperamos sea ejecutado al acceder a la webapp. Mas adelante vamos a crear una clase donde uno de sus métodos realizará ciertas validaciones para mostrarnos bien sea la pantalla de inicio de sesión o acceder de una vez a la aplicación. Esta clase la vamos a llamar ‘user_authentication’, y para que sea ejecutada por defecto, debemos especificarla en el archivo ‘routes.php’. Tras modificarlo, la URL con la que venias probando la instalación de CI te dará el error de página no encontrada, pero no te preocupes que mas adelante la encontrará.

$route['default_controller'] = 'user_authentication';

Instalando Bootstrap

Esta sección debería mas bien llamarse ‘Reutilizando un template de Bootstrap’. Basándonos en una plantilla de ejemplo, tomaremos parte de su html, lo mezclaremos con PHP y tendremos una versión capaz de conectarse con una base de datos para controlar el manejo de sesiones de usuario.

Si te paseas por este enlace, podrás visualizar una maqueta web que te permite tanto iniciar como finalizar sesión pero sin introducir usuario o contraseña alguna, y esto es porque precisamente es una maqueta. Vamos a descargar esta maqueta a través del siguiente enlace y su contenido lo vamos a descomprimir en la raíz del directorio de nuestro proyecto. Como vemos en la siguiente imagen, se han añadido algunos directorios y archivos adicionales.

Directorio CodeIgniter en htdocs con la maqueta de Bootstrap instalada

Puedes ver ahora tu propia copia de esta maqueta en funcionamiento a través de este enlace http://localhost/codeigniter/index.html.

Si interactuas un poco con ella, podrás navegar entre una completa librería de elementos HTML formateados con clases CSS que Bootstrap te ofrece; pero me interesa que pruebes la opción de cerrar sesión en la esquina superior derecha, en el menú con el ícono común de un usuario, la última opción ‘Logout’. Al hacer clic, serás redirigido a una pantalla de inicio de sesión con la cual sin importar que credenciales coloques, al presionar ‘Login’ volverás a la pantalla que se encuentra en la imagen siguiente.

Maqueta de Bootstrap a reutilizar

Trabajando con CodeIgniter

A estas alturas del tutorial, voy a necesitar que el código de las clases que voy a mencionar, lo explores en el siguiente link (es correcto, tengo ya toda una instancia configurada en GitLab para tu uso). En lo sucesivo solo mostraré extractos de código en los que quiero tu atención así como hemos realizado anteriormente.

CI emplea el framework MVC o también llamado Model, View, Controller. Este framework indica que debes trabajar de manera independiente las tres capas básicas de toda aplicación: Modelo, describe los datos e interacción con la capa de persistencia o almacenamiento, en nuestro caso la base de datos ‘codeigniter’ que creamos anteriormente; Vista, describe la capa de presentación hacia el usuario, esta puede ser gráfica, o una API; y Controlador, describe las clases en las que se basa nuestra webapp, en ella tenemos el grueso de la lógica de negocio de nuestra aplicación. Dentro del directorio de instalación de CI los ficheros PHP correspondientes a estas clases estarán almacenados según la siguiente estructura:

application\models
- login_database.php
application\views
- login_form.php
- registration_form.php
- admin_page.php
application\controllers
- user_authentication.php

Por convención, en CI es requerido que toda clase en PHP se corresponda con el nombre del archivo, teniendo en mayúscula la inicial de cada palabra que confome el nombre del archivo, como verás en los ejemplos siguientes.

Modelo

La clase ‘Login_Database’ (archivo ‘login_database.php’) posee, además del constructor, tres funciones que nos permitirán interactuar con la base de datos.

<?php

    Class Login_Database extends CI_Model {

   // Constructor
    public function __construct() {
        ...
    }

    // Insertar registro de nuevo usuario en la base de datos
    public function registration_insert($data) {
         ...
    }

    // Leer información de inicio de sesión desde objeto $data
    public function login($data) {
         ...
    }

    // Leer información de inicio de sesión desde nombre de usuario
    public function read_user_information($username) {
         ...
    }
}
?>

La función ‘registration_insert’ recibe un objeto llamado ‘$data’ que posee los datos suministrados al llenar el formulario de registro de usuario, y devuelve un valor lógico para indicar si el intento de registro proviene de un nuevo usuario o en su defecto, el usuario ya existe.

A través de una consulta en SQL se trae todoslos datos de las columnas de la tabla ‘user_login’ donde el campo ‘user_name’ o ‘user_email’ correspondan con los ingresados en el formulario (mas adelante, cuando veamos el controlador, veremos como se llena ‘$data’ con esta información).

Si la consulta no arroja ningún resultado, se confirma que tanto el usuario como la contraseña son valores únicos provenientes de un nuevo registro, y se realiza la inserción dentro de la tabla ‘user_login’ a través del método ‘db->insert()’; CI sabrá como mapear cada valor dentro del objeto ‘$data’ con las columnas de la tabla ‘user_login’ en la medida de que tanto los miembros de ‘$data’ se llamen igual que las columnas a las que deben referenciarse dentro de la tabla ‘user_login’.

public function registration_insert($data) {

  // Consultar si existe o no el nombre de usuario
  $condition = "user_name =" . "'" . $data['user_name'] . "' or user_email = " . "'" . $data['user_email'] . "'";
  $this->db->select('*');
  $this->db->from('user_login');
  $this->db->where($condition);
  $this->db->limit(1);
  $query = $this->db->get();
  if ($query->num_rows() == 0) {

      // Consulta para insertar en la base de datos
      $this->db->insert('user_login', $data);
      if ($this->db->affected_rows() > 0) {
           return true;
      }
   } else {
      return false;
   }
}

Por su parte, las funciones ‘login()’ y ‘read_user_information()’ ofrecen el mismo comportamiento, solo cambia la forma de entrada de los datos. La función ‘read_user_information’ será empleada en el proceso de inicio de sesión de usuario; la función espera recibir a través de la variable ‘$username’ un nombre de usuario el cual buscará si existe dentro de la table ‘user_login’ y en caso de encontrarlo, devolverá todo el contenido correspondiente al registro dentro de la tabla ‘user_login’, sino, devolverá el valor lógico FALSE para indicar que no fue encontrado.

public function read_user_information($username) {
   $condition = "user_name =" . "'" . $username . "'";
   $this->db->select('*');
   $this->db->from('user_login');
   $this->db->where($condition);
   $this->db->limit(1);
   $query = $this->db->get();

   if ($query->num_rows() == 1) {
        return $query->result();
   } else {
        return false;
   }
}

Vistas

Nuestra webapp está conformada hasta el momento por tres vistas, la pantalla de registro de usuario (‘registration_form.php’), la pantalla de inicio de sesión (‘login_form.php’) y la pantalla a la que esperamos aterrizar tras iniciar sesión (‘admin_page.php’). Para nuestra webapp, estarán conformadas principalmente de código HTML con algo de PHP embedido para automatizar generación de mas código HTML o poder comunicarnos con clases del controlador.

Es en esta capa del framework MVC donde empleamos Bootstrap para reutilizar componentes de estilo CSS.

Voy a explicarte únicamente la vista de registro de usuario (‘registration_form.php’), te aseguro que con ella entenderás la de inicio de sesión.

Inciamos verificando si ya existe una sesión de usuario activa (empleamos la propiedad ‘$session’ de CI para manejar sesiones de usuario), en caso de que así sea invocamos el método ‘user_login_process’ de nuestro controlador el cual exploraremos mas adelante; en base a lo anterior, no nos interesa entonces seguir mostrando el formulario de registro, es por eso que redirigimos al usuario fuera de la pantalla empleando la función ‘header()’.

<?php
   if (isset($this->session->userdata['logged_in'])) {
      header("location: http://localhost/login/index.php/user_authentication/user_login_process");
   }
?>

En el siguiente bloque de código, cargamos las lbrerias que venían con nuestra descarga de Bootstrap para hacer uso de las mismas. Especial atención en el método ‘base_url()’, este método de CI devuelve la raíz que definimos en el archivo ‘config.php’ el cual el navegador necesita para encontrar en el servidor la definición de los .css o .js.

<!-- Core CSS de Bootstrap-->
<link href="<?php echo base_url();?>/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

<!-- CSS de MetisMenu -->
<link href="<?php echo base_url();?>/vendor/metisMenu/metisMenu.min.css" rel="stylesheet">

<!-- CSS Personalizado -->
<link href="<?php echo base_url();?>/dist/css/sb-admin-2.css" rel="stylesheet">

<!-- Fuentes Personalizadas -->
<link href="<?php echo base_url();?>/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">

En esta sección hacemos uso de la función ‘validation_errors()’ de CI, la cual devuelve cualquier error que se haya producido durante la validación de un formulario, y en caso de que esta posea algún mensaje asociado, o algo que mostrar, definimos unos bloques ‘div’ empleando subclases de la clase ‘alert’ del CSS de Bootstrap bien sea para mostrar el mensaje en un cuadro amarillo (‘alert-warning’) o en un cuadro rojo (‘alert-warning’), como puedes ver en la animación con la cual comienza este post.

<?php 
   if (null !== validation_errors() && strlen(validation_errors()) > 0) {
      echo "
";
 echo validation_errors();
 echo "
";
 }
 
 if (isset($message_display)) {
 echo "
";
 echo $message_display;
 echo "
";
 }
?>

La siguiente sección es la definición del formulario de registro; la función ‘form_open()’ es un helper de CI para indicar qué método invocar tras la acción de enviar los datos de un formulario (botón ‘submit’) y que los siguientes elementos serán parte de un formulario hasta que se declare la función ‘form_close()’.

En esta sección también hacemos uso de Bootstrap ajustando valores a las propiedades HTML class de los elementos del formulario.

<?php echo form_open('user_authentication/new_user_registration',array('role'=>'form')); ?>

<fieldset>
  

 


 


 





 


 
 <button class="btn btn-lg btn-success btn-block" name="submit" type="submit" value="">Sign Up</button> 

</fieldset>
<?php echo form_close(); ?>

Para finalizar con esta sección, una forma rápida para saber qué elementos podemos reutilizar de la maqueta de Bootstrap que descargamos, es inspeccionando el código HTML asociado. Varios navegadores te permiten hacer esto de forma sencilla, por ejemplo, en la imagen siguiente puedes ver como en Google Chrome si presionas F12, se despliega un poderoso panel que te permite saber qué hay y qué ocurre tras bastidores de la pagina que estas visualizando. Puedes inspeccionar el codigo HTML de un elemento presionando el botón inspeccionar (1), luego posiciona el cursor sobre el elemento cuyo HTML te interesa ver (2), y este será resaltado (3).

Inspección de código HTML empleando Google Chrome

Controlador

La clase ‘User_Authentication’ explicada parte por parte.

Previamente definimos que esta clase es la que CI invocará automáticamente al acceder a la raíz de nuestra webapp. Lo primero que esta realizará es preparar el manejo de sesiones de usuario de PHP invocando ‘session_start()’.

//Se necesita iniciar sesion de PHP para poder usarla a través de CI
session_start();

En el constructor de la clase debemos ejecutar e inicializar las variables o librerías que nos serán de utilidad mas adelante. Anteriormente te mostré cómo cargarlas de manera automática, también pueden ser cargadas de manera manual; recordemos que en PHP debemos precargar o tener definidas todas las variables, constantes, funciones, entre otros, antes de utilizarlas.

public function __construct() {
   try {
      parent::__construct();
   } catch (Exception $e) {}

   // Cargar manualmente el helper para manejo de formularios
   $this->load->helper('form');

   // Cargar manualmente la libreria que permitirá
   // automatizar validaciones sobre formularios
   $this->load->library('form_validation');

   // Iniciar el modelo de datos
   $this->load->model('login_database');
}

La función ‘user_already_logged()’ podrá ser empleada para validar si existe una sesión iniciada, como se muestra en la función ‘index()’. En CI tras invocarse el constructor de una clase del controlador, la siguiente función a invocarse si no se especifica nada en la URI es ‘index()’. En ‘index()’ se valida si se ha iniciado una sesión de usuario, de ser cierto, muestra la ventana principal de la webapp, sino, redirigirá al usuario para que inicie sesión invocando la carga de la página de inicio de sesión.

private function user_already_logged() {
   return isset($this->session->userdata['logged_in']);
}
        
public function index() {
   if ($this->user_already_logged()) {
      $this->load->view('admin_page');
   } else {
      $this->load->view('login_form');
   }
}    

Anteriormente declaramos en el formulario de registro que cuando ejecutemos el evento de enviar formulario (‘submit’) se ejecutará el método ‘new_user_registration()’, este método realiza las siguientes acciones en el orden descrito: comienza inicializando un conjunto reglas de validación sobre los datos que han sido enviados desde el formulario; el método ‘set_rules()’ especifica para cada uno de los campos el tipo de validación a realizar; para los tres campos del formulario (usuario, correo y contraseña) queremos evaluar que no tenga espacios, que es obligatorio que el valor esté definido y de manera adicional que venga limpio de código malicioso (Cross-Site Scripting – XSS). Si al validar estas reglas, la función ‘run()’ devuelve el valor lógico FALSE, automáticamente CI prepara el mensaje de error que se obtendrá al tratar de ver el contenido de la función ‘validation_errors()’ y de manera adicional, indicamos que vuelta a ser cargada la página que contiene el formulario de registro.

Por el contrario, si la validación del formulario no arroja ningún error, preparamos el objeto ‘$data’ con los valores que capturamos a través del formulario e intentamos registrar estos datos en la base de datos. No obstante, nota que la contraseña no la estamos registrando tal cual viene en el formulario, estamos añadiendo seguridad a nuestra aplicación empleando una de las mejores prácticas en lo que se refiere a almacenamiento de contraseñas en base de datos. La función ‘password_hash()’ genera una versión de la contraseña casi imposible de descifrar, aún empleando estrategias avanzadas de hacking. Si la función ‘registration_insert()’, que vimos anteriormente en la clase ‘login_database()’ del modelo, se ejecuta sin problemas, preparamos el atributo ‘message_display’ del objeto ‘$data’ con el mensaje de registro exitoso y luego mostramos la pantalla de inicio de sesión para que el usuario pruebe sus credenciales de acceso; en caso de que la función ‘registration_insert()’ falle, es porque los datos introducidos ya existían y por lo tanto no son registros válidos para crear un nuevo usuario, se prepara entonces el mensaje para indicar el error y se vuelve a mostrar el formulario de registro.

// Validar y almacenar información de registro en la base de datos
public function new_user_registration() {
   // Validar los datos del formulario
   $this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean');
   $this->form_validation->set_rules('email_value', 'Email', 'trim|required|xss_clean|valid_email');
   $this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');
   if ($this->form_validation->run() == FALSE) {
      $this->load->view('registration_form');
   } else {
      $data = array(
         'user_name' => $this->input->post('username'),
         'user_email' => $this->input->post('email_value'),
         'user_password' => $this->input->post('password')
      );

      //Aplicando seguridad, encriptando la contraseña
      $hashed_password = password_hash($data['user_password'], PASSWORD_DEFAULT);
      $data['user_password'] = $hashed_password;

      $result = $this->login_database->registration_insert($data);
      if ($result == TRUE) {
         $data['message_display'] = 'Registration Successfully !';
         $this->load->view('login_form', $data);
      } else {
         $data['message_display'] = 'Username or Email already exist!';
         $this->load->view('registration_form', $data);
      }
   }
}


Si ya exploraste el código asociado en la página de inicio de sesión (‘login_form.php’), te habrás percatado que el formulario de registro de esta página invoca la función ‘user_login_process()’ del controlador. De igual manera, la explico en orden: antes que nada, se valida que los datos enviados a través del formulario de inicio de sesión vengan sin espacios, estén definidos y no posean código malicioso. Si la validación falla, pero se detectó que ya existía una sesión iniciada, se muestra la pantalla de inicio de nuestra webapp; caso contrario, si no hay sesión iniciada, se muestra de nuevo la pantalla de inicio de sesión recordando que la función ‘run()’ preparará el mensaje de error que desplegará esta página en caso de que existan.

Si la validación de los datos provenientes a través de los campos del formulario es exitosa, lo siguiente es validar que en efecto el usuario esté registrado en la base de datos y la contraseña se corresponda. Nota como la validación de la contraseña se realiza empleando la función ‘password_verify()’; esta función genera el hash para la contraseña introducida y luego valida que sea idéntico al hash de la contraseña que se registró en la base de datos. En caso de que así sea, se cargan los datos de sesión del usuario para que estén disponibles para su uso posterior y se muestra la página de inicio de nuestra webapp.

// Validar el proceso de inicio de sesión de usuario
public function user_login_process() {
   $this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean');
   $this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');

   if ($this->form_validation->run() == FALSE) {
      if(isset($this->session->userdata['logged_in'])){
         $this->load->view('admin_page');
      } else {
         $this->load->view('login_form');
      }
   } else {
      $data = array(
         'username' => $this->input->post('username'),
         'password' => $this->input->post('password')
       );

      $result = $this->login_database->login($data);  
      if (password_verify($data['password'], $result[0]->user_password)) {
         $username = $this->input->post('username');
         $result = $this->login_database->read_user_information($username);
         if ($result != false) {
            $session_data = array(
               'username' => $result[0]->user_name,
               'email' => $result[0]->user_email,
            );
               
            // Añadir la información de usuario a la sesión
            $this->session->set_userdata('logged_in', $session_data);
            $this->load->view('admin_page');
         }
      } else {
         $data = array(
            'error_message' => 'Invalid Username or Password'
         );
         $this->load->view('login_form', $data);
      }
   }
}

    

Por último, queda el método ‘logout()’. Este método se encarga de limpiar las variables de sesión y de destruir los datos de sesión que puedan existir. Esto debe realizarse también por seguridad.

// Cerrar sesión
public function logout() {
   $sess_array = array(
      'username' => ''
   );
   $this->session->unset_userdata('logged_in', $sess_array);
   $this->session->sess_destroy();
   $data['message_display'] = 'Successfully Logout';
   $this->load->view('login_form', $data);
}

A este punto, te he explicado los aspectos mas relevantes de cada clase que componen nuestra webapp. Ahora, toca verla en acción.

Probando tu WebApp

La forma mas rápida de probar todo, es descargando el directorio del repositorio tal cual te indiqué previamente (igual acá te coloco de nuevo el enlace), no obstante, si tu mismo has realizado la instalación y ajustes paso a paso, espera ver la pantalla de inicio de sesión cuando navegues en la URL http://localhost/codeigniter/. Una vez ahí puedes iniciar probando el registro de usuario.

Es probable que se muestren muchos errores de tipo Warning, y esto es porque por defecto CI viene configurado en modo ‘development’. Estos mensajes son importantes, pero puedes deshacerte de ellos cambiando en el archivo ‘index.php’ en la raìz de tu WebApp (directorio ‘htdocs\CodeIgniter’) el entorno de ejecución a ‘testing’. Aún se mostrarán errores importantes pero los de tipo Warning ya no aparecerán.

define('ENVIRONMENT', isset($_SERVER['CI_ENV']) ? $_SERVER['CI_ENV'] : 'testing');

En la pantalla de registro de usario puedes probar introducir valores erroneos en los campos, como valores con espacio al inicio o al final, o correos inválidos (sin la arroba o sin dominio). Tras presionar ‘Sign Up’, la función de validación de nuestro controlador evaluará los datos y fallará notificándote qué errores tienes.

Página de registro de usuario

Por el contrario, si colocaste valores correctos, se mostrará la página de inicio de sesión con el mensaje de que el registro se realizó de manera exitosa.

Pantalla de inicio de sesión tras un registro de usuario exitoso

A este punto me imagino que te preguntas cómo se habrá registrado la contraseña en la base de datos. Pues si volvemos con el viejo amigo phpMyAdmin, podemos explorar el contenido de la tabla ‘user_login’. Puedes hacerlo a través del siguiente enlace. Como puedes apreciar, el registro de la contraseña no se parece en lo mas mínimo al valor que introdujiste en la pantalla de registro. En la siguiente imagen se ve el valor hash generado en mi servidor local para la contraseña ‘Codeigniter’. Aún cuando tu utilices la misma contraseña, aún empleando el mismo ‘encryption_key’ que vimos en el archivo ‘config.php’, el hash será distinto; así de seguro es.

Visualización de los registros de la tabla ‘user_login’

Ahora, te invito a ti mismo a explorar sobre el código y hacer los cambios o experimentos que se te ocurran. La mejor manera de aprender es practicando, haciendo, dañando y corrigiendo.

Reconocimientos

Los siguientes enlaces me ayudaron en la construcción de este tutorial:

  • La idea principal la tomé de este enlace, la idea final (este post) viene con mejoras, traducciones y correcciones de bugs que yo mismo hice.
  • Mi querido stackoverflow, para cifrado de contraseñas y alternar entre modos de despliegue en CodeIgniter.

¡Gracias!

Si te gustó este tutorial, me alegra muchísimo, a mi también me gustó prepararlo. Puedes hacer lo que quieras con el, darle Like, compartirlo, comentar o realizar cualquier consulta en los comentarios, y si está en tus posibilidades, donar a través de PayPal.me para incentivar la creación de mas tutoriales como este.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s