Home > PHP > Kako napraviti logiranje na web stranici?

Kako napraviti logiranje na web stranici?

Prosinac 17th, 2008

Kratki kurs => Kako napraviti logiranje na web stranici?

Prvi ozbiljni problem koji se javi kada se čovjek igra sa PHPom obično je logiranje i zaštita pojedinih dijelova stranice.

Tada bi prvo trebali pročitati nešto o sigurnosti PHP aplikacija, skontati logiku koji ćemo koristiti, zakrpiti sve moguće i nemoguće propuste (mi mislimo na sve mogućnosti, lošim momcima je dovoljna samo jedna).

U ovom kratkom kursu pokušaću da Vam približim jednu moju logiku koju sam nekada koristio pri zaštiti svojih stranica.
Ono što je potrebno za razumijevanje ovog kursa je osnovno znanje PHPa & MySQLa.

Podatke o korisnicima čuvaćemo u MySQL tabeli. Šifru nećemo spremati u orginalnom obliku nego kriptovanu.
Zašto? Zato jer onaj ko pregleda (vlasnik baze podataka, mysql servera, hacker…) sadržaj tabele u bazi podataka neće vidjeti šifre nego nešto tipa “$1$F3yJ96m5$.gA9aeoIAEj3M3blO77/p0″. Ovako osiguravamo da šifra nije nigdje zapisana (sem na žutom papiriću na korisničkom monitoru :-) ) i time nije ni dostupna ljudima koji nemaju potrebe i prava da je znaju.
Šifru ćemo kriptovati funkcijom crypt();

Ova funkcija je one-way algoritam, znači da nema decrypt(), tj. ono što kriptujemo teoretski ne možemo vratiti u izvorni oblik.
Neko se može zapitati čemu to služi onda? Evo primjera gdje se to može iskoristiti:

Korisnik upiše svoj password kad se registruje, mi primimo taj password, kriptujemo ga i spremimo.
Korisnik dolazi, pokušava da se loguje, prihvatimo string koji je unio kao password, kriptujemo ga i onda taj hash poredimo sa onim kojeg imamo spremljen.

Ovako, opet napominjem, osiguravamo da se password ne nalazi na serveru!!!

MySQL tabela

Dosta, šuplje, da krenemo na posao :)
Podaci o korisnicima, čuvaju se u tabeli koja se pravi slijedećim queryjem

CREATE TABLE `user` (
`ID` INT(6)UNSIGNED
NOT NULL auto_increment,

`ime`VARCHAR(30)NOT NULL default ,

`prezime` VARCHAR(30)NOT NULL default ,

`username`VARCHAR(16) NOT NULL default ,

`adresa`VARCHAR(50) default NULL,

`telefon`VARCHAR(12) default NULL,

`fax` VARCHAR(12) default NULL,

`organizacija` VARCHAR(50) defaultNULL,

`CryptedPass` VARCHAR(50) NOT NULL default ,

PRIMARY KEY  (`ID`)

)TYPE=MyISAM;

FORMA ZA LOGIN

Dosta, šuplje, da krenemo na posao :)
Korisnici se logiraju preko slijedeće forme:

<form action=“user.php” method=“post” name=“logiranje”>
<table width=“300″ border=“1″ cellpadding=“2″ cellspacing=“2″>

<tr >

<td height=“29″ colspan=“2″>LOGIN

</td >

</tr >

<tr >

<td width=“50%”>Korisničko ime:&nbsp;</td >

<td width=“50%”>

<input name=“user” type=“text” id=“user” size=“17″ maxlength=“16″>

</td >

</tr >

<tr >

<td width=“50%”>
Šifra:&nbsp;</td >

<td width=“50%”>

<input name=“password” type=“password” id=“password” size=“17″ maxlength=“16″>

</td >

</tr >

<tr >

<td colspan=“2″>

<input name=“loginButon” type=“submit” id=“loginButon” value=“LOGIRAJ SE”>

