Login mit Hilfe von PHP und mySQL
Dieses Tutorial soll die Grundzüge eines Login-Systems auf der Basis von PHP und mySQL unter Zuhilfenahme von Sessions klären.
2003-07-27 13:02:20 2003-07-27 13:02:20 razorblade
Login mit Hilfe von PHP und mySQL
Dieses Tutorial soll die Grundzüge eines Login-Systems auf der Basis von PHP und mySQL unter Zuhilfenahme von Sessions klären.
Keinesfalls findet sich hier ein vollständiges und bis ins kleinste Detail ausgefeilte Benutzermanagement, weder mit noch ohne expliziter Rechtevergabe.
Ebenfalls erhebt dieses Tutorial nicht den Anspruch die ultimative Lösung zu sein, aber es ist eine einfache, leicht verständliche und recht flexible, da leicht erweiterbare Variante.
Inhaltsverzeichnis
Sinn und Zweck eines Login-Systems
Der Sinn und Zweck einer Benutzerverwaltung sollte wohl jedem klar sein. Grob gesagt sprechen folgende Gründe dafür:
Der Webmaster kann
-
entscheiden, wer wann welche Teile der Seite zu sehen bekommt (inkl. Downloads)
-
nachvollziehen, welcher Benutzer wann wo war
-
nachvollziehen, wer wann was gemacht hat
-
Benutzer, die sich etwas zu Schulden kommen ließen, sperren
-
ganz allgemein gesagt entscheiden, dass Herr X bestimmte Aktionen machen darf, Herr Y andere und Herr Z nur ein paar der Aktionen die Herr X machen darf
Gründe für PHP und mySQL
Gründe für PHP
Der Login (als ein Bauteil einer Benutzerverwaltung) muss auf dem Server ablaufen, auf dem die Seiten gespeichert sind. Das impliziert die Voraussetzung, dass eine Möglichkeit gegeben sein muss, auf dem Server Benutzereingaben auszuwerten und entsprechend darauf zu reagieren.
PHP ist eine kostenlose Skriptsprache, die von vielen Webhostern zur Verfügung gestellt wird und serverseitige Aktionen erlaubt. Die Syntax ist an C angelehnt, jeder, der damit schon Erfahrung hat, wird sich sofort zu Recht finden, jeder andere wird es schnell lernen. An dieser Stelle sei kurz auf http://www.php.net verwiesen und dort insbesondere auf das Handbuch (neudeutsch Manual)
Gründe für mySQL
Die Daten für den Login, gegen die die Eingaben des Benutzers zum Einloggen abgeprüft werden, müssen natürlich auch gespeichert werden. Hierzu gibt es (wie so oft) mehrere Möglichkeiten:
-
Speichern im Skript
-
Am einfachsten zu realisieren, aber wehe, es kommen Benutzer hinzu oder es sollen Passwörter geändert werden.
-
Ganz zu schweigen von den oben erwähnten Funktionen
-
-
Speichern in Textdateien
-
Schon besser, aber auch unkomfortabel
-
Entweder für jeden Benutzer eine eigene Datei, oder eine Datei für alle auf jeden Fall schwierig zu erweitern
-
nur sequentieller Zugriff, daher langsam
-
-
Speichern in einer Datenbank
-
einfacher Zugriff
-
wahlfreier Zugriff
-
leicht erweiterbar
-
übersichtlich
-
Die Tabelle
Theoretisch kann der Webmaster auswählen, ob er die Daten aller Benutzer in
einer Tabelle haben will, oder ob er für jeden Benutzer eine separate Tabelle
anlegen will.
Logisch ist es, nur eine Tabelle zu verwenden, da zusammengehörige Daten
gleicher Struktur auch an einer zentralen Stelle gesammelt werden sollten.
Praktisch ist es auch, da so eine spätere Modifikation oder Erweiterung der
Datenstruktur unabhängig von der Anzahl an Benutzern nur für eine
Tabelle vorgenommen werden muss.
Bei der Überlegung, welche Spalten in der Tabelle enthalten sein sollen, muss unterschieden werden zwischen:
-
Notwendige Spalten
-
Optionale Spalten
-
Zusatzspalten (Die Kür)
Und natürlich findet sich hier auch das SQL-Statement, um die Tabelle tatsächlich zu erstellen.
Notwendige Spalten Um sich einzuloggen, gibt der Benutzer unseres Systems seinen Namen und sein Passwort an Da wir den Benutzer also anhand dieser Daten identifizieren, müssen wir zwingend diese beiden Spalten in unserer Tabelle bereitstellen.
Da wir den Namen des Benutzers nutzen, um ihn zu identifizieren, darf es nicht mehrere Benutzer geben, die den gleichen Namen in unserem System verwenden. mySQL hilft uns hier, da es die Eigenschaft UNIQUE zur Verfügung stellt.
Daraus folgt, dass wir zwingend zwei Spalten brauchen:
-
Name des Benutzers, mit dem er im System agieren will (vergleichbar dem Nickname in einem Forum wie dem vBulletin)
-
Das Passwort des Benutzers
Optionale Spalten
Nachdem wir jetzt alle Felder haben, die wir unbedingt brauchen, kommen jetzt die Spalten, die empfehlenswert, weil komfortabel sind.
Wie oben bereits geschrieben, wollen wir Sessions
verwenden.
Da wir die Session immer starten müssen, können wir nicht
davon ausgehen, dass sich hinter jeder Session ein eingeloggter Benutzer
verbirgt.
Was spricht also dagegen, die Tabelle um eine Spalte für die ID der Session des
Benutzers zu erweitern?
Bei nicht eingeloggten Benutzern steht in der entsprechenden Spalte natürlich
nichts.
Natürlich könnte nach erfolgreichem Anmelden eine Variable in der Session registriert werden und dann nur diese abgefragt werden, aber die Variante wie wir sie hier machen, ist meiner Meinung nach besser, weil sie flexibler im Hinblick auf Erweiterungen wie z. B. Rechtevergabe und -entzug ist.
Mit Hilfe dieser Spalte kann natürlich auch festgestellt werden, welche Benutzer momentan eingeloggt sind und welche nicht.
Um uns (auch und vor allem) im Hinblick auf eine einfache Verwendung der
Tabelle mitsamt der darin enthaltenen Benutzer die Arbeit zu erleichtern, wäre
es vorteilhaft, die Zahl der notwendigen Spalten, um einen Benutzer eindeutig zu
identifizieren, zu minimieren und den Inhalt dieser Spalte so klein wie nur
irgend möglich zu halten.
Eingeloggte Benutzer können anhand ihrer eindeutigen Session-ID identifiziert
werden, aber da nicht immer alle Benutzer eingeloggt sind, scheidet die Spalte
aus.
Jeder Benutzer kann über seinen eindeutigen Namen im System identifiziert
werden, aber ich persönlich bevorzuge eine weitere Spalte. Diese Spalte
beinhaltet die interne ID des Benutzers. Die ID ist eine eindeutige Zahl, anhand
derer ein Benutzer ganz zweifelsfrei und unproblematisch identifiziert werden
kann.
Ebenfalls zu empfehlen ist eine Spalte, die die Email-Adresse des Benutzers
beherbergt.
Mit Hilfe der Email-Adresse können Benutzer über wichtige Änderungen
informiert werden und außerdem kann die Email-Adresse zur Verifikation der
Existenz des Benutzers genutzt werden.
Daraus folgt, dass wir noch die folgenden Spalten in die Tabelle aufnehmen:
-
Benutzer-ID (diese Spalte wird als Primärschlüssel verwendet)
-
Session-Spalte, die die Session-ID eines momentan eingeloggten Benutzers beinhaltet
-
Mail-Spalte, die die Email-Adresse des Benutzers enthält
Zusatzspalten (Die Kür)
Hier ein kleiner Ausblick auf mögliche Erweiterungen:
-
Account-Freischaltung anhand eines Aktivierungslinks an die gespeicherte Email-Adresse
-
Anzahl fehlerhafter Login-Versuche (ggf. inklusive Sperren des Accounts und Zusenden eines neuen Passwortes bei Überschreitung eines Limits)
-
Prüfen, ob ein Benutzer gesperrt ist (ggf. auch warum)
-
Prüfen, ob ein Benutzer seinen Account aktiviert hat (kann zur Prüfung der Email-Adresse verwendet werden)
-
Zeitpunkt des Einloggens
-
Zeitpunkt der letzten Aktion
-
Zeitpunkt des Ausloggens
-
Spalte mit Benutzerlevel
-
Benutzer in verschiedene Gruppen einteilen
-
...
Das SQL-Statement
Folgendes SQL-Statement erstellt die Tabelle inklusive der notwendigen und optionalen Felder:
CREATE TABLE users ( UserID int(11) PRIMARY KEY auto_increment, UserName varchar(30) NOT NULL default '', UserPass varchar(32) NOT NULL default '', UserSession varchar(32), UserMail varchar(150) NOT NULL default '', UNIQUE KEY NickName (UserName), UNIQUE KEY UserMail (UserMail) )
PRIMARY KEY besagt, dass die Spalte UserID der Primärschlüssel der Tabelle ist, also jeden Datensatz eindeutig identifiziert. auto_increment besagt, dass der Wert dieser Spalte automatisch um 1 erhöht wird,wenn ein neuer Benutzer angelegt wird, d. h. die Datenbank kümmert sich selbst darum, dass die Eindeutigkeit gewährleistet bleibt. Toll, oder?
UNIQUE KEY besagt, dass die Datenbank auch von alleine darauf achtet, dass in der Spalte, die zwischen den Klammern steht, kein Wert doppelt eingetragen wird.
Und so sieht die Tabelle aus:
Field | Type | Null | Key | Default | Extra |
---|---|---|---|---|---|
UserID | int(11) | PRI | NULL | auto_increment | |
UserName | varchar(30) | UNI | |||
UserPass | varchar(32) | ||||
UserSession | varchar(32) | YES | NULL | ||
UserMail | varchar(150) | UNI |
Das Passwort
Hier kommt jetzt kein Hinweis darauf, dass Passwörter wie geheim, 007, passwort, der Geburtstag des Kanarienvogels rückwärts nicht empfehlenswert sind.
Ganz allgemein sollte man aber sagen:
-
je länger das Passwort, desto sicherer.
-
Groß- und Kleinbuchstaben, Sonderzeichen und Ziffern sollten alle verwendet werden.
Akzeptabel wäre zum Beispiel ein Passwort mit 6 Zeichen Läge, dass aus Buchstaben, Ziffern und Sonderzeichen besteht, aber eine dahingehende Prüfung hat mit dem eigentlichen Thema nicht direkt zu tun. Diese kleine Ausführung ist mehr als Anregung und Gedankenanstoß zu sehen.
Worauf ich eigentlich hinaus wollte, war:
Das Passwort wird in der Tabelle verschlüsselt
So kann niemand (wirklich niemand) das Passwort eines Benutzers auslesen.
Selbstverständlich muss das vom Benutzer eingegebene Passwort ebenfalls verschlüsselt
werden, bevor wir es mit dem in der Tabelle abgleichen können.
Zum verschlüsselten Speichern verwenden wir eine Funktion, die uns SQL zur
Verfügung stellt.
Ihr Name lautet MD5.
Die Funktion werden wir beim Anlegen des Beispielbenutzers und beim Einloggen in
Aktion sehen.
Der Beispielbenutzer
Damit wir später auch kontrollieren können, ob unser Login funktioniert,
legen wir jetzt einen Benutzer in unserem System an.
Der Benutzer wird folgende Daten haben:
Tabellenspalte | Wert |
---|---|
UserID | ? irrelevant, da die Spalte von der Datenbank automatisch befüllt wird |
UserName | admin |
UserPass | tutorial |
UserSession | NULL wird nicht angegeben, da NULL laut unserer Tabellendefinition der Standardwert ist |
UserMail | mrhappiness@inter.net |
Daraus ergibt sich folgendes SQL-Statement:
INSERT INTO users SET UserName='admin', UserPass=MD5('tutorial'), UserMail='mrhappiness@inter.net'
Danach sieht unsere Tabelle so aus:
UserID | UserName | UserPass | UserSession | UserMail |
---|---|---|---|---|
1 | admin | 0575c8d592fb7b088226750aceec2b4e | NULL | mrhappiness@inter.net |
Wie man unschwer erkennen kann, haben wir als Passwort tutorial verwendet, aber stattdessen steht auf einmal 0575c8d592fb7b088226750aceec2b4e in der Spalte UserMail. Diese Umwandlung hat die bereits erwähnte SQL-Funktion MD5 erledigt.
Das Loginformular
Natürlich wollen wir nicht, dass die Benutzer unseres Systems direkten
Kontakt zur Datenbank mit unserer Benutzertabelle haben.
Dagegen sprechen Gründe wie Datensicherheit, Datenschutz und nicht zuletzt natürlich
auch der Komfort.
Es ist schließlich nicht nur bequemer, sondern auch allgemein üblich die
Anmeldedaten in ein Formular einzugeben und dieses dann abzuschicken.
Solch ein Formular wollen wir jetzt (ganz rudimentär) erstellen:
<form method="post" action="login.php"> <label>Benutzername:</label><input name="username" type="text"> <br> <label>Passwort: </label><input name="userpass" type="password" id="userpass"> <br> <input name="login" type="submit" id="login" value="Einloggen"> </form>
Zur kurzen Erläuterung:
-
method="post" bedeutet, dass die Daten des Formulares versteckt versendet werden, also nicht in der Adressleiste des Browser auftauchen.
-
action="login.php" bedeutet, dass die Daten des Formulares an die Datei login.php gesendet werden. Diese Datei ist für die Auswertung der Daten zuständig.
-
Es gibt zwei Textfelder mit den Namen username und userpass.
Der Inhalt der Felder steht uns in PHP in einer Variablen mit gleichem Namen zur Verfügung.
Diese Datei speichern wir unter dem Namen login.php ab. Das heißt, dass wir die Daten sozusagen an uns selbst schicken. So können wir die Prüfung der Daten, das Einloggen und das erneute Anzeigen des Formulares im Fehlerfall am bequemsten durchführen.
Das Einloggen
Nachdem wir jetzt ein fast bildhübsches Formular haben, fehlt uns nur noch
die serverseitige Logik, mit Hilfe derer wir die eingegebenen Daten verifizieren
und angemessen reagieren.
Daher laden wir die Datei login.php und erweitern sie wie
folgt:
Wie gehabt, kommt erst der Code und danach die Erklärung:
<?php
session_start();
include 'sessionhelpers.inc.php';
if (isset($_POST['login']))
{
$userid=check_user($_POST['username'], $_POST['userpass']);
if ($userid!=false)
login($userid);
else
echo 'Ihre Anmeldedaten waren nicht korrekt!';
}
if (!logged_in())
echo '<form method="post" action="login.php">
<label>Benutzername:</label><input name="username" type="text"><br>
<label>Passwort: </label><input name="userpass" type="password" id="userpass"><br>
<input name="login" type="submit" id="login" value="Einloggen">
</form>';
else
echo '<a href="logout.php">Ausloggen</a>';
echo '<p /><a href="logged_in.php">Check</a>';
?>
Die erste Zeile startet die Session. Dieser Befehl muss auf allen Seiten
stehen, und zwar überall als erster Befehl, da es sonst unter Umständen zu
unschönen Fehlermeldungen kommt.
Die zweite Zeile bindet die Datei sessionhelpers.inc.php ein, in der
ein paar Funktionen zum Ein- und Ausloggen stehen.
Die dritte Zeile prüft, ob unser Formular abgeschickt wurde.
Ist das der Fall wird mit der Funktion check_user die UserID des
Benutzers erfragt, zu dem die eingegebenen Daten passen.
Es gibt hier zwei Möglichkeiten:
- Es wird eine UserID zurückgeliefert. Daraus folgt, dass die Anmeldedaten korrekt waren und der Benutzer wird mit der Funktion login eingeloggt.
- Es wird false zurückgeliefert. Daraus folgt, dass die Anmeldedaten nicht korrekt waren und es wird eine entsprechende Meldung ausgegeben.
Die folgenden Schritte werden immer durchgeführt, also auch dann, wenn der
Benutzer kein Formular abgeschickt hat:
Es wird geprüft, ob der Benutzer eingeloggt ist.
Ist dies der Fall wird ein Link ausgegeben, der ihm das Ausloggen ermöglicht,
anderenfalls wird das Login-Formular angezeigt.
Das Überprüfen
Natürlich reicht es nicht, den Benutzer einmalig einzuloggen.
Es muss auch geprüft werden, ob der Mensch, der gerade eine Seite anklickt, berechtigt ist eben diese zu sehen, ob er also eingeloggt ist. Die Prüfung läuft folgendermaßen:
<?php
session_start();
include 'sessionhelpers.inc.php';
echo 'Sie sind ';
if (!logged_in())
echo 'nicht ';
echo 'eingeloggt.<p />';
echo '<a href="login.php">Start</a>';
?>
Wie man sieht, ist die Prüfung recht kurz:
Die erste Zeile startet wie gehabt die Session. Danach wird wieder die Datei sessionhelpers.inc.php
eingebunden, da sie die Funktion logged_in() beinhaltet.
if (!logged_in()) prüft, ob der Benutzer eingeloggt ist. Das Ergebnis wird
durch das vorangestellte Ausrufezeichen »!« negiert.
Abhängig vom Ergebnis dieser Abfrage wird die Ausgabe angepasst. Das speichern wir jetzt als logged_in.php.
Das Ausloggen
Das Ausloggen eines Benutzers wird noch kürzer. Den unten stehenden Code speichern wir unter logout.php ab.
<?php
session_start();
include 'sessionhelpers.inc.php';
echo 'Sie sind ';
if (!logged_in())
echo 'nicht ';
echo 'eingeloggt.<p />';
logout();
echo 'Sie sind ';
if (!logged_in())
echo 'nicht ';
echo 'eingeloggt.< p/>';
echo '<a href="login.php">Einloggen</a>';
?>
Wie gehabt wird die Session gestartet. Danach wird wieder die Datei sessionhelpers.inc.php eingebunden, da sie die Funktion logout() beinhaltet.
Die Datei sessionhelpers.inc.php
Jetzt kommen wir endlich zu der Datei, die die Funktionalität, die wir schon mehrmals genutzt haben, beinhaltet.
Natürlich könnte man die oben verwendeten Abfragen auf jeder Seite verwenden, vor allem wenn wir sehen, wie wenig Codezeilen sie umfassen, wird sich das auch der ein oder andere fragen, daher hier gleich die Antwort:
Wenn ich die verwendeten Routinen nicht an jeder Stelle, an der sie verwendet werden, sondern nur einmal an einer zentralen Stelle einbinde, hast das mindestens diese 3 Vorteile:
- Sollte sich etwas ändern, muss die Änderung nur an der einen zentralen
Stelle vorgenommen werden.
So wird die Gefahr des Übersehens und des Vertippens bei einem Auftreten minimiert. - Die Funktionalität ist so leichter erweiterbar, da nur eine Stelle geändert werden muss.
- Wird die Login-Funktionalität auch an anderer Stelle benötigt, müssen die Routinen nicht mühsam aus mehreren Skripten zusammengesucht werden.
<?php
function connect()
{
$con=mysql_connect('servername','benutzer','passwort') or die(mysql_error());
mysql_select_db('datenbank, die die Benutzertabelle enthält',$con) or die(mysql_error());
}
function check_user($name, $pass)
{
$sql="SELECT UserId
FROM users
WHERE UserName='".$name."' AND UserPass=MD5('".$pass."')
LIMIT 1";
$result=mysql_query($sql) or die(mysql_error());
if (mysql_num_rows($result)==1)
{
$user=mysql_fetch_assoc($result);
return $user['UserId'];
}
else
return false;
}
function login($userid)
{
$sql="UPDATE users
SET UserSession='".session_id()."'
WHERE UserId=".$userid;
mysql_query($sql);
}
function logged_in()
{
$sql="SELECT UserId
FROM users
WHERE UserSession='".session_id()."'
LIMIT 1";
$result=mysql_query($sql);
return (mysql_num_rows($result)==1);
}
function logout()
{
$sql="UPDATE users
SET UserSession=NULL
WHERE UserSession='".session_id()."'";
mysql_query($sql);
}
connect();
?>
Jetzt fehlt nur noch die Erklärung:
Es gibt, wie man sieht, fünf Funktionen in der Datei.
connect()
Diese Funktion stellt eine Verbindung zum SQL-Server her.
Die Parameter servername, benutzer und passwort
sind natürlich anzupassen.
check_user($name, $pass)
Diese Funktion prüft die im Formular (oder ggf. im Cookie) eingetragenen Werte und liefert entweder die eindeutige ID des Benutzers zurück, oder false, falls es keinen Datensatz gibt, der die Bedingung erfüllt.
Diese Abfrage heißt übersetzt soviel wie:
Liefere (SELECT) den Wert der Spalte UserID
aus der Tabelle (FROM) users bei der (WHERE) der Wert in der Spalt
UserName und der Wert in der Spalte UserMail mit den Formulareingaben übereinstimmen.
Um die Geschwindigkeit etwas zu steigern (es ist aber auch so schon schnell), sagen wir, dass nach einem Datensatz (LIMIT 1) aufgehört werden soll mit der Suche.
login($userid)
Diese Funktion loggt einen Benutzer in unser System ein. Welcher Benutzer
eingeloggt werden soll, wird über den Parameter $userid angegeben.
Die ganze Hexerei wird erledigt, indem schlicht und ergreifend die
Session-ID (die eindeutig ist) in die Spalte UserSession des
Benutzers geschrieben wird.
logged_in()
Diese Funktion prüft, ob der Benutzer eingeloggt ist.
Zu diesem Zweck wird abgefragt, wie viele Einträge in der Benutzertabelle
mit der aktuellen Session-ID in der Spalte UserSession vorhanden
sind. Wird ein Eintrag gefunden, ist der Benutzer eingeloggt.
logout()
Diese Funktion loggt den Benutzer wieder aus, indem in die Spalte UserSession der Wert NULL geschrieben wird.
Der Schluss
So, das war's auch schon.
Ich hoffe, es war einigermaßen verständlich geschrieben und hat euch weitergeholfen.
Bei Fragen zu dem Tutorial sehen wir uns im Forum.
Ratings
Da steht alles drin was man über PHP als Einsteiger mit programmiererfahrung wissen muss:
Mit PHP kann man einen Linuxrechner (hier: einer mit echt krasser Hardware und Server genannt)
Fernbedienen (hier: befehle ausführen lassen, Datenbanken abfragen)
PHP ist die Schnittstelle zwischen Fernbediener/Nutzer und Linuxrechner
einzigst einen Link zum Fortsetzungskapitel "Rechteverwaltung mit PHP" hätte mir noch gefehlt (oder fällt diese Aufgabe eher dem Linuxsystem zu? also die rechteverwaltung mein ich )
Also mir hats SEHR GEHOLFEN
DANKE+Gruß,
joseppe
Here you can write a comment
Related topics
Wie schreibt man ein Forum mit PHP und Mysql
Wie erstellt man ein kleines Forum mit PHP und MYSQL? Dieses Tutorials zeigt wie es geht ...
Autor :
Moqui
Category:
PHP-Tutorials
Installation von MySQL auf Linux
SuSE Linux Pro 8.2 mit mysql einfach installieren ...
Autor :
Moqui
Category:
Linux & Server Tutorials
PHP cURL Tutorial: Using cURL to Make HTTP Requests
cURL is a powerful PHP extension that allows you to communicate with different servers using various protocols, including HTTP, HTTPS, FTP, and more. ...
Autor :
TheMax
Category:
PHP-Tutorials
plotting masters - a professional guide - Teil II
Grafische Interpolation und Bestapproximation von numerischen Wertepaaren: Wir wollen Punkte auf einer Zeichenebene über verschiedene Verfahren miteinander verbinden. ...
Autor :
EVAMasters
Category:
PHP-Tutorials
Hier ein kleines allgemeines Tutorial zu PHP
Die Einleitung ist in folgende Themen aufgeteilt: -Einleitung -Variablen -Parameterübergabe -Funktionen -Schleifen -IF-Abfragen Am besten Sie schauen sie sich der Reihenfolge nach an. ...
Autor :
demiangrandt@
Category:
PHP-Tutorials
Text-Counter mit IP-Sperre ( Cookies oder Datei)
In diesem Tutorial möchte ich erklären wir man auf 2 arten einen Counter Programmieren kann,nebenbei werden ein paar Datei Funktionen erklärt! ...
Autor :
support1@
Category:
PHP-Tutorials