Pierwszą rzeczą którą będziemy mieli do zrobienia to zaprojektowanie naszej bazy danych. Zakładam iż wystarczy nam do tego jedna baza z jedną tabelą. W tablicy tej będziemy przechowywać nazwę użytkownika oraz jego hasło. Hasło oczywiście ze względów bezpieczeństwa powinno być zakodowane, co uczynimy przy pomocy funkcji…

Skoro poznaliśmy już te najbardziej podstawowe zasady MySQL’a czas przystąpić do napisania naszego pierwszego skryptu, czyli wyjść na ten pierwszy spacer). W tym calu posłużymy się już istniejącym skryptem logowania napisanym przez lockoom’a w artykule „Sesje w PHP na przykładzie skryptu autoryzacji użytkowników„. Rozwiniemy go o sprawdzanie danych użytkownika zapisanych w bazie danych, oraz możliwość zmiany tych danych.

Pierwszą rzeczą którą będziemy mieli do zrobienia to zaprojektowanie naszej bazy danych. Zakładam iż wystarczy nam do tego jedna baza z jedną tabelą. W tablicy tej będziemy przechowywać nazwę użytkownika oraz jego hasło. Hasło oczywiście ze względów bezpieczeństwa powinno być zakodowane, co uczynimy przy pomocy funkcji md5(). Dodatkowo dla ułatwienia będziemy przechowywać razem z danymi użytkownika jego ID. W bazie będziemy co prawda dbali o to aby przechowywany był zawsze tylko jeden użytkownik, ale to ID przyda nam się przy jego usuwaniu.

Skoro juz ustaliliśmy wygląd naszej bazy danych to musimy napisać pierwszy plik, który będzie definiował nasza bazę czyli będzie przechowywał wszystkie instrukcje potrzebne do jej stworzenia. Od razu wyjaśniam, że przyjąłem iż nasz baza nazywać się będzie pass, a tablica users. Oto nasz plik:

db.sql:

CREATE DATABASE pass; 
USE pass; 
CREATE TABLE users ( 
id int NOT NULL auto_increment, 
name varchar(20), 
pass varchar(255), 
PRIMARY KEY (id) 
); 
INSERT INTO users VALUES(0, 'root', '63a9f0ea7bb98050796b649e85481845'); 

W pierwszej lini tworzymy bazę danych – CREATE, następnie wybieramy ją do użycia – USE. W kolejnym kroku tworzymy tabelę – CREATE TABLE do której wstawiamy wszystkie oczekiwane przez nas pola: id – ID użytkownika, name – nazwa użytkownika, oraz pass- jego hasło w zakodowanej formie. Teraz, ze względu na to żeby w skrypcie uniknąć tworzenia mechanizmów tworzenia pierwszego użytkownika od razu wprowadzimy jego dane INSERT. Będzie się on nazywał root, a jego hasło będzie brzmiało tak samo: root. Jednak ze względu na wykorzystywanie w skrypcie hasła kodowanego musimy podać tu jego wersję zakodowaną. Najprościej będzie posłużyć się skryptem PHP:”” – po jego wykonaniu dostaniemy na ekranie wartość która należy wpisać do pliku db.sql.

Teraz trzeba zawartość naszego pliku wprowadzić do bazy. W tym celu kopiujemy go bo katalogu bin bazy danych i z linii poleceń bazy wydajemy polecenie:

\. db.sql 

W naszej bazie mamy już wszystko zrobione. Teraz przystępujemy do napisania skryptów ja obsługujących. Stworzymy w tym celu plik mySQL.php w którym zdefiniujemy sobie zmienne konfigurujące połączenie z serwerem bazy danych, oraz dwie klasy do obsługi tej bazy.

Nawet jeśli pracujemy na lokalnym parserze PHP i lokalnej bazie danych, pamiętajmy, że serwer Apache i tak widzi ją jako serwer, tyle że o adresie localhost. Jako że w tym artykule stawiamy na praktykę, najpierw kod, a potem wyjaśnienia.

mySQL.php:

<?php 
# zmienne konfiguracyjne 
$dbServer="localhost"; #adres serwera bazy danych 
$dbUserName="local"; #nazwa użytkownika bazy danych 
$dbUserPass="local"; #hasło użytkownika bazy danych 
$dbName="pass"; #nazwa bazy dancyh 
class dbMySQL 
{ 
var $dbHandle; #identyfikator połączenia z bazą danych 
var $result; #wynik funkcji MySQL'owych 
function Query($q="") 
{ 
  if ($q!="") 
   $this->result=mysql_query($q, $this->dbHandle); 
} 
function dbMySQL($q="") 
{ 
  global $dbServer; 
  global $dbUserName; 
  global $dbUserPass; 
  global $dbName; 
  $this->dbHandle=mysql_connect($dbServer, $dbUserName, $dbUserPass); 
  $this->result=mysql_query("USE ".$dbName, $this->dbHandle); 
  if ($q!="") 
   $this->Query($q); 
} 
function destroy() 
{ 
  $this->result=mysql_close($this->dbHandle); 
} 
}; 
class dbUserClass 
{ 
var $dbHandle; #obiekt bezpośredniej obsługi bazy danych 
var $userId;   #id użytkownika 
var $userName; #nazwa użytkownika 
var $userPass; #hasło użytkownika 
function ReadUser() 
{ 
  $this->dbHandle->Query("SELECT * FROM users"); 
  $UserObj=mysql_fetch_object($this->dbHandle->result); 
  $this->userId=$UserObj->id; 
  $this->userName=$UserObj->name; 
  $this->userPass=$UserObj->pass; 
  unset($UserObj); 
} 
function WriteUser() 
{ 
  $this->dbHandle->Query("DELETE FROM users WHERE 
id=".$this->userId); 
  $this->dbHandle->Query("INSERT INTO users VALUES(0, 
'".$this->userName."', '".$this->userPass."')"); 
} 
function ChxUser($n, $p) 
{ 
  if(($this->userName==$n)&&($this->userPass==md5($p))) 
  { 
   return true; 
  } 
  else 
  { 
   return false; 
  }; 
} 
function ChangeUser($n, $p) 
{ 
  $this->userName=$n; 
  $this->userPass=md5($p); 
  $this->WriteUser(); 
} 
function dbUserClass() 
{ 
  $this->dbHandle=new dbMySQL(); 
  $this->ReadUser(); 
} 
function destroy() 
{ 
  $this->dbHandle->destroy(); 
} 
}; 
?> 

W pierwszej części zdefiniowaliśmy wspomniane dane konfiguracyjne, zgodnie z ich opisem w komentarzach. Następnie tworzymy klasę do ogólnej obsługi MySQL’a o nazwie dbMySQL – klasa ta ma dwie włąsciwości – w jednej przchowujemy identyfikator połączenia z bazą danych dbHandle, a drugą jest wskaźnik rezultatu funkcji wysyłającej zapytanie – result.

Klasa ta trzy metody. Pierwszą jest metoda Query(), wysyłająca zapytanie do bazy i umieszczająca jego zwracająca jego rezultat pod właściwość result Parametrem tej metody jest treść zapytania SQL’owego która zostanie przekazana bazie danych przez funkcję mysql_query.
Kolejną metodą jest konstruktor klasy dbMySQL() nawiązuje on połączenie z bazą danych funkcją mysql_connect przypisując identyfikator tego połączenia do właściwości dbHandle oraz w przypadku podania jako parametru treści zapytania do bazy, od razu wywołuje metodę Query() wysyłając to zapytanie. Ostatnią metodą jest pseudo destruktor destroy() (może się on stać prawdziwym destruktorem poprzez umieszczenie w konstruktorze linijki:

 register_shutdown_function('destroy'); 

Jednak funkcja ta działa tylko na systemach unix’owych i ze względu na lokalny charakter użycia tego skryptu – do celów dydaktycznych – zrezygnowałem zniej). W desruktorze kończymy tylko połączenie z bazą poprzez mysql_close.

Drugą, najważniejszą ze względu na algorytm naszego skryptu klasą jest klasa dbUserClass to właśnie w niej zdefiniowane są wszystkie metody potrzebne przy logowaniu. Więc po kolei, najpierw właściwości:

dbHandle obiekt klasy dbMySQL odpowiedzialny za naszą „łączność” z bazą. potem trzy właściwości opisujące użytkownika: userId, userName, userPass to odpowiednio ID użytkownika, jego nazwa i hasło. Są odpowiednikami pól w bazie danych którą zdefiniowaliśmy w pliku db.sql.

Następnie metody:
ReadUser() jest metodą pobierającą dane z bazy danych – mysql_query, następnie wyciąga z rezultatu dane o użytkowniku i przypisuje do obiektu $UserObj. Potem dat tego obiektu są przypisywane do własności naszej klasy, a obiekt jest usuwany.

Pajączek.pl - twórz poprawiaj publikuj

Kolejną metodą jest WriteUser() zapisująca dane o użytkowniku do bazy danych. Skorzystaliśmy tu z njprostrzej ocji skasowania krotki DELETE w której pole id jest równe właściwości userId, a następnie doaliśmy nowy wpis INSERT.

Następnie tworzymy metodę ChxUser(), sprawdzającą czy podane dane o użytkowniku, są zgodne z tymi, przechowywanymi w obiekcie. Parametrami tej metody są, kolejno: $n – nazwa użytkownika, oraz $p – hasło użytkownika. Metoda zwraca wartość true gdy hasło i nazwa się zgadzają, oraz false gdy się nie zgadzają. Można ją więc bezpośrednio wykorzystać w instrukcjach warunkowych.

Dalej tworzymy metodę pozwalającą na zmianę danych użytkownika w obiekcie – ChangeUser(). Nie możemy zmieniać ich bezpośrednio, gdyż musimy odpowiednio zakodować hasło. Parametrami tej metody, podobnie jak poprzednio są, kolejno: $n – nazwa użytkownika, oraz $p – hasło użytkownika.
Został jeszcze tylko do stworzenia konstruktor dbUserClass(), który stworzy obiekt dbHandle i wczyta odpowiednie dane z bazy metodą ReadUser(), oraz pseudo destruktor destroy(), który z kolei ma za zadanie wywoływać metodę destruktora obiektu dbHandle.

To już jest prawie wszystko co musimy zrobić aby nasz skrypt logujący zaczął działać w oparciu o bazę danych. Teraz tylko naszą pracę musimy odpowiednio włączyć do skryptów przedstawionych przez kolegę lockoom’a. Oto odpowiednie przykłady:

login.php (tu chyba najistotniejsze zmiany):

<?php 
include("mySQL.php"); # LucaS: dołancza plik z obiektami MySQL'a 
$User=new dbUserClass(); #LucaS: stworzenie obiektu użytkownika 
if (isset($_POST['login']) && isset($_POST['pass'])) {  # zmieniono 
$login i $pass na odpowiednie indeksy tablicy superglobalnej $_PASS 
    $login=$_POST['login'];  # doano celem dostosowania skryptu 
    $pass=$_POST['pass'];    # doano celem dostosowania skryptu 
#   if ($login == "lockoom" && $pass == "test") {  # 
LucaS: oryginalny warunek zamieniony na warunek korzystający z bazy danych 
    if ($User->ChxUser($login,$pass)) {            # LucaS: nowy warunek 
        session_start(); 
        session_register("login"); 
        header("Location: secret.php?" . SID); 
        exit(); 
    } 
    else 
    $error = "Błędny login lub hasło!"; 
} 
else 
$error = false; 
$User->destroy(); # LucaS: destruktor obiektu 
?> 
<HTML> 
<HEAD> 
<TITLE>Logowanie</TITLE> 
</HEAD> 
<BODY> 
<?php echo $error ? $error : ""; ?> 
Podaj login i&nbsp;hasło 
<FORM method="POST" action="<?php echo 
basename($_SERVER['PHP_SELF']) ?>"> 
Login: <INPUT type="text" name="login"> 
Hasło: <INPUT type="password" name="pass"> 
<INPUT type="submit" value="Zaloguj się"> 
</FORM> 
</BODY> 
</HTML> 

Istotne jest tu włączenie naszych klas, utworzenie obiektu $User klasy dbUserClass oraz wywołanie metody jego pseudo destruktora. Bardzo istotne też są zmiany w warónku sprawdzającym poprawność logowania.

W pliku secret.php dodałem tylko formularz umożliwiający zmianę danych użytkownika, jednak cała zmiana odbywa się w kolejnym pliku, dlatego przytoczę tu tylko jego nowy listing.

secret.php:

<?php 
session_start(); 
if (!isset($_SESSION["login"])) { 
    header("Location: login.php"); 
    exit(); 
} 
?> 
<HTML> 
<HEAD> 
<TITLE>Tajne/poufne</TITLE> 
</HEAD> 
<BODY> 
<?php 
echo "Witaj " . $_SESSION["login"]; 
echo "<A href='logout.php?" . SID . "'>"; 
echo "[Wyloguj]</a>"; 
?> 
Ściśle tajne dane. 
<!-- LucaS: dodana możliwość zmieny hasła --> 
<br> 
Tutaj możesz zmienić nazwę użytkownika i hasło: 
<form name="NUser" method="POST" <?php echo 
"action='change.php?" . SID . "'"; ?> 
onSubmit="if(this.NewUserPass.value==this.NewUserPassRetype.value){return 
true;}else{return false;};"> 
<table border="0" cellpadding="0" 
cellspacing="0"> 
<tr> 
        <td>Nazwa:</td> 
        <td><input type="text" 