</td >

</tr >

</table >

</form >

Korisnik submituje ovu formu koja poziva stranicu user.php, u kojoj se vrši provjera unešenih podataka.

Klasa i funkcije

Prije nego što objasnim kako se vrši provjera logiranja, da objasnimo klasu i funkcije koje će se koristi pri tome.

U fajlu klase.php nalazi se klasa user, koja se sastoji od konstruktora klase (pri kreranju nove instance klase user funkcija user() se automatski pokreće i u ovom slučaju konektuje na MySQL server), te funkcija članica ove klase.


Manual: Constructors are functions in a class that are automatically called when you create a new instance of a class with new.

function user()


{


mysql_connect(“localhost”,“root”,“”) or die(“ne mogu na MySQL”.mysql_error());


mysql_select_db(“bhwm”) or die (“Ne mogu na db <br />”.mysql_error());


}


Slijedeća funkcija je
add_user($ime,$prezime, $username,$adresa,$telefon,$fax,$org,$Pass) koja prima podatke koje ćemo upisati u tabelu, i preko standardnog queryja ih sprema u bazu podataka.

Jedino što vrijedi spomenuti je linija u kojoj kriptujemo password.

$CryptedPass = crypt($Pass);


Funkcija userlogin() obavlja glavni dio posla, i objasnićemo je liniju po liniju

function userlogin($username,$Pass)

{

Funkcija kao argumente prima korisničko ime i password koji su upisani, te ih proslijeđuje u query, koji vraća podatke o korisniku sa datim imenom.

(Napomena: validnost šifre ne provjeravamo u queryiju).

$sql=“SELECT ID, CryptedPass AS crypty, ime, prezime FROM user WHERE username= ‘$username’ “;

$r=mysql_query($sql) or die (mysql_error());

$a=mysql_fetch_array($r);

Na početku postavljamo kontrolnu zastavicu koju ćemo poslati kao izlazni arument funkcije. Zastavicu
setujemo na nulu, što bi značilo da nije prona?en odgovarajući korisnik.

$flag = 0;

Ukoliko je query vratio jedan rezultat (ne bi trebalo više, ako kodom regulišemo da je username unique) upuštamo se u provjeru passworda.

if (mysql_num_rows($r)==1)

{

Postavljamo novu varijablu $passw i setujemo njenu vrijednost na virjednost stringa koji smo pokupili iz baze za ovog korisnika (znam da pravim varijablu viška, al’ preglednije je).

$passw=$a[‘crypty’];
Password koji je korisnik unio kriptujemo sa uzorkom “$passw” koji smo imali spremljen u bazi (tzv. salt).
Kriptovan uneseni password poredimo sa uzorkom iz queryija, i ukoliko su isti logujemo korisnika

Napomena: pri kriptovanju (u ovom if() statmentu) moramo koristiti uzorak jer bez njega ne bi dobili žljeni string čak i ako bi korisnik upisao ispravan password, jer crypt (“dino”); ne vrati uvijek isto, tek sa crypt(“dino”,”ovo#je#prije#kriptovano#”) dobijamo željeni string.
Za više pogledajte šta piše o ovoj funkciji u manualu.

if(crypt($Pass,$passw) == $passw)

{


Ako je zadovoljen gornji uslov vrijeme je da logujemo našeg korisnika, jer je regularan (il’ nas je dobro zezn’o ;-) ). Podatke
o korisniku ćemo zapisati u sesiju, kao asocijativni niz. Pored ID korisnika upisaćemo i njegovo ime, mada ih po potrebi kasnije možemo
povući iz tabele. Takođe, snimićemo i njegovu IP adresu, nek se nađe.

session_start();

$ip = getenv (“REMOTE_ADDR”);

$_SESSION[‘ses_info’] = array(“ip” => $ip,“ime” => $a[ime], “prezime” => $a[prezime], “ID” => $a[ID]);
Sada se u arrayu $_SESSION[‘ses_info’] nalaze podaci (mogli smo upisati i samo ID korsnika, ali to nije sada bitno za ovaj kurs), sve je prošlo OK i flag dobija vrijednost 1

$flag = 1;

}

}
Poslaćemo $flag iz funkcije, na osnovu kojeg ćemo znati da li je uspjelo logovanje ili ne.

return ($flag);

}

}

