Post Top Ad

Your Ad Spot

jueves, 7 de mayo de 2020

Registro de usuarios y verificación de correo electrónico PHP y MySQL

Ya escribí una publicación de blog sobre la creación de un sistema completo de registro e inicio de sesión de usuario utilizando PHP y MySQL, pero no incluí la verificación por correo electrónico.
Este tutorial es un poco como una actualización del tutorial anterior. Además de poder registrarse, iniciar sesión y cerrar sesión en su cuenta, a un usuario también se le enviará un correo electrónico de verificación a su dirección de correo electrónico con un enlace donde puede hacer clic y verificar su dirección de correo electrónico.
En la mayoría de las aplicaciones que va a compilar, es importante agregar una función de verificación de correo electrónico por muchas razones: es posible que desee enviar un correo electrónico más adelante al usuario y asegurarse de que lo vea; o el usuario puede olvidar su contraseña y necesitar restablecerla, y para hacer esto, necesitaremos enviarles un enlace de restablecimiento de contraseña; hay muchas otras razones pero entiendes el punto.
En este sistema que estamos construyendo hoy, los usuarios que no hayan verificado su correo electrónico no podrán realizar ciertas acciones (solo usaré una demostración simple como ver un botón. Solo los usuarios verificados podrán ver ese botón).
Para comenzar, cree un nuevo proyecto PHP llamado verificado-usuario y en esta carpeta, cree dos archivos: signup.php y login.php .
signup.php :
<!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">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
  <link rel="stylesheet" href="main.css">
  <title>User verification system PHP</title>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-4 offset-md-4 form-wrapper auth">
        <h3 class="text-center form-title">Register</h3>
        <form action="signup.php" method="post">
          <div class="form-group">
            <label>Username</label>
            <input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
          </div>
          <div class="form-group">
            <label>Email</label>
            <input type="text" name="email" class="form-control form-control-lg" value="<?php echo $email; ?>">
          </div>
          <div class="form-group">
            <label>Password</label>
            <input type="password" name="password" class="form-control form-control-lg">
          </div>
          <div class="form-group">
            <label>Password Confirm</label>
            <input type="password" name="passwordConf" class="form-control form-control-lg">
          </div>
          <div class="form-group">
            <button type="submit" name="signup-btn" class="btn btn-lg btn-block">Sign Up</button>
          </div>
        </form>
        <p>Already have an account? <a href="login.php">Login</a></p>
      </div>
    </div>
  </div>