name="NewUserName"></td> 
</tr> 
<tr> 
        <td>Nowe hasło:</td> 
        <td><input type="password" 
name="NewUserPass"></td> 
</tr> 
<tr> 
        <td>Powtórz nowe hasło:</td> 
        <td><input type="password" 
name="NewUserPassRetype"></td> 
</tr> 
</table> 
<input type="submit" name="Change" value="Zmień 
użytkownika"> 
</form> 
<!-- LucS: /dodana możliwość zmieny hasła --> 
</BODY> 
</HTML> 

Jak widać z tego pliku, faktyczna zmiana danych odbywa się w pliku change.php. W pliku tym podobnie jak w login.php włanczamy najpierw nasze definicje klas i tworzymy nowy obiekt $User. Następnie korzystając z kodu lockooma’a sprawdzamy czy oby napewno jesteśmy zalogowani. Teraz już banalnie prosto – wywołujemy metodę zmieniająca dane użytkownika ChangeUser() z odpowiednimi parametrami, desruujemy obiekt $user oraz sesję i zmuszamy użytkownika do ponownego zalogowania się.

change.php:

<?php 
include("mySQL.php"); # LucaS: doołancza plik z obiektami MySQL'a 
$User=new dbUserClass(); #LucaS: stwożenie obiektu użytkownika 
# Lockoom: sprawdzanie czy zalogowany 
session_start(); 
if (!isset($_SESSION["login"])) { 
    header("Location: login.php"); 
    exit(); 
}; 
# Lockoom: /sprawdzanie czy zalogowany 
$User->ChangeUser($_POST['NewUserName'],$_POST['NewUserPass']); 
$User->destroy(); 
session_destroy(); 
header("Location: login.php"); 
?> 

