Lag et login-system i php



Lag et login-system i php

av Ole Petter den 18. januar 2020

Sist oppdatert: 9 desember, 2020 kl 23:23

I dette innlegget kan du finne ut hvordan du kan lage ditt eget login-system i php.

I forrige innlegg om programmeringsspråket php viste jeg hvordan du kan konvertere databaseinnhold til json.

For å lage et login-system i php må man bruke en del innebygde funksjoner. En nyttig funksjon er password_hash() som krypterer passordet som lagres i databasen.

Les mer om denne funksjonen på siden til php: https://www.php.net/manual/en/function.password-hash.php

Først må man opprette en tabell som lagrer brukerinformasjon, inkludert passord. I dette eksempelet brukes phpmyadmin/ MySQL til å lagre data. Jeg oppretter databasen «login_system», og bruker den i dette eksempelet.

Contents

1 Lage tabellen «users»

For å finne ut mer om databaser, les mer på denne linken: https://progitek.no/category/programmering/mysql/

CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `email` varchar(255) NOT NULL,
  `username` varchar(255) NOT NULL,
  `password` varchar(255) NOT NULL
) 

2 Koble til databasen «login_system»

Først oppretter jeg en config-fil som kobler til databasen. Denne setter jeg inn i config-mappen i hovedmappen.

config.php

<?php 
// config.php
$link = mysqli_connect("localhost", "root", "", "login_system");

3 Lage frontend

For at brukere kan registrere en konto på siden, må det opprettes et skjema hvor brukere kan registrere seg. Det må også opprettes et skjema for innlogging etter at brukere har registrert seg.

Først oppretter jeg en hjemmeside kalt «index.php». Jeg inkluderer her «header.php» og «footer.php» som ikke er opprettet enda.

<?php include 'includes/views/header.php'; ?>

<h1>index.php</h1>

<?php include 'includes/views/footer.php'; ?>

Så oppretter jeg en mappe kalt «includes» i hovedmappen, og i denne mappen oppretter jeg en ny mappe kalt views. Denne mappen inneholder «header.php» og «footer.php».

header.php

<?php 
// header.php
ob_start();
session_start();
include "config/config.php";
?>

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <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">

    <title>Login_system</title>
  </head>
  <body>

footer.php

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></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>
    $(".toggleForms").click(function() {

        $("#login_form").toggle();
        $("#signup_form").toggle();

    });
    </script>
  </body>
</html>

Deretter lager jeg en login-side kalt «login.php» hvor brukere kan registrere seg og logge inn.

Men først oppretter jeg en klasse i «includes/classes/» kalt «Form.php». Denne filen inneholder skjemaene for å logge inn og registrere seg.

form.php

<?php 


class Form {

    public function login_form() { ?>

        <!--Logg inn-->
        <form action="includes/inc/login.inc.php" method="post" id="login_form">
            <h4>Innlogging</h4>
            <div class="md-form">
            <i class="fas fa-envelope prefix"></i>
            <input type="text" name="email" class="form-control">
            <label for="orangeForm-email">Din epost</label>
            </div>

            <div class="md-form">
            <i class="fas fa-lock prefix"></i>
            <input type="password" name="password" class="form-control">
            <label for="orangeForm-pass">Ditt passord</label>
            </div>

            <div class="text-center">
            <input class="btn btn-info btn-rounded mt-5" type="submit" name="submit" value="Logg inn">
            </div>
            <p class="text-center"><a class="btn btn-primary toggleForms">Registrering</a></p>
            
        </form>    
    
    <?php }


    public function register_form() { ?>

        <!--Register-->
        <form action="includes/inc/register.inc.php" method="post" id="signup_form">
            <h4>Registrering</h4>
            <div class="md-form">
            <i class="fas fa-envelope prefix"></i>
            <input type="text" name="email" id="orangeForm-email" class="form-control">
            <label for="orangeForm-email">Din epost</label>
            </div>

            <div class="md-form">
            <i class="fas fa-lock prefix"></i>
            <input type="password" name="password" id="orangeForm-pass" class="form-control">
            <label for="orangeForm-pass">Ditt passord</label>
            </div>

            <div class="text-center">
                <input class="btn btn-info btn-rounded mt-5" type="submit" name="submit" value="Registrer deg">
            </div>
            <p class="text-center"><a class="btn btn-primary toggleForms">Innlogging</a></p>

        </form>

    <?php }

}