?>

Listing fajla klase.php slijedi

<?php
class user
{
//konstruktor klase user
//pri kreiranju objekta automatski se vrši i konekcija na bazu podataka
function user()
{
mysql_connect(“localhost”,“root”,“”) or die(“ne mogu na MySQL”.mysql_error());
mysql_select_db(“bhwm”) or die (“Ne mogu na db <br />”.mysql_error());
}
//funkcija za dodavanje korisnika u bazu podataka
function add_user($ime,$prezime, $username,$adresa,$telefon,$fax,$org,$Pass)
{
$CryptedPass = crypt($Pass);
//password se cuva kriptovan, tako smo sigurni da password nije nigdje zapisana u orginalu
$sql=“INSERT INTO user VALUES (NULL, ‘$ime’, ‘$prezime’, ‘$username’,'$adresa’,'$telefon’,'$fax’,'$org’, ‘$CryptedPass’)”;
mysql_query($sql) or die (mysql_error());
}
//funkcija koja se poziva kada se user leli logovati
function userlogin($username,$Pass)
{
$sql=“SELECT ID, CryptedPass AS crypty, ime, prezime FROM user WHERE username= ‘$username’ “;
$r=mysql_query($sql) or die (mysql_error());
$a=mysql_fetch_array($r);
$flag = 0;
if (
mysql_num_rows($r)==1)
{
$passw=$a[‘crypty’];
if(
crypt($Pass,$passw) == $passw)
{
session_start();
$ip = getenv (“REMOTE_ADDR”);
$_SESSION[‘ses_info’] = array(“ip” => $ip,“ime” => $a[ime], “prezime” => $a[prezime], “ID” => $a[ID], “logiran” => “jes_ba”);
$flag = 1;
}
}
return (
$flag);
}
}
?>
user.php

Sve što nam je ostalo je da praktično iskoristimo klasu koju smo napravili. Ovo je jedna od prednosti ovakvog programiranja.

Jednom napišemo klasu i koristimo je kad god nam zatreba (naravno možemo ih iskoristiti na bilo kojem sajtu koji radimo).
Posebno lijep primjer (na koji je jednom “nadošao” moj kolega sa studija Nino Š.) je pravljenje jedne klase koja setuje konekciju na DB a sve ostale se izvode (class jedna extends druga) iz te, i koriste tu konekciju (znači samo jednom definišemo parametre te u svakoj drugoj konekciji koristimo te iste).
Prvo što uradimo je da pokupimo fajl klase.php
include “klase.php”;

Ako fali neka varijabla koje je trebala doći preko POST prekidamo izvršenje skripte.

if(empty($_POST[‘user’]))   die (“Upiši ime”);


if(empty(
$_POST[‘password’]))   die (“Upiši password”);

Dodajemo slasheve da bi spriječili da korisnik upiše “šuhveli” karaktere.

$User=addslashes($_POST[‘user’]);
$Password=addslashes($_POST[‘password’]);



Sada kreiramo instancu naše klase user, pa proslije?ujemo korisničko ime i njegovu šifru funkciji koja provjerava login.
Na osnovu zastavice ($flag) koju vrati naša funkcija, skripta će znati da li se korisnik logirao, da li su session varijable upisane, te da li da ga prebaci na zaštićeni dio sajta i da ga dalje tretira kao regularnog korisnika.

$korisnik = New user;

if( $korisnik->userlogin($User,$Password))


{


prebaci korisnika na zaštićeni dio

}else

{


echo
“—LOGIN FAILED—”;


}