</body>
</html>
Es solo un simple archivo HTML / CSS. Lo único que vale la pena señalar es que estamos utilizando el marco CSS Bootstrap 4 para diseñar nuestra página. Puede usar cualquier otro marco de estilo que elija o escribir su propio CSS si lo desea.
Inmediatamente después del CSS de Bootstrap, estamos incluyendo un archivo main.css para un estilo personalizado. Vamos a crear ese archivo ahora. En la carpeta raíz de la aplicación, cree un archivo llamado main.css .
main.css :
@import url('https://fonts.googleapis.com/css?family=Lora');
li { list-style-type: none; }
.form-wrapper {
  margin: 50px auto 50px;
  font-family: 'Lora', serif;
  font-size: 1.09em;
}
.form-wrapper.login { margin-top: 120px; }
.form-wrapper p { font-size: .8em; text-align: center; }
.form-control:focus { box-shadow: none; }
.form-wrapper {
  border: 1px solid #80CED7;
  border-radius: 5px;
  padding: 25px 15px 0px 15px;
}
.form-wrapper.auth .form-title { color: #007EA7; }
.home-wrapper button,
.form-wrapper.auth button {
  background: #007EA7;
  color: white;
}
.home-wrapper {
  margin-top: 150px;
  border-radius: 5px;
  padding: 10px;
  border: 1px solid #80CED7;
}
En la primera línea de este archivo estamos importando y usando algunas fuentes de Google para que nuestras fuentes se vean más hermosas.
Ahora ve al archivo login.php y haz algo similar.
login.php :
<!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">
  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
  <link rel="stylesheet" href="main.css">
  <title>User verification system PHP - Login</title>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-4 offset-md-4 form-wrapper auth login">
        <h3 class="text-center form-title">Login</h3>
        <form action="login.php" method="post">
          <div class="form-group">
            <label>Username or Email</label>
            <input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
          </div>
          <div class="form-group">
            <label>Password</label>
            <input type="password" name="password" class="form-control form-control-lg">
          </div>
          <div class="form-group">
            <button type="submit" name="login-btn" class="btn btn-lg btn-block">Login</button>
          </div>
        </form>
        <p>Don't yet have an account? <a href="signup.php">Sign up</a></p>
      </div>
    </div>
  </div>
</body>
</html>
En su navegador, vaya a http: //localhost/cwa/verify-user/signup.php, verá un hermoso formulario de registro (lo mismo para iniciar sesión). Ignore los errores en los campos de entrada, lo arreglaremos pronto.http : // localhost cwa verificar usuario registro php verá un hermoso formulario de registro (lo mismo para iniciar sesión). Ignore los errores en los campos de entrada, lo arreglaremos pronto.
Por ahora, configuremos la base de datos. Cree una base de datos llamada verificado-usuario  y en esta base de datos, cree una tabla de usuarios con los siguientes atributos:
CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `username` varchar(100) NOT NULL,
 `email` varchar(100) NOT NULL,
 `verified` tinyint(1) NOT NULL DEFAULT '0',
 `token` varchar(255) DEFAULT NULL,
 `password` varchar(255) NOT NULL,
 PRIMARY KEY (`id`)
)
Nada inusual excepto, tal vez, el token y los  campos verificados , que explicaré en un momento.
Ahora comenzamos con la lógica de registro real. Por lo general, me gusta referirme a la parte lógica de mi aplicación como los controladores y eso es lo que haré aquí. En la carpeta raíz del proyecto, cree una carpeta llamada controladores y dentro de los controladores, cree un archivo llamado authController.php .
controladores / authController.php :
<?php
session_start();
$username = "";
$email = "";
$errors = [];

$conn = new mysqli('localhost', 'root', '', 'verify-user');

// SIGN UP USER
if (isset($_POST['signup-btn'])) {
    if (empty($_POST['username'])) {
        $errors['username'] = 'Username required';
    }
    if (empty($_POST['email'])) {
        $errors['email'] = 'Email required';
    }
    if (empty($_POST['password'])) {
        $errors['password'] = 'Password required';
    }
    if (isset($_POST['password']) && $_POST['password'] !== $_POST['passwordConf']) {
        $errors['passwordConf'] = 'The two passwords do not match';
    }

    $username = $_POST['username'];
    $email = $_POST['email'];
    $token = bin2hex(random_bytes(50)); // generate unique token
    $password = password_hash($_POST['password'], PASSWORD_DEFAULT); //encrypt password

    // Check if email already exists
    $sql = "SELECT * FROM users WHERE email='$email' LIMIT 1";
    $result = mysqli_query($conn, $sql);
    if (mysqli_num_rows($result) > 0) {
        $errors['email'] = "Email already exists";
    }

    if (count($errors) === 0) {
        $query = "INSERT INTO users SET username=?, email=?, token=?, password=?";
        $stmt = $conn->prepare($query);
        $stmt->bind_param('ssss', $username, $email, $token, $password);
        $result = $stmt->execute();

        if ($result) {
            $user_id = $stmt->insert_id;
            $stmt->close();

            // TO DO: send verification email to user
            // sendVerificationEmail($email, $token);

            $_SESSION['id'] = $user_id;
            $_SESSION['username'] = $username;
            $_SESSION['email'] = $email;
            $_SESSION['verified'] = false;
            $_SESSION['message'] = 'You are logged in!';
            $_SESSION['type'] = 'alert-success';
            header('location: index.php');
        } else {
            $_SESSION['error_msg'] = "Database error: Could not register user";
        }
    }
}

