Post Top Ad

Your Ad Spot

jueves, 14 de mayo de 2020

Sistema de inicio de sesión y registro con PHP

Este tutorial cubrirá la creación de un sistema de inicio de sesión con registro al registrar un enlace de activación que se enviará por correo electrónico que contiene un enlace para activar la cuenta. Una vez activo, el usuario puede iniciar sesión, hay una opción de restablecimiento disponible para restablecer la contraseña.
También asegúrese de que su versión php sea al menos 5.3.17, pero idealmente debería ser 5.6 o 7
La estructura del archivo se configurará de la siguiente manera:
La base de datos requerirá una tabla para almacenar los miembros, cree una tabla llamada miembros:
CREATE TABLE `members` (
  `memberID` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `active` varchar(255) NOT NULL,
  `resetToken` varchar(255) DEFAULT NULL,
  `resetComplete` varchar(3) DEFAULT 'No',
  PRIMARY KEY (`memberID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
En la carpeta de clases hay dos archivos: contraseña.php y usuario.php. password.php se usa para proporcionar la misma capacidad de hash que existe en php 5.5, usa los mismos nombres de función para que las versiones 5.3 - 5.5 puedan usar las mismas funciones. <

Nota sobre la contraseña para versiones de php inferiores a 5.5

Esta biblioteca requiere PHP> = 5.3.7 O una versión que tiene el parche de $ 2 atras (como RedHat proporciona). Tenga en cuenta que la versión 5.3.3 de Debian NO es compatible.
user.php es una clase que contiene métodos para devolver el hash de los usuarios (contraseña hash), así como para iniciar sesión, verificar si ya existe una sesión iniciada y cerrar la sesión del usuario.
Revisaré los métodos user.php a medida que se usan.

Config.php

Config.php se incluirá en todas las páginas para habilitar sesiones y activar el búfer de salida de esta manera, los encabezados se pueden usar en cualquier parte del proyecto.
Establezca la zona horaria y defina las credenciales para la base de datos, el próximo intento de hacer una nueva conexión PDO si la conexión falla, muestra el error y elimina la página.
Luego incluya la clase de usuario y haga una instancia de ella, pase el objeto de la base de datos a la clase para hacer uso de la base de datos.
<?php
ob_start();
session_start();

//set timezone
date_default_timezone_set('Europe/London');

//database credentials
define('DBHOST','localhost');
define('DBUSER','database username');
define('DBPASS','password');
define('DBNAME','database name');

//application address
define('DIR','http://domain.com/');
define('SITEEMAIL','noreply@domain.com');

try {

    //create PDO connection 
    $db = new PDO("mysql:host=".DBHOST.";port=8889;dbname=".DBNAME, DBUSER, DBPASS);
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

} catch(PDOException $e) {
    //show error
    echo '<p class="bg-danger">'.$e->getMessage().'</p>';
    exit;
}

//include the user class, pass in the database connection
include('classes/user.php');
include('classes/phpmailer/mail.php');
$user = new User($db); 
?>
A continuación, tengo una carpeta llamada diseño en la que hay un encabezado.php y un pie de página.php, estos contendrán cualquier código de diseño que se utilizará en cada página, esto ahorra tener que incluir la hoja de estilo cada vez.
header.php es un archivo de encabezado típico, tenga en cuenta que el título espera una variable $ title, se creará en las páginas y se pondrá a disposición de este archivo, también haciendo uso de Bootstrap, esto es opcional y no es obligatorio.
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title><?php if(isset($title)){ echo $title; }?></title>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.0/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="style/main.css">
</head>
<body>
Siguiente footer.php esto simplemente cerró el cuerpo y html, ese sería un buen lugar para colocar el código de seguimiento o cualquier javascript incluido.
</body>
</html>

index.php

Esta es la página raíz que el sistema carga de manera predeterminada, en esta página es un formulario para que los usuarios se registren en el sitio, junto con enlaces a la página de inicio de sesión, si ya son miembros. Además, si el usuario ya ha iniciado sesión, será redirigido a la página de miembros.
El inicio de estas páginas es incluir el archivo de configuración y luego verificar si el usuario debe ser redirigido o no.
Se realiza una llamada al objeto de usuario $ user-> is_logged_in (), esto devolverá verdadero o falso si el usuario ha iniciado sesión.
<?php
//include config
require_once('includes/config.php');

//check if already logged in move to home page
//if logged in redirect to members page
if( $user->is_logged_in() ){ header('Location: memberpage.php'); } 
El archivo title y header.php también se incluye en cada página.
//define page title
$title = 'Demo';

//include header template
require('layout/header.php'); 
Para los nuevos registros, muestre un formulario que consta de nombre de usuario, correo electrónico, contraseña y confirme la contraseña.
<form role="form" method="post" action="" autocomplete="off">

                <div class="form-group">
                    <input type="text" name="username" id="username" class="form-control input-lg" placeholder="User Name" value="<?php if(isset($error)){ echo $_POST['username']; } ?>" tabindex="1">
                </div>
                <div class="form-group">
                    <input type="email" name="email" id="email" class="form-control input-lg" placeholder="Email Address" value="<?php if(isset($error)){ echo $_POST['email']; } ?>" tabindex="2">
                </div>
                <div class="row">
                    <div class="col-xs-6 col-sm-6 col-md-6">
                        <div class="form-group">
                            <input type="password" name="password" id="password" class="form-control input-lg" placeholder="Password" tabindex="3">
                        </div>
                    </div>
                    <div class="col-xs-6 col-sm-6 col-md-6">
                        <div class="form-group">
                            <input type="password" name="passwordConfirm" id="passwordConfirm" class="form-control input-lg" placeholder="Confirm Password" tabindex="4">
                        </div>
                    </div>
                </div>
                
                <div class="row">
                    <div class="col-xs-6 col-md-6"><input type="submit" name="submit" value="Register" class="btn btn-primary btn-block btn-lg" tabindex="5"></div>
                </div>
            </form>
Este es un formulario estándar, una cosa a tener en cuenta. Utilizo formularios fijos, lo que significa que si se trata de un error de validación, los campos que se completaron se rellenarán nuevamente con los datos suministrados, excepto las contraseñas. El nombre de usuario y el correo electrónico serán restaurados.
Esto se hace haciendo una declaración if, si se establece el error $ de la matriz, lo que significa que existe, entonces vuelva a entrenar el $ _POST
value="<?php if(isset($error)){ echo $_POST['email']; } ?>"
Si se ha creado un error, se almacenará en una matriz de errores para mostrarlos en bucle a través de la matriz:
//check for any errors
if(isset($error)){
  foreach($error as $error){
    echo '<p class="bg-danger">'.$error.'</p>';
  }
}
Una vez que se haya guardado el nuevo registro, el formulario se volverá a publicar en la misma página agregando una clave $ _GET al final de la URL, la clave se llamará acción, tendrá un valor de unido
(esta técnica se utiliza a través del proyecto)
if(isset($_GET['action']) && $_GET['action'] == 'joined'){
  echo "<h2 class='bg-success'>Registration successful, please check your email to activate your account.</h2>";
}
El formulario solo debe procesarse si se ha enviado, esto puede verificarse mediante una declaración if:
//if form has been submitted process it
if(isset($_POST['submit'])){
De esta manera, solo si se ha enviado el formulario, comienza la validación y comienzan las interacciones de la base de datos.

Validación

La validación utilizada es bastante básica y se puede mejorar
Este ejemplo verifica la longitud del nombre de usuario si tiene menos de 3 caracteres, se crea un error, si la primera verificación pasa, se busca el nombre de usuario para ver si ya existe al pasar el nombre de usuario a la base de datos si se encuentra un registro de un error. creado.
if(strlen($_POST['username']) < 3){
    $error[] = 'Username is too short.';
} else {
    $stmt = $db->prepare('SELECT username FROM members WHERE username = :username');
    $stmt->execute(array(':username' => $_POST['username']));
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    if(!empty($row['username'])){
        $error[] = 'Username provided is already in use.';
    }
        
}
Estos comprueban la contraseña para asegurarse de que el correo electrónico no se haya utilizado, es importante que la dirección de correo electrónico solo se use una vez, en caso de que el usuario quiera restablecer su contraseña, se enviará un enlace por correo electrónico a ese usuario.
if(strlen($_POST['password']) < 3){
    $error[] = 'Password is too short.';
}

if(strlen($_POST['passwordConfirm']) < 3){
    $error[] = 'Confirm password is too short.';
}

if($_POST['password'] != $_POST['passwordConfirm']){
    $error[] = 'Passwords do not match.';
}

//email validation
if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
    $error[] = 'Please enter a valid email address';
} else {
    $stmt = $db->prepare('SELECT email FROM members WHERE email = :email');
    $stmt->execute(array(':email' => $_POST['email']));
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    if(!empty($row['email'])){
        $error[] = 'Email provided is already in use.';
    }
        
}
Después de la validación, si no se han creado errores, continúe.
La contraseña proporcionada no se puede almacenar como está, eso sería un gran problema de seguridad, en lugar de ello se codifica al pasarla al objeto de usuario dentro de una llamada password_hash, esto devuelve una contraseña codificada que luego se puede almacenar en la base de datos, de esta manera nadie puede saber cuál era la contraseña aparte del usuario que la ingresó.
Si se pregunta cómo puede el sistema iniciar sesión en un usuario sin conocer la contraseña; lo que sucede cuando el usuario completa el formulario de inicio de sesión, la contraseña que ingresa se vuelve a cifrar y luego se compara con el hash para ver si coincide.
También queremos enviar un enlace de activación al usuario cuando se registre para garantizar que su dirección de correo electrónico esté activa, para esto generamos un código de activación que se enviará en los correos electrónicos y formará parte de una URL para validar la dirección de correo electrónico.
//if no errors have been created carry on
    if(!isset($error)){

        //hash the password
        $hashedpassword = $user->password_hash($_POST['password'], PASSWORD_BCRYPT);

        //create the activation code
        $activasion = md5(uniqid(rand(),true));
A continuación, los detalles del usuario se guardan en la base de datos utilizando una declaración preparada, la primera página de la consulta le dice a MySQL qué acción realizar en este caso para agregar una nueva fila y la tabla, columnas para insertar.
Donde sus columnas comienzan con: like: username, estos son marcadores de posición que se utilizarán para vincular el valor del nombre de usuario a $ stmt-> execute call. Esto se hace para evitar pasar datos proporcionados por el usuario a la consulta directamente y evitar la posibilidad de inyección de MySQL.
Llamar a lastInsertId seguido de la clave principal devolverá la identificación del registro recién guardado, esto es necesario para el siguiente paso.
$stmt = $db->prepare('INSERT INTO members (username,password,email,active) VALUES (:username, :password, :email, :active)');
$stmt->execute(array(
    ':username' => $_POST['username'],
    ':password' => $hashedpassword,
    ':email' => $_POST['email'],
    ':active' => $activasion
));
$id = $db->lastInsertId('memberID');
A continuación, envíe un correo electrónico al usuario recién creado. Aquí se usarán dos constantes definidas en config.php.
DIR - contiene la dirección completa del sitio web
SITEEMAIL - la dirección de correo electrónico utilizada para los correos electrónicos
En el cuerpo del correo electrónico hay un enlace activar.php? X = $ id & y = $ activación Este enlace está pasando la identificación del usuario $ id y también el código de activación cuando el usuario recibió este correo electrónico, al hacer clic en el enlace se activará su cuenta .
$to = $_POST['email'];
$subject = "Registration Confirmation";
$body = "<p>Thank you for registering at demo site.</p>
<p>To activate your account, please click on this link: <a href='".DIR."activate.php?x=$id&y=$activasion'>".DIR."activate.php?x=$id&y=$activasion</a></p>
<p>Regards Site Admin</p>";

$mail = new Mail();
$mail->setFrom(SITEEMAIL);
$mail->addAddress($to);
$mail->subject($subject);
$mail->body($body);
$mail->send();
El último paso es redirigir la página a sí misma y agregar una acción con el valor de unido para que la página sepa si mostrar un mensaje de éxito.
header('Location: index.php?action=joined');
exit;

active.php

Esta página verifica la identificación y el código de activación que se pasa de la URL (esto sucede cuando el usuario hace clic en el enlace de su correo electrónico).
Una vez que se han verificado los datos, se actualiza el registro de usuarios, la columna activa se cambia del token para mantener 'Sí' para decir que están activos, esto solo sucederá si la identificación y el token pasado coinciden con lo que está almacenado contra ese usuario.
<?php
require('includes/config.php');

//collect values from the url
$memberID = trim($_GET['x']);
$active = trim($_GET['y']);

//if id is number and the active token is not empty carry on
if(is_numeric($memberID) && !empty($active)){

    //update users record set the active column to Yes where the memberID and active value match the ones provided in the array
    $stmt = $db->prepare("UPDATE members SET active = 'Yes' WHERE memberID = :memberID AND active = :active");
    $stmt->execute(array(
        ':memberID' => $memberID,
        ':active' => $active
    ));

    //if the row was updated redirect the user
    if($stmt->rowCount() == 1){

        //redirect to login page
        header('Location: login.php?action=active');
        exit;

    } else {
        echo "Your account could not be activated."; 
    }
    
}
?>

Login.php

Ahora los usuarios pueden registrarse y necesitan una forma de iniciar sesión, comenzar con un formulario que espere su nombre de usuario y contraseña.
<form role="form" method="post" action="" autocomplete="off">

    <div class="form-group">
        <input type="text" name="username" id="username" class="form-control input-lg" placeholder="User Name" value="<?php if(isset($error)){ echo $_POST['username']; } ?>" tabindex="1">
    </div>

    <div class="form-group">
        <input type="password" name="password" id="password" class="form-control input-lg" placeholder="Password" tabindex="3">
    </div>
    
    <div class="row">
        <div class="col-xs-9 col-sm-9 col-md-9">
             <a href='reset.php'>Forgot your Password?</a>
        </div>
    </div>
    
    <hr>
    <div class="row">
        <div class="col-xs-6 col-md-6"><input type="submit" name="submit" value="Login" class="btn btn-primary btn-block btn-lg" tabindex="5"></div>
    </div>
</form>
La página de inicio de sesión se utilizará para mostrar mensajes si la cuenta de usuario se ha activado o se ha cambiado la contraseña, la página sabrá qué mensaje mostrar en función del valor contenido dentro de $ _GET ['acción']
if(isset($_GET['action'])){

    //check the action
    switch ($_GET['action']) {
        case 'active':
            echo "<h2 class='bg-success'>Your account is now active you may now log in.</h2>";
            break;
        case 'reset':
            echo "<h2 class='bg-success'>Please check your inbox for a reset link.</h2>";
            break;
        case 'resetAccount':
            echo "<h2 class='bg-success'>Password changed, you may now login.</h2>";
            break;
    }

}
Siguiente intento de iniciar sesión en el usuario. Recopile el nombre de usuario y la contraseña del formulario y páselos al objeto de usuario en el método de inicio de sesión. password_verify si el hash y el hash del usuario coinciden devuelve verdadero, lo que a su vez establece una sesión $ _SESSION ['loginin'] en verdadero, de lo contrario se devuelve falso.
public function login($username,$password){

    $row = $this->get_user_hash($username);

    if($this->password_verify($password,$row['password']) == 1){

        $_SESSION['loggedin'] = true;
        $_SESSION['username'] = $row['username'];
        $_SESSION['memberID'] = $row['memberID'];
        return true;
    }
}

//process login form if submitted
if(isset($_POST['submit'])){

    $username = $_POST['username'];
    $password = $_POST['password'];
    
    if($user->login($username,$password)){ 

        header('Location: memberpage.php');
        exit;
    
    } else {
        $error[] = 'Wrong username or password or your account has not been activated.';
    }

}//end if submit

Logout.php

Para cerrar la sesión de un usuario es muy fácil: 
//logout
$user->logout(); 
Una vez que el usuario haya cerrado sesión, redirígelo.

memberpage.php

Una vez que el usuario haya iniciado sesión, rediríjalo a la página solo para miembros (opcional).
Para garantizar que un usuario solo pueda acceder a la página si ha iniciado sesión, realice una comprobación:
//if not logged in redirect to login page
if(!$user->is_logged_in()){ header('Location: login.php'); } 
En este ejemplo, no es mucho para la página de miembros, a saber:
<h2>Member only page</h2>
<p><a href='logout.php'>Logout</a></p>

reset.php

Cada sistema necesita la capacidad de restablecer una contraseña en caso de que se olvide, cómo funcionará esto si un usuario ingresa su dirección de correo electrónico, se realiza una verificación para asegurarse de que pertenece a un usuario.
A continuación, se crea un token y se guarda en el registro de los usuarios, se les envía un correo electrónico que contiene un enlace para que cuando se haga clic en el token del enlace se verifique, si pasa, el usuario recibe un formulario para ingresar su nueva contraseña, luego guardado en la base de datos.
Esto puede parecer un enfoque largo pero evita que la contraseña se envíe por correo electrónico, lo que no se recomienda.
Para comenzar con el formulario:
<form role="form" method="post" action="" autocomplete="off">
    <div class="form-group">
        <input type="email" name="email" id="email" class="form-control input-lg" placeholder="Email" value="" tabindex="1">
    </div>
    
    <hr>
    <div class="row">
        <div class="col-xs-6 col-md-6"><input type="submit" name="submit" value="Sent Reset Link" class="btn btn-primary btn-block btn-lg" tabindex="2"></div>
    </div>
</form>
Si hay un $ _GET ['acción'] muestra el mensaje correcto.
<?php
if(isset($_GET['action'])){

    //check the action
    switch ($_GET['action']) {
        case 'active':
            echo "<h2 class='bg-success'>Your account is now active you may now log in.</h2>";
            break;
        case 'reset':
            echo "<h2 class='bg-success'>Please check your inbox for a reset link.</h2>";
            break;
    }
}
?>
Luego, procese el formulario y asegúrese de que el correo electrónico coincida con un usuario:
//email validation
if(!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
    $error[] = 'Please enter a valid email address';
} else {
    $stmt = $db->prepare('SELECT email FROM members WHERE email = :email');
    $stmt->execute(array(':email' => $_POST['email']));
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    if(empty($row['email'])){
        $error[] = 'Email provided is not on recognised.';
    }
        
}
Crea el token
//create the activation code
$token = md5(uniqid(rand(),true));
A continuación, actualice el registro de usuarios y establezca resetToken en el valor del token y resetComplete a No que será necesario si se hace clic en el enlace y se ha cambiado la contraseña. Envíe un correo electrónico al usuario que contenga un enlace que apunte a resetPassword.php? Key = $ token pasando el token.
$stmt = $db->prepare("UPDATE members SET resetToken = :token, resetComplete='No' WHERE email = :email");
$stmt->execute(array(
    ':email' => $row['email'],
    ':token' => $token
));

//send email
$to = $row['email'];
$subject = "Password Reset";
$body = "<p>Someone requested that the password be reset.</p>
<p>If this was a mistake, just ignore this email and nothing will happen.</p>
<p>To reset your password, visit the following address: <a href='".DIR."resetPassword.php?key=$token'>".DIR."resetPassword.php?key=$token</a></p>";

$mail = new Mail();
$mail->setFrom(SITEEMAIL);
$mail->addAddress($to);
$mail->subject($subject);
$mail->body($body);
$mail->send();

//redirect to index page
header('Location: login.php?action=reset');
exit;

resetPassword.php

Primero verifique que el token pasado a la página coincida con un usuario
$stmt = $db->prepare('SELECT resetToken, resetComplete FROM members WHERE resetToken = :token');
$stmt->execute(array(':token' => $_GET['key']));
$row = $stmt->fetch(PDO::FETCH_ASSOC);

//if no token from db then kill the page
if(empty($row['resetToken'])){
    $stop = 'Invalid token provided, please use the link provided in the reset email.';
} elseif($row['resetComplete'] == 'Yes') {
    $stop = 'Your password has already been changed!';
}
Si se ha configurado $ stop, muestre que
if(isset($stop)){
    echo "<p class='bg-danger'>$stop</p>";
}
Si no se han creado errores, muestre un formulario para cambiar la contraseña.
<form role="form" method="post" action="" autocomplete="off">
    <div class="row">
        <div class="col-xs-6 col-sm-6 col-md-6">
            <div class="form-group">
                <input type="password" name="password" id="password" class="form-control input-lg" placeholder="Password" tabindex="1">
            </div>
        </div>
        <div class="col-xs-6 col-sm-6 col-md-6">
            <div class="form-group">
                <input type="password" name="passwordConfirm" id="passwordConfirm" class="form-control input-lg" placeholder="Confirm Password" tabindex="1">
            </div>
        </div>
    </div>
    
    <hr>
    <div class="row">
        <div class="col-xs-6 col-md-6"><input type="submit" name="submit" value="Change Password" class="btn btn-primary btn-block btn-lg" tabindex="3"></div>
    </div>
</form>
Una vez que se ha enviado el formulario, valide los datos y luego seleccione la contraseña para actualizar la fila de usuarios y establezca resetComplete en Sí para indicar que el proceso ha finalizado si se hace clic nuevamente en el enlace de restablecimiento desde el correo electrónico, el proceso se detendrá.
//if form has been submitted process it
if(isset($_POST['submit'])){

    //basic validation
    if(strlen($_POST['password']) < 3){
        $error[] = 'Password is too short.';
    }

    if(strlen($_POST['passwordConfirm']) < 3){
        $error[] = 'Confirm password is too short.';
    }

    if($_POST['password'] != $_POST['passwordConfirm']){
        $error[] = 'Passwords do not match.';
    }

    //if no errors have been created carry on
    if(!isset($error)){

        //hash the password
        $hashedpassword = $user->password_hash($_POST['password'], PASSWORD_BCRYPT);

        try {

            $stmt = $db->prepare("UPDATE members SET password = :hashedpassword, resetComplete = 'Yes'  WHERE resetToken = :token");
            $stmt->execute(array(
                ':hashedpassword' => $hashedpassword,
                ':token' => $row['resetToken']
            ));

            //redirect to index page
            header('Location: login.php?action=resetAccount');
            exit;

        //else catch the exception and show the error.
        } catch(PDOException $e) {
            $error[] = $e->getMessage();
        }

    }

}

Conclusión

Eso cubre los fundamentos, esto puede usarse como un punto de partida para crear sitios basados ​​en miembros o incluso un comienzo para un panel de administración.

Instalar desde Descargar Github

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

outbrain

Páginas