Listing fajla user.php


<?php
include "klase.php";
if(empty(
$_POST['user']))   die ("Upiši ime");
if(empty(
$_POST['password']))   die ("Upiši password");
//znam da pravim visak varijabli al' volim se kutarisat $_POST i slicnog
$User=addslashes($_POST['user']);
$Password=addslashes($_POST['password']);
//nova instanca klase
$korisnik = New user;

if( $korisnik->userlogin($User,$Password))
{
?>
<script language=”Javascript”>
<!–
setTimeout(“window.location=’stranica.php’”, 10 * 1000);
//–>
</script>
<a href=”stranica.php”>Password prihvacen!<br></a>
Molim sacekajte par sekundi, ili kliknite na link iznad, ako ste iskljucili JS na Vasem browseru.
<?php

}else
{
echo
“—nije OK, pogresan username ili sifra—”;
}
?>

Provjera logiranja je završena, slijedi primjer zaštićene stranice.

Jedna zaštićena stratnica

Sve što trebamo uraditi jeste da na početku stranice, provjerimo da li postoje session varjable koje nam trebaju za normalan rad stranice.

Startamo sesiju (naravno prije bilo kakvog znaka poslanog u browser), i provjerimo da li je setovana varijabla $_SESSION[‘ses_info’][‘logiran’].

session_start();

if(

$_SESSION[‘ses_info’][‘logiran’] != “jes_ba”){


die(
“<a href=\”pristup.php\”>Niste logovani!</a>”);

}

Dalje možemo (dodatno) ponovo snimiti IP i provjeriti da li je istao kao ona u našem arrayu iz sessiona.

$ip_ = getenv (“REMOTE_ADDR”);


if($ip_ != $_SESSION[‘ses_info’][‘ip’]){


die(
“<a href=\”pristup.php\”>Niste logovani</a>”);


}


Ukoliko svi if uslovi budu zadovoljeni, korisniku dozvoljavamo da koristi ovu stranicu.

Listing fajla stranica.php


<?php
session_start
();
if(
$_SESSION['ses_info']['logiran'] != "jes_ba"){
die(
"<a href=\"index.php\">Niste logovani!</a>");
}
//snimamo ponovo IP adresu
$ip_ = getenv ("REMOTE_ADDR");
//poredimo IP adresu sa onom iz session varijable, ukoliko nisu iste, skripa prestaje da se izvr±ava
if($ip_ != $_SESSION['ses_info']['ip']){
die(
"<a href=\"index.php\">Niste logovani</a>");
}
//ovaj dio gore treba staviti na početak svih zaa;tićenih stranica
//dalje slijedi zaa;tićeni sadrl(aj
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Dobro doa;li</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2" />
</head>
<body>
<?php
echo "Dobro doa;li: ".$_SESSION['ses_info']['ime'].", ".$_SESSION['ses_info']['prezime'];
echo
"<br />Imate pravo pristupiti sadrl(aju na ovom sajtu";
?>
</body>
</html>

Logout

Da bi korisniku omogucili da se odloguje (uništi sesiju) jednostavno napravite ovakav fajl i linkujete na njega.

<?php

session_start();

//unset ($_SESSION['ses_info']);

//ili

session_destroy();

?>


Ovim bi završili naš kurs. Ostao sam vam dužan pokazati kako usere uopšte dodavati u tabelu. Ovo je primjer u kojem ručno upisujem podatke, a vi možete napraviti formu, koja će datoj funkciji proslije?ivati potrebne varijable.


<?php
include "klase.php";
$korisnik = New user;
$korisnik->add_user("Dino","Lokmic","dino_lok","Izvjesna cetvrt NewYorka","+3876100000","","Društvo propalih programera","mojasifra");
$korisnik->add_user("Vedran","H.","Vienna","Studentski prihvatni centar, Bec","+216100000","","Društvo propalih programera","vieninasifra");
?>