// LOGIN
if (isset($_POST['login-btn'])) {
    if (empty($_POST['username'])) {
        $errors['username'] = 'Username or email required';
    }
    if (empty($_POST['password'])) {
        $errors['password'] = 'Password required';
    }
    $username = $_POST['username'];
    $password = $_POST['password'];

    if (count($errors) === 0) {
        $query = "SELECT * FROM users WHERE username=? OR email=? LIMIT 1";
        $stmt = $conn->prepare($query);
        $stmt->bind_param('ss', $username, $password);

        if ($stmt->execute()) {
            $result = $stmt->get_result();
            $user = $result->fetch_assoc();
            if (password_verify($password, $user['password'])) { // if password matches
                $stmt->close();

                $_SESSION['id'] = $user['id'];
                $_SESSION['username'] = $user['username'];
                $_SESSION['email'] = $user['email'];
                $_SESSION['verified'] = $user['verified'];
                $_SESSION['message'] = 'You are logged in!';
                $_SESSION['type'] = 'alert-success';
                header('location: index.php');
                exit(0);
            } else { // if password does not match
                $errors['login_fail'] = "Wrong username / password";
            }
        } else {
            $_SESSION['message'] = "Database error. Login failed!";
            $_SESSION['type'] = "alert-danger";
        }
    }
}
Si ha seguido mis tutoriales anteriores, entonces nada en este archivo debería ser nuevo para usted. Pero por el bien de los novatos, voy a hacer algunas explicaciones.
Lo primero es que estamos comenzando la sesión usando session_start () ya que necesitaremos almacenar la información de usuario registrada en la sesión. Después de comenzar la sesión, estamos inicializando las variables $ username y $ email que estamos usando en nuestros formularios, y también la matriz $ errors que contendrá nuestros errores de validación de formularios.
A continuación, nos conectamos a la base de datos. Las siguientes dos si las declaraciones que siguen son, respectivamente, el código que se ejecuta cuando el usuario hace clic en el registro o los botones de inicio de sesión. En el caso de la suscripción, verificamos que todos los campos obligatorios se hayan completado correctamente y solo entonces procedemos a guardar al usuario en la base de datos. También estamos generando un token  (una cadena única y aleatoria) y guardándolo con el usuario como un atributo. Esto se usará para verificar el correo electrónico del usuario. Más sobre esto más tarde.
Dado que nuestro archivo authController.php es responsable del registro y el inicio de sesión, tenemos que incluirlo en la parte superior de las páginas signup.php y login.php porque allí es donde se envían los datos del formulario. Al igual que:
signup.php y login.php  (en la parte superior):
<?php include 'controllers/authController.php' ?>
Si hay mensajes de error en la matriz $ errors , debemos mostrarlos en el formulario. Para hacerlo, agregue esta declaración if dentro de su formulario directamente debajo del título del formulario para las páginas de registro e inicio de sesión. 
<!-- form title -->
<h3 class="text-center form-title">Register</h3> <!-- or Login -->

<?php if (count($errors) > 0): ?>
  <div class="alert alert-danger">
    <?php foreach ($errors as $error): ?>
    <li>
      <?php echo $error; ?>
    </li>
    <?php endforeach;?>
  </div>
<?php endif;?>
Si no hay errores, nuestro script procederá a guardar al usuario en la base de datos. Después de guardar al usuario en la base de datos, lo registramos de inmediato. En nuestro caso, iniciar sesión en un usuario significa almacenar sus datos en la sesión y eso es lo que acabamos de hacer.
En este punto, ya puede registrarse e incluso iniciar sesión en un usuario. Pero después de iniciar sesión, será redirigido a la página index.php que no existe. Lo crearemos pronto. 
En authController.php , estamos almacenando las  variables de mensaje  y tipo en la sesión para que se muestren tan pronto como el usuario haya iniciado sesión. Mensaje es el texto real del mensaje mientras que el tipo es la clase de estilo Bootstrap que formateará el mensaje con el mensaje apropiado colores según el valor del tipo .
Este mensaje se muestra después de que el usuario ha iniciado sesión y se muestra en el archivo index.php. Creemos ese archivo ahora en la carpeta raíz de nuestro proyecto.
index.php :
<?php include 'controllers/authController.php'?>
<?php
// redirect user to login page if they're not logged in
if (empty($_SESSION['id'])) {
    header('location: login.php');
}
?>
<!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">

  <!-- Bootstrap CSS -->
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
  <link rel="stylesheet" href="main.css">
  <title>User verification system PHP</title>