dla wygody pozwoliłem sobie także dodać jeden link do pliku logout.php

logout.php:

<?php session_start(); ?> 
<HTML> 
<HEAD> 
<TITLE>Wylogowanie</TITLE> 
</HEAD> 
<BODY> 
<?php 
echo "Użytkownik " . $_SESSION["login"]; 
echo " został wylogowany."; 
session_destroy(); 
?> 
<!-- LucaS: dodano celem ułatwienia testów --> 
<br> 
<a href="index.php"> Początek </a> 
<!-- LucaS: /dodano celem ułatwienia testów --> 
</BODY> 
</HTML> 

To już byłby koniec w tej serii, podstawowych artykułów o MySQL’u – zakończyliśmy praktycznie i chyba o to chodzi. Teraz wszystkim życzę maksimum inwencji twórczej. W następnych artykułach zajmę się już bardziej złożonymi problemami.

Acha – pamiętajcie o tym co pisałem na początku cyklu. Odpuściliśmy sobie na tym etapie kontrolę błędów i przedstawione przykłady jej nie zawierają. Jeśli chcielibyście je profesjonalnie wykorzystać, koniecznie musicie ją dorobić.

Wielkie dzięki dla Marek Pawłowskiego (lockoom) za zgodę na wykorzystanie jego skryptów jako bazy do stworzenia przykładów w tym artykule. Skrypty napisane przez niego to pliki: login.php, secret.php, logout.php – a wszelkie zmiany w stosunku do oryginału zostały w nich zaznaczone.

Pozdrawiam,
Łukasz A. “Lucas” Grabowski