Logowanie i rejestracja w PHP

System logowania i rejestracji to praktycznie najważniejszy element strony www. Już wcześniej pisałem na ten temat tutorial, ale postanowiłem go napisać od nowa, wraz z dodatkowymi funkcjami: wyświetlanie profilu, edycja profilu oraz lista użytkowników.

Na początek stworzymy sobie plik config.php. Będą się w nim znajdować dane do połączenia z bazą danych oraz niezbędne funkcje:

<?php
 
// definiujemy dane do połączenia z bazą danych
define('DBHOST', 'localhost');
define('DBUSER', 'root');
define('DBPASS', '');
define('DBNAME', 'baza');
 
function db_connect() {
    // połączenie z mysql
    mysql_connect(DBHOST, DBUSER, DBPASS) or die('<h2>ERROR</h2> MySQL Server is not responding');
 
    // wybór bazy danych
    mysql_select_db(DBNAME) or die('<h2>ERROR</h2> Cannot connect to specified database');
}
 
function db_close() {
    mysql_close();
}
 
function clear($text) {
    // jeśli serwer automatycznie dodaje slashe to je usuwamy
    if(get_magic_quotes_gpc()) {
        $text = stripslashes($text);
    }
    $text = trim($text); // usuwamy białe znaki na początku i na końcu
    $text = mysql_real_escape_string($text); // filtrujemy tekst aby zabezpieczyć się przed sql injection
    $text = htmlspecialchars($text); // dezaktywujemy kod html
    return $text;
}
 
function codepass($password) {
    // kodujemy hasło (losowe znaki można zmienić lub całkowicie usunąć
    return sha1(md5($password).'#!%Rgd64');
}
 