Deretter må jeg importere denne klassen i filen «login.php» for å bruke den.

login.php

<?php
$page = 'login';
include 'config/config.php';
include 'includes/views/header.php';
include 'includes/classes/Form.php';

$form = new Form();
?>
<main>

  <div class="container">

                <div class="card card-body">
                  <!--Logg inn-->
                  <?php $form->login_form(); ?>

                  <!-- register --> 
                  <?php $form->register_form(); ?>
                </div>

  </div>
  <!-- container -->

</main>

<?php include 'includes/views/footer.php';

login.php frontend

Innloggingsside
login.php

Innloggingsskjemaet og registreringsskjemaet har en unik id hver som gjør at jeg viser kun et skjema av gangen. Det er med hjelp av jQuery mulig å «toggle» mellom disse to skjemaene.

4 Registrere brukere

For å registrere brukere må skjemaet behandles. For registrering oppretter jeg en ny mappe kalt «inc» som behandler forespørsler. Denne mappen ligger i «includes» mappen.

Først oppretter jeg en fil kalt «register.inc.php» som behandler registreringsforespørsler.

register.inc.php

<?php
/* inkluderer databasen */
require_once('../../config/config.php');

/* Sjekker om email og passord er fylt ut */
if (empty($_POST['email']) || empty($_POST['password']) ) {

    header("Location: ../../login.php?signup=empty");
    exit();

}

else {

    /* Lagrer brukernavn og passord som egne variabler */
    /*Use filter_var to remove special characters from the inputs*/
    $email = filter_var($_POST['email'], FILTER_SANITIZE_STRING);
    $password = filter_var($_POST['password'], FILTER_SANITIZE_STRING);

    $password = password_hash($password, PASSWORD_DEFAULT);

    try {

        /* Check that username does not already exist */
        $sql = "SELECT 1 FROM users WHERE email = '".$email."'";
        if ($result = mysqli_query($link, $sql)) 
        {
            if (mysqli_num_rows($result) >= 1) {

              header("Location: ../../login.php?signup=exists");
              exit();

            } else {
              /* Setter inn brukerinformasjon i databasen */
              $sql = "INSERT INTO users (email, password ) VALUES ('".$email."', '".$password."')";
               

              if (mysqli_query($link, $sql)) {

                header("Location: ../../login.php?signup=success");
                exit();

              } else { echo  "<br>Error: " . $sql . "<br>" . mysqli_error($link);  }

            }
        }
    }
    catch(Exception $e)
    {
        $message = 'Forespørsel mislyktes';
    }
}

?>

5 Logge inn brukere

login.inc.php

I samme mappe «includes/inc/» oppretter jeg filen «login.inc.php». Denne filen skal behandle innloggingsforespørsler fra eksisterende brukere.

<?php
require_once('../../config/config.php');
/* starter en sesjon for at brukere skal få en sesjons_id ved innlogging */
session_start();

/* Sjekker først om brukeren allerede er innlogget */
if (isset( $_SESSION['user_id'] ))
{
    header("Location: ../../index.php?user=loggedin");
    exit();
}
/* Sjekker om epost og passord er fylt ut */
if(empty($_POST['email']) || empty( $_POST['password']) ) {

    header("Location: ../../login.php?login=empty");
    exit();

} else {  
    
    /* Lagrer brukernavn og passord i variabler */
    $email = filter_var($_POST['email'], FILTER_SANITIZE_STRING);
    $password = filter_var($_POST['password'], FILTER_SANITIZE_STRING);

    /* Sjekker om det finnes brukere med samme epost i databasen */
    $sql = "SELECT * FROM users WHERE email = '$email'";
    $result = mysqli_query($link, $sql);

    $user_exist = mysqli_num_rows($result);

/* Hvis det ikke finnes bruker med denne epost, sendt beskjed */
    if ($user_exist < 1) {

        header("Location: ../../login.php?login=nouser");
        exit();

    } else {

        if ($row = mysqli_fetch_array($result)) {

/* Hvis det finnes en bruker med gjeldende epost: sjekk om det krypterte passordet i databasen stemmer overens med passordet som ble fylt ut i innloggingsskjemaet */
            $check_hash = password_verify($password, $row['password']);

/* Hvis passordet ikke stemmer overens -> send brukeren tilbake til innloggingssiden med feilmelding */
            if ($check_hash == false) {

                header("Location: ../../login.php?login=wrongpwd");
                exit();

/* Hvis passordet stemmer, logg inn brukeren */
            } elseif ($check_hash == true) {

/* Oppretter en sesjon for brukeren basert på brukerens id i databasen */
                $_SESSION['user_id'] = $row['id'];
                $_SESSION['timeout'] = time();

                header("Location: ../../index.php?login=success");
                exit();

            }

        }
        

    }
   

}