</head>

<body>
  <div class="container">
    <div class="row">
      <div class="col-md-4 offset-md-4 home-wrapper">

        <!-- Display messages -->
        <?php if (isset($_SESSION['message'])): ?>
        <div class="alert <?php echo $_SESSION['type'] ?>">
          <?php
            echo $_SESSION['message'];
            unset($_SESSION['message']);
            unset($_SESSION['type']);
          ?>
        </div>
        <?php endif;?>

        <h4>Welcome, <?php echo $_SESSION['username']; ?></h4>
        <a href="logout.php" style="color: red">Logout</a>
        <?php if (!$_SESSION['verified']): ?>
          <div class="alert alert-warning alert-dismissible fade show" role="alert">
            You need to verify your email address!
            Sign into your email account and click
            on the verification link we just emailed you
            at
            <strong><?php echo $_SESSION['email']; ?></strong>
          </div>
        <?php else: ?>
          <button class="btn btn-lg btn-primary btn-block">I'm verified!!!</button>
        <?php endif;?>
      </div>
    </div>
  </div>
</body>
</html>
Esta página debe ser accesible solo para usuarios registrados. Es por eso que en la sección superior del archivo, estamos redirigiendo al usuario a la página de inicio de sesión si no está conectado. En algún lugar en el centro de la página, estamos mostrando el mensaje. Después de mostrar el mensaje, deseleccionamos el mensaje y escribimos variables porque no queremos que permanezca allí en la página incluso después de que el usuario actualice la página.
Por último, en el centro de la página, realizamos una verificación para ver si el usuario conectado ha verificado su dirección de correo electrónico o no. Recuerde que agregamos la  variable verificada en la sesión cuando iniciamos la sesión del usuario. Si el usuario ha sido verificado, mostramos el mensaje "¡Estoy verificado!" botón para que lo vean. Si no se verifican, les informamos sobre el enlace de verificación que enviamos a su dirección de correo electrónico y les pedimos que hagan clic en ese enlace para verificar su correo electrónico.

Verificar correo electrónico

En el archivo authController.php, utilizamos un comentario para indicar dónde enviaríamos el correo electrónico de verificación al usuario llamando a sendVerificationEmail () . Vaya al archivo authController.php y descomente la llamada a la función de esta manera:
// TO DO: send verification email to user
sendVerificationEmail($email, $token);
Definiremos esta función en otro archivo e incluiremos ese archivo dentro de authController.php. Dentro de la carpeta de controladores , cree un archivo llamado sendEmails.php .
Antes de agregar cualquier código en este archivo, permítanme decir un poco sobre PHP SwiftMailer, la biblioteca popular para enviar correos electrónicos en PHP que vamos a usar en este proyecto para enviar correos electrónicos desde localhost. 
SwiftMailer es una biblioteca popular con muchas funciones para enviar correos electrónicos en aplicaciones PHP. 
Para usar Swiftmailer, primero debe instalar Composer . Una vez que haya instalado Composer, abra su terminal o línea de comando y navegue a la carpeta raíz del proyecto y ejecute el siguiente comando para agregar la biblioteca Swift Mailer con todos sus archivos a nuestro proyecto:
composer require "swiftmailer/swiftmailer:^6.0"
Esto crea una carpeta de proveedor en la raíz de nuestra aplicación que contiene todos los códigos (clases) necesarios para enviar un correo electrónico y también crea un archivo composer.json en la raíz de la aplicación que se ve así:
{
    "require": {
        "swiftmailer/swiftmailer": "^6.0"
    }
}
Ahora abra el archivo sendEmails.php que creamos anteriormente y escriba la función sendVerificationEmail () :
<?php
require_once './vendor/autoload.php';