// funkcja na sprawdzanie czy user jest zalogowany, jeśli nie to wyświetlamy komunikat
function check_login() {
    if(!$_SESSION['logged']) {
        die('<p>To jest strefa tylko dla użytkowników.</p>
        <p>[<a href="login.php">Logowanie</a>] [<a href="register.php">Zarejestruj się</a>]</p>');
    }
}
 
// funkcja na pobranie danych usera
function get_user_data($user_id = -1) {
    // jeśli nie podamy id usera to podstawiamy id aktualnie zalogowanego
    if($user_id == -1) {
        $user_id = $_SESSION['user_id'];
    }
    $result = mysql_query("SELECT * FROM `users` WHERE `user_id` = '{$user_id}' LIMIT 1");
    if(mysql_num_rows($result) == 0) {
        return false;
    }
    return mysql_fetch_assoc($result);
}
 
// startujemy sesje
session_start();
 
// jeśli nie ma jeszcze sesji "logged" i "user_id" to wypełniamy je domyślnymi danymi
if(!isset($_SESSION['logged'])) {
    $_SESSION['logged'] = false;
    $_SESSION['user_id'] = -1;
}
?>

Gdy już mamy plik konfiguracyjny należy stworzyć tabelę w bazie danych.

CREATE TABLE `users` (
  `user_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) NOT NULL,
  `user_password` varchar(40) NOT NULL,
  `user_email` varchar(255) NOT NULL,
  `user_regdate` int(10) UNSIGNED NOT NULL,
  `user_from` varchar(255) NOT NULL,
  `user_website` varchar(255) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Zapytanie wklejamy do phpMyAdmin lub tworzymy sobie prosty skrypt, który wykona za nas tę czynność:

<?php
 
include 'config.php';
 
db_connect();
 
mysql_query("CREATE TABLE `users` (
  `user_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) NOT NULL,
  `user_password` varchar(40) NOT NULL,
  `user_email` varchar(255) NOT NULL,
  `user_regdate` int(10) unsigned NOT NULL,
  `user_from` varchar(255) NOT NULL,
  `user_website` varchar(255) NOT NULL,
  PRIMARY KEY (`user_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;");
 
db_close();
 
?>

Skrypt jest bardzo prosty i chyba nie potrzeba do niego komentarza :)

Pierwszym krokiem będzie stworzenie formularza do rejestracji i logowania. Na początek plik register.php:

<?php
include 'config.php';
db_connect();
 
// sprawdzamy czy user nie jest przypadkiem zalogowany
if(!$_SESSION['logged']) {
    // jeśli zostanie naciśnięty przycisk "Zarejestruj"
    if(isset($_POST['name'])) {
        // filtrujemy dane...
        $_POST['name'] = clear($_POST['name']);
        $_POST['password'] = clear($_POST['password']);
        $_POST['password2'] = clear($_POST['password2']);
        $_POST['email'] = clear($_POST['email']);
 
        // sprawdzamy czy wszystkie pola zostały wypełnione
        if(empty($_POST['name']) || empty($_POST['password']) || empty($_POST['password2']) || empty($_POST['email'])) {
            echo '<p>Musisz wypełnić wszystkie pola.</p>';
        // sprawdzamy czy podane dwa hasła są takie same
        } elseif($_POST['password'] != $_POST['password2']) {
            echo '<p>Podane hasła różnią się od siebie.</p>';
        // sprawdzamy poprawność emaila
        } elseif(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) === false) {
            echo '<p>Podany email jest nieprawidłowy.</p>';
        } else {
            // sprawdzamy czy są jacyś uzytkownicy z takim loginem lub adresem email
            $result = mysql_query("SELECT Count(user_id) FROM `users` WHERE `user_name` = '{$_POST['name']}' OR `user_email` = '{$_POST['email']}'");
            $row = mysql_fetch_row($result);
            if($row[0] > 0) {
                echo '<p>Już istnieje użytkownik z takim loginem lub adresem e-mail.</p>';
            } else {
                // jeśli nie istnieje to kodujemy haslo...
                $_POST['password'] = codepass($_POST['password']);
                // i wykonujemy zapytanie na dodanie usera
                mysql_query("INSERT INTO `users` (`user_name`, `user_password`, `user_email`, `user_regdate`) VALUES ('{$_POST['name']}', '{$_POST['password']}', '{$_POST['email']}', '".time()."')");
                echo '<p>Zostałeś poprawnie zarejestrowany! Możesz się teraz <a href="login.php">zalogować</a>.</p>';
            }
        }
    }
 
    // wyświetlamy formularz
    echo '<form method="post" action="register.php">
        <p>
            Login:<br>
            <input type="text" value="'.$_POST['name'].'" name="name">
        </p>
        <p>
            Hasło:<br>
            <input type="password" value="'.$_POST['password'].'" name="password">
        </p>
        <p>
            Powtórz hasło:<br>
            <input type="password" value="'.$_POST['password2'].'" name="password2">
        </p>
        <p>
            E-mail:<br>
            <input type="text" value="'.$_POST['email'].'" name="email">
        </p>
        <p>
            <input type="submit" value="Zarejestruj">
        </p>
    </form>';
} else {
    echo '<p>Jesteś już zalogowany, więc nie możesz stworzyć nowego konta.</p>
        <p>[<a href="index.php">Powrót</a>]</p>';
}
 
db_close();
?>

Następnie plik login.php:

<?php
include 'config.php';
db_connect();
 
// sprawdzamy czy user nie jest przypadkiem zalogowany
if(!$_SESSION['logged']) {
    // jeśli zostanie naciśnięty przycisk "Zaloguj"
    if(isset($_POST['name'])) {
        // filtrujemy dane...
        $_POST['name'] = clear($_POST['name']);
        $_POST['password'] = clear($_POST['password']);
        // i kodujemy hasło
        $_POST['password'] = codepass($_POST['password']);
 
        // sprawdzamy prostym zapytaniem sql czy podane dane są prawidłowe
        $result = mysql_query("SELECT `user_id` FROM `users` WHERE `user_name` = '{$_POST['name']}' AND `user_password` = '{$_POST['password']}' LIMIT 1");
        if(mysql_num_rows($result) > 0) {
            // jeśli tak to ustawiamy sesje "logged" na true oraz do sesji "user_id" wstawiamy id usera
            $row = mysql_fetch_assoc($result);
            $_SESSION['logged'] = true;
            $_SESSION['user_id'] = $row['user_id'];
            echo '<p>Zostałeś poprawnie zalogowany! Możesz teraz przejść na <a href="index.php">stronę główną</a>.</p>';
        } else {
            echo '<p>Podany login i/lub hasło jest nieprawidłowe.</p>';
        }
    }
 
    // wyświetlamy komunikat na zalogowanie się
    echo '<form method="post" action="login.php">
        <p>
            Login:<br>
            <input type="text" value="'.$_POST['name'].'" name="name">
        </p>
        <p>
            Hasło:<br>
            <input type="password" value="'.$_POST['password'].'" name="password">
        </p>
        <p>
            <input type="submit" value="Zaloguj">
        </p>
    </form>';
} else {
echo '<p>Jesteś już zalogowany, więc nie możesz się zalogować ponownie.</p>
        <p>[<a href="index.php">Powrót</a>]</p>';
}
 
db_close();
?>

Nieodłącznym elementem naszego skryptu musi być plik index.php który będzie sprawdzał czy user jest zalogowany. Jeśli nie to wyświetli linki do logowania lub rejestracji - w przeciwnym wypadku powita użytkownika oferując mu zobaczenie tajnej zawartości ;)

<?php
include 'config.php';
db_connect();
 
check_login();
 
// pobieramy dane usera
$user_data = get_user_data();
 
echo '<p>Witaj <b>'.$user_data['user_name'].'</b>!</p>
    <p>Jesteś w strefie tylko dla zalogowanych.</p>
    <p>[<a href="profile.php?id='.$user_data['user_id'].'">Wyświetl swój profil</a>] [<a href="editprofile.php">Edytuj profil</a>] [<a href="userlist.php">Lista użytkowników</a>] [<a href="logout.php">Wyloguj się</a>]</p>';
 
db_close();
?>

Jak widać w powyższym pliku zalogowany użytkownik ma dostęp do kilku opcji. Zaczniemy od wylogowania, ponieważ ten plik jest najkrótszy. logout.php:

<?php
session_start();
$_SESSION['logged'] = false;
$_SESSION['user_id'] = -1;
header('Location: index.php');
?>

Ustawiamy sesje "logged" na false i usuwamy id usera, po czym następuje przekierowanie na index.php.

Teraz czas na "dodatki" :) Na początek edycja profilu - editprofile.php:

<?php
include 'config.php';
db_connect();
 
check_login();
 
$user_data = get_user_data();
 
// jeśli zostanie naciśnięty przycisk "Edytuj profil"
if(isset($_POST['email'])) {
    // filtrujemy dane
    $_POST['website'] = clear($_POST['website']);
    $_POST['from'] = clear($_POST['from']);
    $_POST['new_password'] = clear($_POST['new_password']);
    $_POST['new_password2'] = clear($_POST['new_password2']);
    $_POST['password'] = clear($_POST['password']);
    $_POST['email'] = clear($_POST['email']);
 
    // zmienne tymczasowe na treść błędu
    $err = '';
    // i zapytanie sql
    $up2 = '';
 
    // jeśli zostanie podane nowe hasło lub inny email
    if(!empty($_POST['new_password']) || $_POST['email'] != $user_data['user_email']) {
        // sprawdzamy czy zostało podane aktualne hasło
        if(empty($_POST['password'])) {
            $err = '<p>Jeśli chcesz zmienić hasło lub adres email musisz podać aktualne hasło.</p>';
        // jeśli zostało podane to sprawdzamy czy jest poprawne
        } elseif(codepass($_POST['password']) != $user_data['user_password']) {
            $err = '<p>Podane aktualne hasło jest nieprawidłowe.</p>';
        } else {
            // jeśli wszystko jest ok...
 
            // sprawdzamy czy user chce zmienić hasło
            if(!empty($_POST['new_password'])) {
                // jeśli podane dwa hasła są różne to wyświetlamy błąd
                if($_POST['new_password'] != $_POST['new_password2']) {
                    $err = '<p>Podane hasła nie są takie same.</p>';
                // jeśli wszystko jest ok, dopisujemy do zmiennej tymczasowej zapytanie do zaktualizowania hasła
                } else {
                    $up2.= ", `user_password` = '".codepass($_POST['new_password'])."'";
                }
            }
            // sprawdzamy czy user chce zmienić email (czy ten podany jest różny od aktualnego)
            if($_POST['email'] != $user_data['user_email']) {
                // sprawdzamy czy podany email jest prawidłowy
                if(filter_var($_POST['email'], FILTER_VALIDATE_EMAIL) === false) {
                    $err = '<p>Podany email jest nieprawidłowy.</p>';
                } else {
                    // sprawdzamy czy istnieje taki email w bazie przy czym omijamy usera który jest zalogowany
                    $result = mysql_query("SELECT Count(user_id) FROM `users` WHERE `user_id` != '{$user_data['user_id']}' AND `user_email` = '{$_POST['email']}'");
                    $row = mysql_fetch_row($result);
                    if($row[0] > 0) {
                        $err = '<p>Już istnieje użytkownik z takim loginem lub adresem e-mail.</p>';
                    } else {
                        // jeśli wszystko jest ok to dopisujemy zapytanie do zaktualizowania emaila
                        $up2.= ", `user_email` = '{$_POST['email']}'";
                    }
                }
            }
        }
    }
 
    // jeśli są jakieś błędy z powyższych działań to je wyświetlamy
    if(!empty($err)) {
        echo $err;
    } else {
        // jeśli nie ma błędów to wykonujemy zapytanie dopisując te na aktualizacje hasła oraz emaila - $up2
        $result = mysql_query("UPDATE `users` SET `user_website` = '{$_POST['website']}', `user_from` = '{$_POST['from']}'{$up2} WHERE `user_id` = '{$user_data['user_id']}'");
        if($result) {
            // jeśli zapytanie się wykonało to wyświetlamy komunikat...
            echo '<p>Twój profil został poprawnie zaktualizowany.</p>';
            // i pobieramy od nowa dane usera aby w poniższym formularze się one zaktualizowały
            $user_data = get_user_data();
        } else {
            // jeśli zapytanie będzie błędne to wyświetlamy treść errora
            echo '<p>Niestety wystąpił błąd:<br>'.mysql_error().'</p>';
        }
    }
}
 
// wyświetlamy prosty formularz
echo '<form method="post" action="editprofile.php">
    <p>
        Login:<br>
        <input type="text" value="'.$user_data['user_name'].'" disabled="true">
    </p>
    <p>
        Strona WWW:<br>
        <input type="text" value="'.$user_data['user_website'].'" name="website">
    </p>
    <p>
        Skąd:<br>
        <input type="text" value="'.$user_data['user_from'].'" name="from">
    </p>
    <p>
        Nowe hasło (pozostaw puste jeśli nie chcesz zmieniać):<br>
        <input type="password" value="" name="new_password" autocomplete="off">
    </p>
    <p>
        Powtórz nowe hasło:<br>
        <input type="password" value="" name="new_password2" autocomplete="off">
    </p>
    <p>
        E-mail:<br>
        <input type="text" value="'.$user_data['user_email'].'" name="email">
    </p>
    <p>
        Aktualne hasło (wymagane przy zmianie emaila lub hasła):<br>
        <input type="password" value="" name="password" autocomplete="off">
    </p>
    <p>
        <input type="submit" value="Edytuj profil">
    </p>
</form>';
 
db_close();
?>

Wyświetlanie profilu - profile.php:

<?php
include 'config.php';
db_connect();
 
check_login();
 
// filtrujemy id oraz rzutujemy je na int
$_GET['id'] = (int)clear($_GET['id']);
 
// pobieramy dane usera z podanego id
$user_data = get_user_data($_GET['id']);
 
// sprawdzamy czy znalazło użytkownika
// jeśli nie to wyświetlamy komunikat
// a jeśli tak to wyświetlamy wszystkie jego dane
// jeśli user nie ma podanej strony www lub skąd jest to wyświetlamy "brak"
if($user_data === false) {
    echo '<p>Niestety, taki użytkownik nie istnieje.</p>
        <p>[<a href="index.php">Powrót</a>]</p>';
} else {
    echo '<h2>Profil użytkownika</h2>
        <p>Nick: <b>'.$user_data['user_name'].'</b></p>
        <p>Email: '.$user_data['user_email'].'</p>
        <p>Data rejestracji: '.date("d.m.Y, H:i", $user_data['user_regdate']).'</p>
        <p>Strona WWW: '.(empty($user_data['user_website']) ? 'brak' : $user_data['user_website']).'</p>
        <p>Skąd: '.(empty($user_data['user_from']) ? 'brak' : $user_data['user_from']).'</p>';
}
 
db_close();
?>

Oraz wyświetlanie listy wszystkich użytkowników - userlist.php. Został tu zastosowany mój skrypt na stronicowanie, który napisałem specjalnie na potrzeby tego artykułu (oraz dla sprawdzenia siebie). Tego kodu nie da się opisać słowami - każdy musi sam sobie przeanalizować ;)

<?php
include 'config.php';
db_connect();
 
check_login();
 
// wyświetlamy początek prostej tabelki
echo '<h2>Lista użytkowników</h2>
    <table border="1" width="500px">
        <tr>
            <th>Nick</th>
            <th>Email</th>
            <th>Data rejestracji</th>
        </tr>';
 
// sprawdzamy ilu jest wszystkich userów
$result = mysql_query("SELECT Count(user_id) FROM `users`");
$row = mysql_fetch_row($result);
$count_users = $row[0];
 
// ustawiamy ile ma być wyników na 1 strone
$per_page = 10;
 
// obliczamy ilość stron
$pages = ceil($count_users / $per_page);
 
// aktualna strona - jeśli nie została podana to = 1
// jeśli została podana to filtrujemy ją i rzutujemy na int
$current_page = !isset($_GET['page']) ? 1 : (int)clear($_GET['page']);
 
// jeśli ktoś poda stronę mniejszą niż 1 lub większą niż ilość stron to zmieniamy ją na 1
if($current_page < 1 || $current_page > $pages) {
    $current_page = 1;
}
 
// jeśli jest chociaż 1 user to wyświetlamy
if($count_users > 0) {
    $result = mysql_query("SELECT * FROM `users` ORDER BY `user_id` ASC LIMIT ".($per_page*($current_page-1)).", ".$per_page);
    while($row = mysql_fetch_assoc($result)) {
        echo '<tr>
            <td><a href="profile.php?id='.$row['user_id'].'">'.$row['user_name'].'</a></td>
            <td>'.$row['user_email'].'</td>
            <td>'.date("d.m.Y, H:i", $row['user_regdate']).'</td>
        </tr>';
    }
} else {
    // jeśli nie ma w ogóle to wyświetlamy komunikat
    echo '<tr>
        <td colspan="3" style="text-align:center">Niestety nie znaleziono żadnych użytkowników.</td>
    </tr>';
}
echo '</table>';
 
// wyświetlamy stronicowanie
if($pages > 0) { 
    echo '<p>';
    if($pages < 11) {
        for($i = 1; $i <= $pages; $i++) {
            if($i == $current_page) {
                echo '<b>['.$current_page.']</b> ';
            } else {
                echo '<a href="userlist.php?page='.$i.'">['.$i.']</a> ';
            }
        }
    } elseif($current_page > 10) {
        echo '<a href="userlist.php?page=1">[1]</a> ';
        echo '<a href="userlist.php?page=2">[2]</a> ';
        echo '[...] ';
        for($i = ($current_page-3); $i <= $current_page; $i++) {
            if($i == $current_page) {
                echo '<b>['.$current_page.']</b> ';
            } else {
                echo '<a href="userlist.php?page='.$i.'">['.$i.']</a> ';
            }
        }
        for($i = ($current_page+1); $i <= ($current_page+3); $i++) {
            if($i > ($pages)) break;
            if($i == $current_page) {
                echo '<b>['.$current_page.']</b> ';
            } else {
                echo '<a href="userlist.php?page='.$i.'">['.$i.']</a> ';
            }
        }
        if($current_page < ($pages-4)) {
            echo '[...] ';
            echo '<a href="userlist.php?page='.($pages-1).'">['.($pages-1).']</a> ';
            echo '<a href="userlist.php?page='.$pages.'">['.$pages.']</a> ';
        } elseif($current_page == ($pages-4)) {
            echo '[...] ';
            echo '<a href="userlist.php?page='.$pages.'">['.$pages.']</a> ';
        }
    } else {
        for($i = 1; $i <= 11; $i++) {
            if($i == $current_page) {
                if($i > ($pages)) break;
                echo '<b>['.$current_page.']</b> ';
            } else {
                echo '<a href="userlist.php?page='.$i.'">['.$i.']</a> ';
            }
        }
        if($pages > 12) {
            echo '[...] ';
            echo '<a href="userlist.php?page='.($pages-1).'">['.($pages-1).']</a> ';
            echo '<a href="userlist.php?page='.$pages.'">['.$pages.']</a> ';
        } elseif($pages == 12) {
            echo '[...] ';
            echo '<a href="userlist.php?page=12">[12]</a> ';
        }
    }
    echo '</p>';
}
 
db_close();
?>

No i to by było na tyle.

O czym należy pamiętać:

Aby pobrać wszystko zapraszam tutaj.