?>

6 Testing av innlogging

Først legger jeg til en ny side kalt «user.php» hvor brukere kan redigere sin informasjon og endre passord. Deretter legger jeg til et par lenker på «index.php».

user.php

<?php include 'includes/views/header.php'; ?>
<?php 
include 'includes/classes/Form.php';
$form = new Form();
?>

<div class="container">

    <?php 
    if (isset($_SESSION['user_id'])) {

        $user_id = $_SESSION['user_id'];
        

        $sql = "SELECT * FROM users WHERE id = $user_id";
        $result = mysqli_query($link, $sql);

        $row = mysqli_fetch_array($result);
        $email = $row['email'];
        $username = $row['username'];
        ?>
        <h1 class="mt-4 mb-4"><?php echo "Velkommen til user.php ". $email . " , du er logget inn!"; ?></h4>

        <a href="logout.inc.php" class="btn btn-info">Logg ut</a>

        <div class="card card-body">
            <?php $form->edit_user_form($email, $username, $user_id); ?>
        </div>

        <div class="card card-body mt-4">
            <?php $form->edit_password_form($user_id); ?>
        </div>

        <?php 
    } else {
        echo "Du må logge inn!"; ?>
        <a href="login.php" class="btn btn-info">Logg inn</a>
        <?php 
    }

    ?>

</div>
<!-- container --> 

<?php include 'includes/views/footer.php'; ?>

Oppdaterer Form.php

For å bruke metodene i «user.php» må jeg legge de til i Form.php. Nedenfor de to originale metodene, legger jeg til disse to nye metodene «edit_user_form()» og «edit_password_form()»:

Ved hjelp av disse to metodene kan man nå endre brukerinformasjon og oppdatere passord.

    public function edit_user_form($email, $username, $user_id) { ?>
    
        <form action="includes/inc/edit_user.inc.php" method="POST">
            <h3>Rediger brukerinformasjon</h3>

            <div class="form-group">
                <input type="text" name="email" value="<?php echo $email; ?>" class="form-control">
            </div>

            <div class="form-group">
                <label for="username">Ditt brukernavn</label>
                <input type="text" name="username" value="<?php echo $username; ?>" class="form-control">
            </div>

            <input type="hidden" name="user_id" value="<?php echo $user_id; ?>">

            <input type="submit" name="submit" value="Oppdater" class="btn btn-primary">

        </form>

    <?php }

    public function edit_password_form($user_id) { ?>
        <form action="includes/inc/edit_password.inc.php" method="POST">

            <h3>Rediger passord</h3>

            <label for="current_password"></label>
            <input type="password" name="current_password" class="form-control" placeholder="Skriv inn nåværende passord">

            <div class="form-group">
                <label for="password">Bytt passord (Hvis du vil beholde passord, la stå blank</label>
                <input type="password" name="password" placeholder="Skriv inn nytt passord" class="form-control"><br>
                <input type="password" name="password2" placeholder="Bekreft nytt passord" class="form-control">
            </div>

            <input type="hidden" name="user_id" value="<?php echo $user_id; ?>">

            <input type="submit" name="submit" value="Oppdater" class="btn btn-primary">

        </form>
    <?php } 

Oppdatert index.php

<?php include 'includes/views/header.php'; ?>

<?php 
/* Sjekker om en sesjon er startet */
if (isset($_SESSION['user_id'])) {
/* Hvis brukeren er logget inn -> vis link til user.php */
    echo "Velkommen, du er logget inn!"; ?>
    <a href="user.php" class="btn btn-info">Gå til min side</a>
    <?php
} else {
    echo "Du må logge inn!"; ?>
    <a href="login.php" class="btn btn-info">Logg inn</a>
    <?php 
}

?>

<?php include 'includes/views/footer.php'; ?>

Oppdaterer login.php

For å vise kun et skjema av gangen må litt CSS legges til for å skjule et av skjemaene. Jeg skjuler først innloggingsskjemaet ved hjelp av selectoren id: «#login_form» som er id-en til innloggingsskjemaet.

Oppdatert login.php

<?php
$page = 'login';
include 'config/config.php';
include 'includes/views/header.php';
include 'includes/classes/Form.php';

$form = new Form();
?>
<style>
#login_form {
  display: none;
}
</style>
<main>

  <div class="container">

    <div class="card card-body">
        <!--Logg inn-->
        <?php $form->login_form(); ?>

        <!-- register --> 
        <?php $form->register_form(); ?>
    </div>

  </div>
  <!-- container -->