// Create the Transport
$transport = (new Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl'))
    ->setUsername(SENDER_EMAIL)
    ->setPassword(SENDER_PASSWORD);

// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);

function sendVerificationEmail($userEmail, $token)
{
    global $mailer;
    $body = '<!DOCTYPE html>
    <html lang="en">

    <head>
      <meta charset="UTF-8">
      <title>Test mail</title>
      <style>
        .wrapper {
          padding: 20px;
          color: #444;
          font-size: 1.3em;
        }
        a {
          background: #592f80;
          text-decoration: none;
          padding: 8px 15px;
          border-radius: 5px;
          color: #fff;
        }
      </style>
    </head>

    <body>
      <div class="wrapper">
        <p>Thank you for signing up on our site. Please click on the link below to verify your account:.</p>
        <a href="http://localhost/cwa/verify-user/verify_email.php?token=' . $token . '">Verify Email!</a>
      </div>
    </body>

    </html>';

    // Create a message
    $message = (new Swift_Message('Verify your email'))
        ->setFrom(SENDER_EMAIL)
        ->setTo($userEmail)
        ->setBody($body, 'text/html');

    // Send the message
    $result = $mailer->send($message);

    if ($result > 0) {
        return true;
    } else {
        return false;
    }
}
La primera declaración requiere el archivo autoload.php en este archivo. Este archivo autoload.php incluirá automáticamente todas las clases de la biblioteca Swift Mailer en la carpeta del proveedor que usamos en este archivo. 
Estamos usando Gmail en este ejemplo. Por lo tanto, puede reemplazar SENDER_EMAIL y SENDER_PASSWORD con su dirección de Gmail y contraseña que desea usar como dirección de correo electrónico del remitente. (La dirección de correo electrónico del destinatario es la que se envía a través del formulario).
Normalmente, para enviar un correo electrónico a alguien, debe iniciar sesión en su cuenta de Gmail antes de redactar el correo y enviarlo. Es lo mismo que hace la biblioteca Swift Mailer. Entonces, cuando el receptor ( $ userEmail ) recibe el correo electrónico, es su dirección de Gmail (SENDER_EMAIL) que verá como el correo electrónico de envío.
Ahora estamos llamando a la función sendVerificationEmail () en nuestro archivo authController.php pero definimos la función dentro del archivo sendEmails.php . Incluyamos el archivo sendEmails.php dentro de nuestro authController.php para que esta función esté disponible en el archivo. En la parte superior de authController.php , justo antes de session_start (), agregue la siguiente línea:
require_once 'sendEmails.php';
Eso es todo lo que necesitamos, caballeros (y damas) para enviar un correo electrónico a nuestro usuario con un enlace de verificación de correo electrónico. Pero estamos trabajando en localhost y Gmail bloqueará cualquier intento de inicio de sesión de Swift Mailer que se ejecute en localhost. 

Envío de correo electrónico desde localhost

Si desea que esto se ejecute en localhost, deberá configurar su cuenta de Gmail para aceptar el inicio de sesión desde aplicaciones menos seguras. Por supuesto, esto puede presentar cierta vulnerabilidad en su cuenta de Gmail, pero puede hacerlo solo por el corto tiempo que necesita para probar esta aplicación en localhost. Después de la prueba, puede deshacer la configuración en su cuenta de Gmail. Una vez que su aplicación haya sido alojada en Internet, trabajará. Solo estamos haciendo esto porque estamos en localhost.
Puede ser aún más cauteloso y crear otra cuenta de Gmail solo para fines como estos.
Así que inicie sesión en su Gmail en su navegador, vaya a https://myaccount.google.com/security#connectedapps y cambie el valor 'Permitir aplicaciones menos seguras' a ON. https : // myaccount google com security connectedapps y cambie el valor 'Permitir aplicaciones menos seguras' a ON. 
Puede desactivar esto una vez que haya terminado de probar el proyecto en localhost.
Con esto, podrá enviar un correo electrónico desde localhost con un enlace de verificación una vez que el usuario se registre. Ahora mire nuevamente el método sendVerificationEmail () y notará que en el cuerpo del correo electrónico que enviamos al usuario, el token que generamos para ese usuario en particular (el token es único) se ha establecido como un parámetro en el enlace de modo que cuando el usuario haga clic en el enlace del correo electrónico, se lo dirigirá a nuestra aplicación en una página llamada  generate_email.php  con ese token en la URL. Me gusta esto:
<a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
Para que podamos obtener este token en nuestro generate_email.php de esta manera (cálmate, crearemos este Verified_email.php pronto): 
$token = $_GET['token'];
Ahora podemos usar este token para buscar el usuario que tiene este token en particular (recuerde que el token es único) y si obtenemos ese usuario, actualizamos su registro cambiando el atributo verificado a verdadero en la base de datos. Luego, podemos decir con orgullo que hemos verificado la dirección de correo electrónico de ese usuario.
Creemos este archivo verificado_email.php en la carpeta raíz de nuestro proyecto:
verificar_email.php :
<?php
session_start();

$conn = new mysqli('localhost', 'root', '', 'verify-user');

if (isset($_GET['token'])) {
    $token = $_GET['token'];
    $sql = "SELECT * FROM users WHERE token='$token' LIMIT 1";
    $result = mysqli_query($conn, $sql);

    if (mysqli_num_rows($result) > 0) {
        $user = mysqli_fetch_assoc($result);
        $query = "UPDATE users SET verified=1 WHERE token='$token'";

        if (mysqli_query($conn, $query)) {
            $_SESSION['id'] = $user['id'];
            $_SESSION['username'] = $user['username'];
            $_SESSION['email'] = $user['email'];
            $_SESSION['verified'] = true;
            $_SESSION['message'] = "Your email address has been verified successfully";
            $_SESSION['type'] = 'alert-success';
            header('location: index.php');
            exit(0);
        }
    } else {
        echo "User not found!";
    }
} else {
    echo "No token provided!";
}
Tenga en cuenta que establecer el valor del valor  verificado  en 1 es lo mismo que establecerlo en verdadero, ya que en la base de datos MySQL, el tipo Boolean se interpreta como tinyint. 
Ahora, cuando el usuario hace clic en el enlace de su correo electrónico y lo lleva a esta página, actualiza el estado verificado de ese usuario a verdadero, lo registra y lo redirige a la página index.php. En la página de índice, después de verificar al usuario, notará que el mensaje de advertencia que le aconseja al usuario que verifique su dirección de correo electrónico ya no está y en su lugar tenemos el mensaje "¡Estoy verificado!" botón que solo es visible para usuarios verificados.
Una última cosa, en la página index.php después de iniciar sesión en el usuario, hay un enlace de cierre de sesión que apunta a un archivo logout.php que se supone que cierra la sesión del usuario. Vamos a crear ese archivo en la raíz de nuestra aplicación:
logout.php :
<?php
session_destroy();
unset($_SESSION['id']);
unset($_SESSION['username']);
unset($_SESSION['email']);
unset($_SESSION['verify']);
header("location: login.php");
Entonces, además de poder registrarse, verificar el correo electrónico, iniciar sesión, el usuario ahora también puede cerrar sesión.

Conclusión

Eso es todo con el registro de usuarios y la verificación por correo electrónico. Si tiene algún comentario, pregunta o palabras de aliento, déjelos en el comentario a continuación. Y por favor, recuerde compartir esta publicación o recomendar este sitio a sus amigos si lo encuentra útil. ¡Me anima mucho! 
¡Que tengas un gran día!

No hay comentarios.:

Publicar un comentario

Dejanos tu comentario para seguir mejorando!

outbrain

Páginas