Ovo bi trebalo biti dovoljno sigurno za neku Vašu stranicu, ukoliko se ne valja neka ogromna lova na njoj :) .

Ukoliko imate komentara na kurs (posebno me interesuju mogući sigurnosni problemi), molim Vas da to iznesete na BHWM forumu, pa da ih zajedno otklonimo i preuredimo ovaj kurs.


Napomena:


Nije mi bila namjera da napravi neku free skriptu za autentifikaciju korisnika (radi supporta koji raja očekuje kada skine neki sličan besplatan rad), već da dam ideju za početak onima koji žele da ovo programiraju za svoju stranicu. Ukoliko Vam treba ovakva free skripta, ima dosta boljih na hotscripts.com i na phpclasses.org.
Zato Vas molim da mi ne šaljete emailove tipa “Instalirao sam tvoju skriptu ali ne radi…”.

Dino Lokmic

Popularity: 100% [?]

PHP , , , , , ,

  1. Siječanj 15th, 2009 at 18:18 | #1

    Mozda bi bolje bilo da su se posjetiocima objasnile klase i funkcije pa se onda preslo na rad s ovakvom skriptom.

    Ili eventualno da se ne koriste funkcije i klase..
    No u svakom slucaju, bravo.

  2. Siječanj 15th, 2009 at 22:47 | #2

    @xyz
    pozdrav anonimnom posjetitelju,
    hvala na komentaru. Drugi put rado sa imenom, nemate razloga za kriti se. Koristan savjet. Radi se o tome da je clanak napisan za naprednije korisnike, detaljnije o PHP-u moze se naci u PHP tecaju ovdje: http://www.bhwebmasters.net/?cat=36
    no ni tu se nismo dotakli klasa. Mislim da cemo opcenito o klasama pisati uskoro. Preporucio bih tecaj objekt orinetiranog programiranja koji je jos samo u arhivi ovdje: http://www.most-art.de/ctutorial/oop/1100.php i uskoro cemo ga prebaciti na ovaj novi CMS.

    pozdrav,
    Zeljko Kvesic

  3. sekretar
    Siječanj 15th, 2009 at 23:13 | #3

    @xyz
    Ideja je bila da se pokaze logika autentifikacije korisnika, provjera i rad sa ‘zasticenim’ dijelom stranice.

    Naravno sve se lijepo moglo pokazati i bez klasa, ali ovaj tutorijal i nije za pocetnike, niti za nekog ko bi uradio copy/paste.
    Samo daje ideju, kod sam po sebi i nije iskoristiv.

  4. Kolovoz 31st, 2009 at 15:28 | #4

    Eh ovako, prije svega da pozdravim sve na portalu , ima korisnih stvari.. da ne duljim nego predjem na stvar, znam da komentaru nije mjesto ovdje ,al nemam vremena traziti odredjeno mjesto..

    Ovako, poceo sam se bavit php programiranjem prije par dana, uz to pomalo i mysql ucim, nasao sam neku skriptu community portala pa na njoj vjezbam..zelio bi napravit da se na vrhu krecu porukice koje su korisnici upisali..
    znaci napravio sam u .css tamo poziciju div-a i sve, i stavim u taj DIV oznaku marquee i stavim da mi cita iz baze podatke izmedju marqee oznaka , eh sad , prilikom upisivanja porukice , korisnici moraju upisat svoj nick i poruku, mene zanima jel moguce da automatski kako nadje koji je nick korisnika,jer samo logovani mogu postavit poruku,znaci, da samo upisu poruku ,a da se gore prikazuje i ta poruka kao i njihov username, ovako pisu u tuddja imena pa sam iskljucio opciju dok ne sredim..

    pokusavo sam preko cookie,al ne ide.. kad se neko od korisnika izloguje onda samo poruka ostane,a cookie se brise .

    et hvala i nadam se Vasoj pomoci :)

  1. Siječanj 16th, 2009 at 11:15 | #1