</main>

<?php include 'includes/views/footer.php';
Registreringsside
Tester registrering

Registreringen var vellykket, og nå kan man logge inn på siden.

Bruker er registrert og kan logge inn

7 Legge til filene edit_password.inc.php og edit_user.inc.php

edit_password.inc.php

<?php

require_once('../../config/config.php');

session_start();

/* Check that username, and password are populated*/
if (empty($_POST['password']) ) {

    header("Location: ../../user.php?pwd=empty");
    exit();

}


else {

    /* Store username and pwds as variable */
    /*Use filter_var to remove special characters from the inputs*/
    $current_password = $_POST['current_password'];

    $password = mysqli_real_escape_string($link, $_POST['password']);
    $password2 = mysqli_real_escape_string($link, $_POST['password2']);

    if ($password != $password2) {
        header("Location: ../../user.php?pwd=not+matching");
        exit();
    }


    $user_id = mysqli_real_escape_string($link, $_POST['user_id']);


    $sql = "SELECT * FROM users WHERE `id` = $user_id";
    $result = mysqli_query($link, $sql);
    $row = mysqli_fetch_array($result);

    $hash = $row['password'];


    if (password_verify($current_password, $hash)) {
        $msg = 'Password+is+valid!';
    } else {
        header("Location: ../../user.php?pwd=wrong+current+password");
        exit();
    }

    $password = filter_var($_POST['password'], FILTER_SANITIZE_STRING);
    
    $password = password_hash($password, PASSWORD_DEFAULT);

    try {

        /* Prepare the sql insert statement */
        $sql = "UPDATE users 
                SET
                `password` = '$password'
                WHERE id = $user_id";

        if (mysqli_query($link, $sql)) {

            header("Location: ../../user.php?pwd=success&&hash=$msg");
            exit();

        } else { 
            echo  "<br>Error: " . $sql . "<br>" . mysqli_error($link);  
        }
    }
    catch(Exception $e)
    {
        $message = 'Unable to process request';
    }
}

?>

edit_user.inc.php

<?php 

if (isset($_POST['submit'])) {

    require_once('../../config/config.php');
    session_start();

    $user_id = mysqli_real_escape_string($link, $_POST['user_id']);
    $username = mysqli_real_escape_string($link, $_POST['username']);
    $email = mysqli_real_escape_string($link, $_POST['email']);

    $sql = "UPDATE users
            SET
            email = '$email',
            username = '$username'
            WHERE id = $user_id";

    if (mysqli_query($link, $sql)) {
        header("Location: ../../user.php?msg=success");
        exit();
    } else {
        header("Location: ../../user.php?msg=fail");
        exit();
    }
} else {
    exit();
}

8 Oppsummering

Hvis du har fulgt denne veiledningen har du klart å lage et fungerende login-system. Dette er nyttig for å begrense deler av nettsiden til innloggede brukere, og dette åpner nye muligheter.

Legg igjen en kommentar