LOGIN PHP: ¿Cómo crear un login en PHP y MySQL en menos de una hora?
by Juan Carlos García
27-En-2024
(13)
Suscribirme al canal:
Hoy vamos hacer algo que estoy seguro te va a encantar y que has estado esperando, claro, si has seguido mi curso de PHP con MySQL. Hoy veremos como hacer un sistema de login en PHP MySql completo en un vídeo que no dura ni una hora, con lo cual aprenderás a limitar el acceso de tus aplicaciones y comprenderás el manejo de sesiones en PHP.
- No olvides seguir las otras clases, por ejemplo: ¿Cómo Realizar Select, Update, Delete en MySQL desde PHP?
Y si te gusta mi contenido puedes apoyarme suscribiéndote a mi canal de YouTube y compartiendo en redes sociales. 😜
¡No te puedes perder las nuevas clases 🧐!
Conectar PHP con MySQL
¿Cómo realizar la conexión de PHP con MySQL utilizando PDO y MySQLi?
(4)
Insertar datos en MySQL desde PHP
¿Cómo insertar datos en MySQL desde PHP? Y ¿ Cómo obtener el ultimo ID insertado de una tabla?
(4)
Sentencias Preparadas MySQL PHP
¿Cómo crear y ejecutar sentencias preparadas (Prepared Statement) en MySQL con PHP?
(2)
Select, Update, Delete MySQL PHP
¿Cómo hacer y ejecutar querys SELECT, UPDATE y DELETE en MySQL desde PHP?
(1)
¿Cómo crear un Dashboard en PHP y MySQL?
¿Cómo crear un Dashboard con gráficas en PHP y MySQL?
(10)
Procedimientos Almacenados MySQL PHP
CREATE PROCEDURE en MySQL: ¿Cómo crear procedimientos almacenados en MySQL?
(6)
🧐 Autoevaluación: Login en PHP
¿Qué función se utiliza para iniciar una sesión en PHP?
Para enviar datos desde un formulario HTML a un script PHP utilizando el método POST, ¿Cuál es el atributo que debe tener el formulario?
En HTML, ¿Cuál de las siguientes etiquetas se utiliza para crear un encabezado de nivel 1?
Tabla de contenido
- 1 💡 ¿Cómo haremos nuestro login?
- 2 💡 ¿Qué necesito para crear un Login en PHP?
- 3 💡 Pasos para crear nuestro Login
- 4 Manejo de sesiones en PHP
- 5 Manejando la sesión en una clase
- 6 Maquetación de nuestro Login
- 7 Creando el servicio que atenderá los request del Front End
- 8 Comprobando la sesión en las diferentes pantallas
💡 ¿Cómo haremos nuestro login?
Bien lo primero que debes saber es que este post forma parte de mi curso de PHP y MySQL, en un capitulo anterior creamos un dashboard donde mostramos algunos indicadores y una gráfica.
Ahora bien, el objetivo de este nuevo vídeo es agregarle seguridad a ese dashboard que creamos y limitar el acceso, crearemos un Login desde cero y aprenderás a manejar las sesiones en una aplicación monolítica.
- Entonces, debes ver el vídeo para que puedas ver paso a paso la creación del Login, a continuación te dejo los conceptos básicos que debes saber para poder entender correctamente.
💡 ¿Qué necesito para crear un Login en PHP?
Principalmente necesitamos lo siguiente:
- Manejo de sesiones en PHP.
- Te dejo este post donde aprenderás la teoría de la Programación Orientada a Objetos, lo vas a necesitar ya que usamos POO en este tutorial.
- La maquetación web la haremos con Bootstrap, aquí te dejo este otro vídeo donde hacemos una página web completa.
- Vamos a utilizar AJAX para comunicar JavaScript y el back end en PHP.
Y listo creo que estos son los puntos más importantes, obviamente te invito a revisar todos los vídeos de este curso que con este ya son 8 capítulos y si te gustan suscríbete a mi canal de YouTube.
💡 Pasos para crear nuestro Login
- Primero es que clones el repositorio que tenemos en esta URL, o dale descargar aquí, te aviso que vamos avanzando y tal vez descargues versiones posteriores a las que te muestro en este vídeo, solo es cuestión que revises el código
https://github.com/EWebik/php-mysql-desde-cero.git
- Crea los nuevos archivos como muestro en el vídeo
- Crear tabla usuarios donde almacenaremos los usuarios que tendrán acceso a nuestro dashboard. Solo debes correr el query directamente en phpMyAdmin.
CREATE TABLE usuarios (
id INT(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(45) NOT NULL DEFAULT '',
correo VARCHAR(45) NOT NULL DEFAULT '',
password VARCHAR(45) NOT NULL DEFAULT '',
fecha_alta datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
estado boolean NOT NULL DEFAULT 0
)
- Ahora solo debemos crear la lógica para la conexión a la base de datos y el manejo de sesiones.
Manejo de sesiones en PHP
El manejo de sesiones en PHP principalmente se utiliza para preservar o almacenar información que se utilizaremos en procesos subsiguientes o futuros al proceso actual.
Con las sesiones podemos guardar información de usuario en memoria y así poder identificarlo en cualquier memento.
En este ejemplo ocuparemos:
- session_start, iniciar una nueva sesión o reanudar la existente
- session_destroy, elimina la sesión
- $_SESSION, almacena las variables de sesión
Gracias por tu calificación
(13)
Manejando la sesión en una clase
La sesión la podemos manejar de diferentes maneras, a mi en lo personal me gusta mucho la POO así que siempre la uso, entonces como te muestro en el vídeo creamos la clase sesion.php.
<?php
include "bd.php";
class Sesion extends BD
{
const SESION_INIT = TRUE;
const SESION_NO_INIT = FALSE;
//Operadores de resolución de ambito
//self --> Hace referencia a la clase actual y se usa cuando accedemos a atributos y métodos const o static desde dentro de la clase
//this --> Hace referencia al objeto actual y lo usamos en atributos o métodos no const y static
//parent --> Temas de herencia, y lo usamos para acceder a atributos o static de una clase padre
//Estado de la sesión
private $edoSesion = self::SESION_NO_INIT;
//Instancia de la clase
private static $instancia;
public function __construct()
{
parent::__construct();
}
/**
* Retorna la instancia de la sesión
* Si la sesión no existe se inicializa
*/
public static function getInstancia()
{
//isset -> Determina si una variable está definida y no es NULL
if (!isset(self::$instancia)) {
self::$instancia = new self;
}
self::$instancia->iniSesion();
return self::$instancia;
}
/**
* Inicializa o reinicializa la sesión
* @retur bool
* true -> si la sesión se inicializa
* false -> si no
*/
public function iniSesion()
{
//session_start — Iniciar una nueva sesión o reanudar la existente
if ($this->edoSesion == self::SESION_NO_INIT) {
$this->edoSesion = session_start();
}
return $this->edoSesion;
}
/**
* Destruir la sesión
*/
public function destruirSesion()
{
if ($this->edoSesion == self::SESION_INIT) {
$this->edoSesion = !session_destroy();
unset($_SESSION);
return !$this->edoSesion;
}
return false;
}
/**
* Almacena datos en la sesión
* $instancia->attr = 'value';
*/
public function __set($name, $value)
{
//$_SESSION --> variables de sesión
$_SESSION[$name] = $value;
}
/**
* Permite obtener datos de la sesión
* echo $instancia->attr;
*/
public function __get($name)
{
if (isset($_SESSION[$name])) {
return $_SESSION[$name];
}
}
/**
* Validar una variable de sesión
*/
public function __isset($name)
{
return isset($_SESSION[$name]);
}
/**
* Eliminamos una variable de sesión
*/
public function __unset($name)
{
//unset — Destruye una variable especificada
unset($_SESSION[$name]);
}
}
Gracias por tu calificación
(13)
- Ahora bien, la clase extiende de otra clase de nombre DB, esta clase nos permite conectarnos a una base de datos que necesitaremos para validar que el usuario existe en el sistema.
<?php
include get_include_path() . 'config.php';
class BD
{
public $oConBD = null;
public function __construct()
{
global $usuarioBD, $passBD, $ipBD, $nombreBD;
$this->usuarioBD = $usuarioBD;
$this->passBD = $passBD;
$this->ipBD = $ipBD;
$this->nombreBD = $nombreBD;
}
/**
* Conexión BD por PDO
*/
public function conBDPDO()
{
try {
$this->oConBD = new PDO("mysql:host=" . $this->ipBD . ";dbname=" . $this->nombreBD, $this->usuarioBD, $this->passBD);
return true;
} catch (PDOException $e) {
echo "Error al conectar a la base de datos: " . $e->getMessage() . "\n";
return false;
}
}
}
- Ahora si podemos crear nuestra clase usuarios.php donde administraremos el Loguin y también nos servirá en las clases siguientes.
<?php
include "sesion.php";
class Usuarios extends Sesion
{
public function __construct()
{
parent::__construct();
$this->sesion = null;
}
public function login($correo, $pass)
{
$query = " select nombre, correo from usuarios where correo= :correo and password= :pass and estado = 1 ;";
$oUsuario = null;
if ($this->conBDPDO()) {
$pQuery = $this->oConBD->prepare($query);
$pQuery->bindParam(':correo', $correo);
$pQuery->bindParam(':pass', $pass);
$pQuery->execute();
$pQuery->setFetchMode(PDO::FETCH_ASSOC);
while ($usuario = $pQuery->fetch()) {
$oUsuario = new Usuario();
$oUsuario->nombre = $usuario['nombre'];
$oUsuario->correo = $usuario['correo'];
}
$this->sesion = $this->getInstancia();
if ($oUsuario != null) {
$jDatos = json_encode($oUsuario);
$this->sesion->__set("rolWeb", $jDatos);
return 200;
} else {
$this->sesion->__set("rolWeb", null);
return 401;
}
}
}
}
class Usuario
{
public $nombre = "";
public $correo = "";
}
Maquetación de nuestro Login
En este punto ya tenemos las clases principales que manejarán el acceso desde el Back End, pero, en el Front también necesitamos hacer cambios para que limitemos el acceso por ejemplo, vamos a maquetar nuestro Login utilizando Bootstrap.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>MySQL con PHP</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="http://localhost/ewebik/web/css/style.css">
</head>
<body>
<div class="container">
<div class="centrar">
<form method="POST" action="http://localhost/ewebik/web/php/login.php">
<img src="https://ewebik.com/static/img/logoN.png" class="img-fluid" />
<div class="form-group">
<label for="idCorreo">Correo electrónico</label>
<input type="email" name="correo" class="form-control" id="idCorreo" aria-describedby="emailHelp" placeholder="Correo electrónico">
<small id="emailHelp" class="form-text text-muted">Valor no valido.</small>
</div>
<div class="form-group">
<label for="idPass">Contraseña</label>
<input type="password" name="pass" class="form-control" id="idPass" placeholder="Contraseña">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<div id="idMensaje" style="display: none;" class="alert alert-danger my-3" role="alert">
<p>El Usuario y/o contraseña no es correcto.</p>
</div>
</div>
</div>
<script src="http://localhost/ewebik/web/js/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
<script>
const queryString = window.location.search;
if (queryString != "") {
//?c=401
const eCode = parseInt(queryString.replace("?c=", ""));
if (eCode == 401) {
document.getElementById("idMensaje").style.display = "block";
}
}
</script>
</body>
</html>
Gracias por tu calificación
(13)
Del código anterior destacamos el siguiente código, donde interceptamos la respuesta de error del servidor que veremos a continuación y mostramos un mensaje al usuario, tu puedes modificar la respuesta para adaptarla a tu proyecto.
const queryString = window.location.search;
if (queryString != "") {
//?c=401
const eCode = parseInt(queryString.replace("?c=", ""));
if (eCode == 401) {
document.getElementById("idMensaje").style.display = "block";
}
}
Gracias por tu calificación
(13)
Creando el servicio que atenderá los request del Front End
Ya tenemos el Front y necesitamos comunicarlo con el Back End, para ello si viste en la maqueta utilizamos un tag form que cuenta con un método submit, al hacer clic en el botón este lanza un request al Back para realizar el Login.
<form method="POST" action="http://localhost/ewebik/web/php/login.php">
<img src="https://ewebik.com/static/img/logoN.png" class="img-fluid" />
<div class="form-group">
<label for="idCorreo">Correo electrónico</label>
<input type="email" name="correo" class="form-control" id="idCorreo" aria-describedby="emailHelp" placeholder="Correo electrónico">
<small id="emailHelp" class="form-text text-muted">Valor no valido.</small>
</div>
<div class="form-group">
<label for="idPass">Contraseña</label>
<input type="password" name="pass" class="form-control" id="idPass" placeholder="Contraseña">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
El request lo atenderemos en el Back de la siguiente manera.
<?php
set_include_path("D:\\desarrollos\\xampp\\htdocs\\ewebik\\");
include "./cuenta/usuarios.php";
$oUsuarios = new Usuarios();
if (!empty($_POST)) {
$correo = $_POST['correo'];
$pass = $_POST['pass'];
$lPassC = sha1(md5("ewebik" . $pass));
//echo $lPassC;
if ($oUsuarios->login($correo, $lPassC) == 200) {
header("Location: http://localhost/ewebik/web/");
} else {
header("Location: http://localhost/ewebik/web/paginas/login/?c=401");
}
} else {
header("Location: http://localhost/ewebik/web/paginas/login/?c=401");
}
Donde:
- $_POST, contiene la información del request
- sha1 y md5 nos permiten encriptar la contraseña ya que nunca deberías almacenar este dato en tu base como texto plano.
Si el usuario no esta registrado o tenemos algún erro regresaremos en la URL los parámetros c=401 un código que representa que el usuario no esta autorizado.
header("Location: http://localhost/ewebik/web/paginas/login/?c=401");
Comprobando la sesión en las diferentes pantallas
Bien en este punto tu usuario ya debe estar logueado, pero no hemos limitado el acceso en la otras pantallas o URLs, que en este caso solo tenemos la de el Dashboard, para ello debemos ir al servicio que atiende los request del Dashboard y validar la sesión, por ejemplo:
<?php
set_include_path("D:\\desarrollos\\xampp\\htdocs\\ewebik\\");
include "./cuenta/usuarios.php";
include './mysql.php';
$oMysql = new MySQL();
$oUsuarios = new Usuarios();
$response = "";
if (!empty($_POST)) {
$oUsuarios->sesion = $oUsuarios->getInstancia();
$rolWeb = $oUsuarios->sesion->__get("rolWeb");
if ($rolWeb) {
http_response_code(200);
$rq = $_POST['rq'];
if ($rq == 1) {
$response = $oMysql->getVendidos();
} else if ($rq == 2) {
$response = $oMysql->getAlmacen();
} else if ($rq == 3) {
$response = $oMysql->getIngresos();
} else if ($rq == 4) {
$response = $oMysql->getDatosGrafica();
}
echo $response;
} else {
header("Location: http://localhost/ewebik/web/paginas/login/");
http_response_code(401);
}
} else {
header("Location: http://localhost/ewebik/web/paginas/login/");
http_response_code(401);
}
Gracias por tu calificación
(13)
Si vemos que la variable rolWeb existe quiere decir que hay una sesión valida, tu puedes agregar más validaciones como validar el permiso para saber si el usuario puede ver esta pantalla, en este caso como es un ejemplo sencillo no hay problema.
Por ultimo nos falta modificar el archivo index.js quien hace los request desde el Front para obtener los datos del Dashboard, necesitamos que lo primero que se envié sea un request que valide la sesión, por ejemplo:
function index() {
this.ini = function() {
console.log("Iniciando...");
this.getSesion();
};
this.getSesion = function() {
const _this = this;
$.ajax({
statusCode: {
401: function() {
window.location.href = "http://localhost/ewebik/web/paginas/login/";
},
200: function() {
_this.getInidicadores();
_this.getDatosGraficas();
}
},
url: "php/servidor.php",
method: "POST",
data: {
rq: "0"
}
});
};
this.getInidicadores = function() {
//Vendidos
$.ajax({
statusCode: {
404: function() {
console.log("Esta página no existe");
}
},
url: "php/servidor.php",
method: "POST",
data: {
rq: "1"
}
}).done(function(datos) {
//La lógica 3,000
$("#idVendidos").text(parseFloat(datos).toLocaleString());
});
//Almacen
$.ajax({
statusCode: {
404: function() {
console.log("Esta página no existe");
}
},
url: "php/servidor.php",
method: "POST",
data: {
rq: "2"
}
}).done(function(datos) {
//La lógica 3,000
$("#idAlmacen").text(parseFloat(datos).toLocaleString());
});
//Ingresos
$.ajax({
statusCode: {
404: function() {
console.log("Esta página no existe");
}
},
url: "php/servidor.php",
method: "POST",
data: {
rq: "3"
}
}).done(function(datos) {
//La lógica 3,000
$("#idIngreso").text(parseFloat(datos).toLocaleString());
});
};
this.getDatosGraficas = function() {
$.ajax({
statusCode: {
404: function() {
console.log("Esta página no existe");
}
},
url: "php/servidor.php",
method: "POST",
data: {
rq: "4"
}
}).done(function(datos) {
//La lógica
if (datos != "") {
let etiquetas = new Array();
let tVendidos = new Array();
let tPrecio = new Array();
let coloresV = new Array();
let coloresP = new Array();
var jDatos = JSON.parse(datos);
var tablaDatos = document.createElement("tabla");
tablaDatos.classList.add("table", "table-striped");
var tr = document.createElement("tr");
var th = document.createElement("th");
th.innerText = "Fecha";
tr.appendChild(th);
th = document.createElement("th");
th.innerText = "Ventas";
tr.appendChild(th);
th = document.createElement("th");
th.innerText = "Precio";
tr.appendChild(th);
tablaDatos.appendChild(tr);
for (let i in jDatos) {
etiquetas.push(jDatos[i].fechaVenta);
tVendidos.push(jDatos[i].totalVendidos);
tPrecio.push(jDatos[i].totalPrecio);
coloresV.push("#36004D");
coloresP.push("679B6B");
tr = document.createElement("tr");
var td = document.createElement("td");
td.innerText = jDatos[i].fechaVenta;
tr.appendChild(td);
td = document.createElement("td");
td.innerText = parseFloat(jDatos[i].totalVendidos).toLocaleString();
tr.appendChild(td);
td = document.createElement("td");
td.innerText = parseFloat(jDatos[i].totalPrecio).toLocaleString();
tr.appendChild(td);
tablaDatos.appendChild(tr);
}
var idCont = document.getElementById("idContTabla");
idCont.appendChild(tablaDatos);
var ctx = document.getElementById("idGrafica").getContext("2d");
var myChart = new Chart(ctx, {
type: "bar",
data: {
labels: etiquetas,
datasets: [
{
label: "Ventas",
data: tVendidos,
backgroundColor: coloresV
},
{
label: "Precios",
data: tPrecio,
backgroundColor: coloresP
}
]
}
});
}
});
};
}
var oIndex = new index();
setTimeout(function() {
oIndex.ini();
}, 100);
Listo, ya tenemos un Login, hay elementos que en este resumen no están así que te recomiendo ver la clase en el vídeo y mirar el repositorio para que puedas acceder al código completo. No olvides en compartir y suscribirte a mi canal en YouTube.
Gracias por tu calificación
(13)
🧐 Autoevaluación: Login en PHP
¿Qué función se utiliza para iniciar una sesión en PHP?
Para enviar datos desde un formulario HTML a un script PHP utilizando el método POST, ¿Cuál es el atributo que debe tener el formulario?
En HTML, ¿Cuál de las siguientes etiquetas se utiliza para crear un encabezado de nivel 1?
Juan Carlos García
Desarrollador de software / SEO
Durante años he desarrollado plataformas dedicadas al rastreo satelital y varios sitios web que se encuentran en la primera página de Google, y hoy quiero compartir contigo lo que se en tecnologías como: Node JS, PHP, C# y Bases de datos.
Si quieres apoyarme sígueme en mis redes sociales y suscríbete a mi canal de YouTube.