PHP - PHP i bezpieczne logowanie 12-2004.pdf
(
404 KB
)
Pobierz
Warsztat_PHP5-sysCMS_12.qxd
C
M
Y
K
PHP
NA CD
NEWSY
Z OKýADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
8
PHP
i
bezpieczne
logowanie
KaŇdy programista PHP prħdzej czy pŅniej stanie przed problemem stworzenia systemu
logowania do serwisu internetowego. DziĻ internauci sĢ juŇ przyzwyczajeni do tego,
Ňe coraz czħĻciej niektre interesujĢce ich informacje dostħpne sĢ jedynie
po zarejestrowaniu siħ w serwisie oraz zalogowaniu siħ. Czħsto potrzeba logowania
wynika takŇe z koniecznoĻci zapewnienia bezpieczeıstwa, np. panel administracyjny
sklepu internetowego lub systemu CMS powinien byę dostħpny jedynie dla ĻciĻle
okreĻlonego grona uŇytkownikw.
Marcin Staniszczak
sze z nich to wykorzystanie autoryzacji HTTP (co opisano dokþad-
nie w MI 9/04, str. 94). Jednak sposb ten jest maþo elegancki,
a dodatkowo czħsto niedostħpny ze wzglħdu na koniecznoĻę utworze-
nia oraz modyfikowania pliku .htaccess. W artykule zaproponujħ im-
plementacjħ klasy autoryzacji opartej o bazħ MySQL oraz przedstawiħ
sposb jej wykorzystania z uŇyciem sesji, a na koniec podsunħ kilka
pomysþw na rozbudowħ zaprezentowanej tu klasy.
lastlogin INT NOT NULL,
lasttry INT NOT NULL,
trycount INT NOT NULL,
authority INT NOT NULL,
UNIQUE(login),
PRIMARY KEY(iduser)
);
Przygotowania
Zanim zaczniemy pisanie naszej klasy, musimy siħ zastanowię, jakie
informacje chcemy przechowywaę w bazie. JuŇ na samym poczĢtku
nasuwa siħ myĻl o loginie i haĻle. Ale nie musimy siħ ograniczaę tylko
do tych dwch informacji. W konstruowanej tu klasie bħdziemy prze-
chowywali imiħ i nazwisko uŇytkownika, jego adres e-mail. Dodatko-
wo zapiszemy poziom uprawnieı, co pozwoli na podziaþ serwisu opar-
tego na tej klasie na moduþy, do ktrych dostħp bħdĢ mieli jedynie
uŇytkownicy z odpowiednimi uprawnieniami.
A oto polecenie SQL tworzĢce tabelħ uŇywanĢ w naszej klasie:
u
iduser Î unikatowy identyfikator uŇytkownika,
u
login, passwd, name, surename, email Î odpowiednio: login
uŇytkownika, jego hasþo, imiħ, nazwisko oraz e-mail,
u
authority Î poziom uprawnieı uŇytkownika.
Nic nie wiadomo jeszcze o polach
lastlogin, lasttry
oraz
trycount
.
Pierwsze z nich bħdzie sþuŇyþo do przechowywania daty ostatniego lo-
gowania. Dlaczego w takim razie
lasttry
jest typu INT? OdpowiedŅ
jest prosta Î data bħdzie przechowywana w bazie w postaci uniksowe-
go znacznika czasu, czyli w postaci liczby bħdĢcej iloĻciĢ sekund jakie
upþynħþy od 1 stycznia 1970 roku. O znaczeniu pozostaþych pl
(
lasttry, trycount
) napiszħ podczas analizy kodu klasy autoryzacji.
CREATE TABLE login
(
iduser INT NOT NULL auto_increment,
login varchar(25) NOT NULL,
passwd varchar(32) NOT NULL,
Klasa cLogin
Pora na przyjrzenie siħ klasie odpowiedzialnej za przeprowadzanie au-
toryzacji. Na poczĢtku zabezpieczamy plik z naszĢ klasĢ przed wpisa-
niem go w adresie przeglĢdarki. JeĻli ktoĻ chciaþby to uczynię (i wpisaę
w przeglĢdarce stronħ o adresie np.
http://adres_strony/include/login.class.php
, zo-
stanie przekierowany na stronħ gþwnĢ serwisu). Nie moŇemy zapo-
mnieę o zmianie w razie koniecznoĻci adresu, na ktry ma zostaę prze-
name varchar(30) NOT NULL,
surename varchar(50) NOT NULL,
email varchar(200) NOT NULL,
98
Omawiane w artykule przykłady są dostępne na dołączonej płycie CD w katalogu
Warsztat_logowanie (archiwum source.rar). Znajduje się tam m.in. plik makedb.php,
który zakłada niezbędną bazę i tabele do funkcjonowania przykładów.
INTERNET.grudzieı.2004
I
stnieje przynajmniej kilka podejĻę do tematu autoryzacji. Najprost-
C
M
Y
K
7
WARSZTAT
PROGRAMY
MAGAZYN
FIRMA
Z OKýADKI
NEWSY
NA CD
PHP
kierowany taki uŇytkownik (w linii Header naleŇy zmienię wpis
../index.php
).
JuŇ na poczĢtku zabezpieczamy siħ przed przemyceniem przez
uŇytkownika instrukcji SQL, ktre mogþyby narobię baþaganu
w bazie (w najgorszym razie nawet jĢ usunĢę). SþuŇy do tego
funkcja
mysql_escape_string(..)
, ktra analizuje tekst podany jako
parametr oraz modyfikuje go tak, aby byþ w peþni bezpieczny
i mgþ zostaę wykorzystany w zapytaniu SQL. Podczas zabezpie-
czania hasþa jest ono dodatkowo szyfrowane za pomocĢ funkcji
haszujĢcej
md5(..)
. Funkcja ta zwraca ciĢg 32 znakw, ktre iden-
tyfikujĢ podane hasþo. Jednak na podstawie znakw wygenerowa-
nych za jej pomocĢ nie da siħ odzyskaę hasþa. Z tego powodu
w razie utraty hasþa przez uŇytkownika, musimy np. wysþaę mu
nowe hasþo (poniewaŇ to w bazie jest zapisane w postaci zakodo-
wanej, co jest jednoznaczne z niemoŇnoĻciĢ jego odzyskania).
Takie podejĻcie wydaje siħ byę rozsĢdne Î wielu uŇytkownikw
uŇywa jednego hasþa we wszelkich moŇliwych sytuacjach.
UmieszczajĢc w bazie hasþo w postaci zakodowanej poprzez funk-
cjħ
md5(..)
, mamy pewnoĻę, Ňe w razie wþamania siħ kogoĻ do na-
szej bazy danych osoba ta i tak nie pozna (w szybki sposb) haseþ
naszych uŇytkownikw.
<?php
if (eregi(Ñlogin.class.phpÑ,$_SERVER[ÓPHP_SELFÓ])) {
Header(ÑLocation: ../index.phpÑ);
die();
}
Nastħpnie definiujemy trzy staþe. Takie wartoĻci bħdzie zwracaþa
nasza funkcja autoryzujĢca:
u
AUTH_FALSE Î oznacza, Ňe podano nieprawidþowy login lub
hasþo,
u
AUTH_OK Î oznacza, Ňe uŇytkownik istnieje i podaþ poprawne
hasþo,
u
AUTH_3TIMES_ERROR Î oznacza, Ňe uŇytkownik o podanym
loginie istnieje, jednak trzy razy pod rzĢd podaþ niepoprawne
hasþo.
define(ÓAUTH_3TIMES_ERRORÓ, 32);
define(ÓAUTH_FALSEÓ, 16);
define(ÓAUTH_OKÓ, 8);
function check($login, $passwd) {
$login = mysql_escape_string($login);
$passwd = mysql_escape_string(md5($passwd));
Przyszþa kolej na definicjħ klasy. NazwĢ klasy bħdzie
cLogin
. Po-
czĢtkowa literka
c
oznacza, Ňe jest to klasa (przy duŇych projektach ta-
kie nazewnictwo ma uþatwię pracħ, ale wszystko zaleŇy od przyjħtych
wzorcw).
Na poczĢtku definiujemy zmienne, w ktrych bħdĢ przechowywa-
ne: identyfikator poþĢczenia z bazĢ MySQL (
$dbConnection
), znacz-
nik informujĢcy o tym czy uŇytkownik przeszedþ autoryzacjħ
(
$isLogin
), informacje o uŇytkowniku (
$id, $name, $surename,
$eMail, $lastLogin, $authority
) oraz trzy zmienne, ktrych znaczenie
poznamy nieco dalej.
Gdy zmienne przechowujĢce hasþo i login majĢ juŇ postaę pozwala-
jĢcĢ bezpiecznie je wykorzystaę w zapytaniu SQL, wydobywamy z ba-
zy informacjħ o uŇytkowniku, ktry taki login posiada. Nie zwracamy
uwagi na to, czy podane hasþo pasuje do tego znajdujĢcego siħ w ba-
zie, poniewaŇ po trzech nieudanych prbach logowania siħ na okreĻlo-
ne konto chcemy je zablokowaę na np. 5 minut.
Nastħpnie sprawdzamy ilu uŇytkownikw w naszej bazie ma
login taki sam, jak podany w parametrze wejĻciowym funkcji
check(..)
. JeĻli liczba takich uŇytkownikw jest rŇna od jedynki,
wwczas uznajemy, Ňe autoryzacja nie powiodþa siħ (ze wzglħdu na
ograniczenie
UNIQUE
zaþoŇone w tabeli
login
na polu
login
moŇe
istnieę tylko jeden uŇytkownik o tym samym loginie), w przeciw-
nym razie moŇemy przystĢpię do kolejnych testw. W tym celu
odczytujemy kilka informacji o logujĢcym siħ uŇytkowniku: jego id,
liczbħ nieudanych prb logowania oraz datħ ostatniej nieudanej pr-
by logowania.
class cLogin {
var $dbConnection;
var $isLogin;
var $id;
var $name;
var $surename;
var $eMail;
var $lastLogin;
var $authority;
var $lastTry;
var $tryCount;
var $nextTry;
$record = mysql_query(ÑSELECT * FROM login WHERE
Æ
login=Ó$loginÓÑ, $this->dbConnection)
Æ
or die(ÓProblem z baza danychÓ);
if(mysql_num_rows($record)===1) {
$res = mysql_fetch_assoc($record);
$this->id = $res[ÓiduserÓ];
$this->tryCount = $res[ÓtrycountÓ];
$this->lastTry = $res[ÓlasttryÓ];
Konstruktor klasy cLogin jest bardzo prosty. Przyjmuje on jeden
argument, ktrym jest identyfikator poþĢczenia z bazĢ danych (klasa
sama nie nawiĢzuje takiego poþĢczenia), przekazuje ten identyfikator
do zmiennej
$dbConnection
oraz ustawia poczĢtkowe wartoĻci zmien-
nych
$isLogin
oraz
$nextTry
.
Sprawdzamy czy hasþo podane jako parametr funkcji jest iden-
tyczne z tym, ktre znajduje siħ w bazie. Sprawdzamy rwnieŇ czy
liczba prb logowania na sprawdzane konto nie osiĢgnħþa juŇ licz-
by 3. JeĻli hasþo jest niepoprawne lub nastĢpiþa trzecia nieudana
prba logowania na konto, zwracamy wartoĻę AUTH_3TI-
MES_ERROR (zobacz dalej). W przeciwnym razie przypisujemy
zmiennym
$name, $surename, $authority
oraz
$eMail
poprawne
wartoĻci (odczytane wczeĻniej z bazy danych). Nastħpnie aktuali-
zujemy informacjħ w tabeli. Ustalamy odpowiedniĢ wartoĻę pola
lastlogin
oraz zerujemy pola
trycoun
i
lasttry
. Zmiennej
$isLogin
moŇna przypisaę wartoĻę true i zakoıczyę funkcjħ
check(..)
z war-
toĻciĢ
AUTH_OK
.
function cLogin($dbConnection) {
$this->dbConnection = $dbConnection;
$this->isLogin = false;
$this->nextTry = false;
}
NajwaŇniejszĢ funkcjĢ caþej klasy jest
check(..)
. Przyjmuje
ona dwa parametry: login uŇytkownika oraz jego hasþo. Ze
wzglħdu na dþugoĻę oraz zþoŇonoĻę tej funkcji zostanie ona opi-
sana fragmentami.
INTERNET.grudzieı.2004
99
C
M
Y
K
NA CD
NEWSY
Z OKýADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
8
PHP
if((strcmp($res[ÓpasswdÓ], $passwd)===0) &&
Æ
(($this->tryCount<3) || (($this->lastTry+300)
Æ
<time()))) {
$this->name = $res[ÓnameÓ];
$this->surename = $res[ÓsurenameÓ];
$this->lastLogin = $res[ÓlastloginÓ];
$this->authority = $res[ÓauthorityÓ];
$this->eMail = $res[ÓemailÓ];
if(($this->tryCount>=3) && (($this->lastTry+600)<time())) {
$record = mysql_query(ÑUPDATE login SET lasttry=Ñ.
Æ
time().Ñ, trycount=1 WHERE iduser=Ñ.$this->id,
Æ
$this->dbConnection) or die(ÓProblem z baza danychÓ);
}else
$record = mysql_query(ÑUPDATE login SET lasttry=Ñ.
Æ
time().Ñ, trycount=Ñ.($this->tryCount+1).Ñ WHERE
Æ
iduser=Ñ.$this->id, $this->dbConnection)
Æ
or die(ÓProblem z baza danychÓ);
}
return AUTH_FALSE;
}
} else { //uŇytkownik nie istnieje
return AUTH_FALSE;
}
//update daty ostatniego logowania
$record = mysql_query(ÑUPDATE login SET
Æ
lastlogin=Ñ.time().Ñ, trycount=0, lasttry=0
Æ
WHERE iduser=Ñ.$this->id, $this->dbConnection)
Æ
or die(ÓProblem z baza danychÓ);
$this->isLogin = true;
return AUTH_OK;
} else { //niepoprawny login lub hasþo
}
Gdy autoryzacja powiodþa siħ, kolejne piħę funkcji bħdzie zwracaþo
wartoĻę odpowiednich zmiennych z klasy Î
getName() Î $name,
getSurename() Î $surename, getLastLogin() Î $lastLogin
(sformato-
wane do postaci dzieı.miesiĢc.rok godzina:minuta:sekunda),
getAuthority() Î $authority, getEmail() Î $email
. Gdy autoryzacja nie
powiodþa siħ, wwczas funkcje te zwracajĢ false.
JeĻli jednak okazaþo siħ, Ňe liczba prb logowania na dane konto
przekroczyþa wþaĻnie liczbħ 3, a nie minħþo jeszcze 5 minut od ostat-
niej prby, wwczas obliczymy czas, po ktrym bħdzie moŇna siħ za-
logowaę (przez jaki czas konto bħdzie jeszcze zablokowane), a nastħp-
nie zwracamy wartoĻę
AUTH_3TIMES_ERROR
i koıczymy dziaþanie
funkcji
check(..)
.
function getName() {
if($this->isLogin)
return $this->name;
if(($this->tryCount>=3) && (($this->lastTry+300)>time())) {
$this->nextTry = (int)((($res[ÓlasttryÓ]+300)
Æ
-time())/60)+1;
return AUTH_3TIMES_ERROR;
} else {
else
return false;
}
function getSurename() {
if($this->isLogin)
return $this->surename;
Gdy liczba nieudanych prb logowania osiĢgnħþa juŇ 3, nato-
miast minħþo juŇ 5 minut zawieszenia konta, a podane hasþo po-
nownie jest niepoprawne, wwczas liczbħ prb ustawiamy na 1,
a datħ ostatniej nieudanej prby logowania ustawiamy na aktual-
nĢ. W ten sposb ta nieudana prba jest zliczona jako pierwsza
z trzech. Gdyby dwie kolejne teŇ okazaþy siħ nieudane, zapeþnio-
ny zostanie warunek opisany wczeĻniej i konto ponownie zostanie
zablokowane na 5 minut. Wwczas zwiħkszamy liczbħ prb
o jeden i ustawiamy aktualnĢ datħ jako datħ ostatniego nieudane-
go logowania.
else
return false;
}
function getLastLogin() {
if($this->isLogin)
return date(Ód.m.Y G:i:sÓ,$this->lastLogin);
else
return false;
}
function getAuthority() {
if($this->isLogin)
return $this->authority;
else
return false;
}
function getEMail() {
if($this->isLogin)
return $this->eMail;
else
return false;
}
Ostatnia funkcja klasy
cLogin
, w przypadku blokady konta, zwraca
czas do jego odblokowania. JeĻli konto nie jest zablokowane, zwraca
wartoĻę
false
.
p
Ekran pokazujĢcy okienko logowania z zablokowanym kontem
Î pozostaþy 3 min do odblokowania
function getNextTry() {
if($this->nextTry)
return $this->nextTry;
else
100
INTERNET.grudzieı.2004
C
M
Y
K
7
WARSZTAT
PROGRAMY
MAGAZYN
FIRMA
Z OKýADKI
NEWSY
NA CD
PHP
return false;
$flag = Ò3timesÓ;
break;
}
}
?>
JeĻli autoryzacja siħ powiodþa, metoda
check(..)
zwraca wartoĻę
AUTH_OK
. Zapisujemy wiħc do tablicy
$info
wszystkie istotne informacje
o logujĢcym siħ uŇytkowniku, nastħpnie tablicħ tħ przypisujemy do zmiennej
sesyjnej
info
. Ustawiamy odpowiednio zmiennĢ
$_SESSION[Ótest_loginÓ]
,
przypisujĢc jej adres komputera z ktrego nastĢpiþo logowanie. Na koniec
przekierowujemy uŇytkownika do strony, do ktrej chciaþ siħ zalogowaę.
Korzystanie z klasy cLogin
Gdy klasa
cLogin
zostaþa juŇ napisana, pora zaprezentowaę sposb
na korzystanie z niej. Jak juŇ wspomniaþem, autoryzacja bħdzie opar-
ta o sesje, ktrych obsþuga z poziomu PHP nie sprawia najmniej-
szych problemw. Sesje uruchamia siħ za pomocĢ funkcji
ses-
sion_start()
, ktra powinna byę wywoþana na poczĢtku pliku, w kt-
rym chcemy mieę do nich dostħp. W przykþadowym kodzie uŇyþem
biblioteki szablonw Smarty.
Na poczĢtku sprawdzamy czy mamy ustawionĢ sesjħ (zmienna
sesyjna, ktrĢ sprawdzamy ma nazwħ
test_login
). JeĻli sesja jest
ustawiona, sprawdzamy czy zawiera odpowiedniĢ wartoĻę (tj. po-
winna byę identyczna z adresem IP komputera uŇytkownika wcho-
dzĢcego na naszĢ stronħ). W przypadku speþnienia obu warunkw
przekierowujemy uŇytkownika na stronħ
index.php
(na niĢ chcemy
siħ zalogowaę).
JeĻli
$_SESSION[Ótest_loginÓ]
jest ustawiona na odpowiedniĢ war-
toĻę, oznacza to, Ňe uŇytkownik dokonaþ juŇ wczeĻniej autoryzacji.
case AUTH_OK:
$info = array(
ÓauthorityÓ => $login->getAuthority(),
Óe-mailÓ => $login->getEMail(),
ÓlastLoginÓ => $login->getLastLogin(),
ÓnameÓ => $login->getName(),
ÓsurenameÓ => $login->getSurename()
);
$_SESSION[ÓinfoÓ] = $info;
$_SESSION[Ótest_loginÓ] = $ip;
if(isset($_SESSION[Ótest_loginÓ])) {
if($_SESSION[Ótest_loginÓ]==$ip) {
header(ÓLocation: index.phpÓ);
exit;
header(ÓLocation: index.phpÓ);
exit;
break;
OstatniĢ wartoĻciĢ, ktrĢ moŇe zwrcię metoda
check(..)
, jest
AUTH_FALSE
, ktra oznacza, Ňe uŇytkownik podaþ niepoprawny
login lub hasþo. WyĻwietlamy wiħc odpowiedni komunikat.
}
}
$flag = ÓÓ;
JeĻli zmienna sesyjna nie byþa ustawiona, nasz skrypt wykona siħ
dalej. Sprawdzamy czy uŇytkownik kliknĢþ w formularzu logowania
input
Zaloguj siħ
. JeĻli tak zrobiþ, bħdĢ ustawione zmienne
$_POST[ÓloginÓ] oraz $_POST[ÓpasswdÓ]
.
case AUTH_FALSE:
$template->assign(Ótpl_loginErrorÓ, true);
$flag = ÓerrorÓ;
break;
}
}
if(isset($_POST[ÓloginÓ]) && isset($_POST[ÓpasswdÓ])) {
if(!($dbConnection = mysql_connect($mysql_host,
Æ
$mysql_user, $mysql_passwd)))
die(ÓNieudane poþĢczenie z bazĢ danychÓ);
Na koniec wyĻwietlamy ekran do logowania. Zostanie on wyĻwie-
tlony, gdy nie sĢ ustawione zmienne $_POST[ÒloginÓ] oraz
$_POST[ÒpasswdÓ] (czyli uŇytkownik nie kliknĢþ na input
zaloguj siħ
),
gdy wystĢpiþ bþĢd podczas logowania lub gdy nastĢpiþy pod rzĢd 3 nie-
udane prby logowania na jeden login.
if(!(mysql_select_db($mysql_db)))
die(ÓNieudane poþĢczenie z bazĢ danychÓ);
$template->display(Ólogin.tplÓ, $flag);
Tworzymy obiekt klasy cLogin, ktra zostaþa opisana wczeĻniej.
Nastħpnie korzystajĢc z jej metody
chack(..)
sprawdzamy, czy podany
login i hasþo sĢ poprawne.
$login = new cLogin($dbConnection);
switch($login->check($_POST[ÓloginÓ],
Æ
$_POST[ÓpasswdÓ])) {
JeĻli metoda
check(..)
zwraca
AUTH_3TIMES_ERROR
, ozna-
cza to, Ňe ktoĻ wykonaþ 3 nieudane prby logowania na ten sam
login. Spowodowaþo to zablokowanie loginu na 5 minut. Musimy
wiħc wyĻwietlię stosownĢ informacjħ (wraz z czasem za jaki
konto zostanie odblokowane Î czas podany z dokþadnoĻciĢ co do
minuty).
case AUTH_3TIMES_ERROR:
$template->assign(Ótpl_3timesÓ, true);
$template->assign(Ótpl_tryTimeÓ,
Æ
$login->getNextTry());
p
Przykþadowy ekran sþuŇĢcy do logowania
INTERNET.grudzieı.2004
101
C
M
Y
K
NA CD
NEWSY
Z OKýADKI
FIRMA
MAGAZYN
PROGRAMY
WARSZTAT
8
PHP
p
Zabezpieczona strona wraz z informacjami o zalogowanym uŇytkowniku. Informacje pobrane przez klasħ cLogin
Tak wyglĢda proces logowania siħ. NaleŇy jeszcze zabezpieczyę
kaŇdĢ ze stron, ktra nie powinna byę dostħpna dla osb niezalogowa-
nych. Robi siħ to bardzo þatwo.
}
Kod tutaj umieszczony wykona siħ, gdy uŇytkownik nie jest zalo-
gowany lub gdy zmienna sesyjna ma niepoprawnĢ wartoĻę.
<?php
session_start();
header(ÓLocation: login.phpÓ);
?>
if(isset($_SERVER[ÓREMOTE_ADDRÓ]))
$ip = ip2long($_SERVER[ÓREMOTE_ADDRÓ]);
Wylogowanie polega na zniszczeniu sesji, a najprostszy wykonujĢ-
cy to skrypt przedstawia siħ nastħpujĢco:
if(isset($_SESSION[Ótest_loginÓ])) {
if($_SESSION[Ótest_loginÓ]==$ip) {
<?php
session_unset();
session_destroy();
header(ÓLocation: login.phpÓ);
?>
Caþy zabezpieczony kod strony powinien byę umieszczony w tym
miejscu, jednak jeszcze przed instrukcjĢ
exit
. MoŇna teŇ umieĻcię tu
wywoþanie wþasnej funkcji i przenieĻę stĢd do niej kod generujĢcy
stronħ.
Propozycje rozbudowy
ZaprezentowanĢ tu klasħ moŇna jeszcze rozbudowaę. Na przykþad
kaŇde logowanie, nieudanĢ prbħ logowania, wylogowanie itd. powin-
no siħ zapisywaę w logu (moŇe to byę dodatkowa tabela w bazie da-
nych lub plik, jednak niedostħpny z poziomu przeglĢdarki, czyli
umieszczony poniŇej katalogu domowego przeznaczonego na strony,
np. public_http). MoŇna takŇe dodaę opcjħ banowania (blokowania)
wybranych adresw IP czy uŇytkownikw.
echo ÓzalogowanyÓ;
exit;
}
To wykona siħ, gdy zmienna sesyjna test_login bħdzie ustawio-
na, lecz juŇ niekoniecznie na zþĢ wartoĻę, co moŇe oznaczaę prbħ
wþamania.
n
102
INTERNET.grudzieı.2004
Plik z chomika:
nemo1206
Inne pliki z tego folderu:
PHP_i_MySQL.Tworzenie_stron_WWW.Vademecum_profesjonalisty-L.Welling__L.Thomson.pdf
(118461 KB)
PHP i MySQL - Tworzenie stron WWW - Vademecum profesjonalisty - wyd 3.part3(1).rar
(102400 KB)
PHP i MySQL - Tworzenie sklepów internetowych (Helion)(1).pdf
(597 KB)
PHP & MySQL.rar
(23206 KB)
video_kurs_php.rar
(264376 KB)
Inne foldery tego chomika:
najlepsze filmy(sex)!!
Pliki dostępne do 01.06.2025
!!! Fronda
!!! Muzyka Dyskografie rar
!!!!Polecam najnowszą wersją Kaspersky Internet Security 2010 - PL. +Nowe Klucze za free
Zgłoś jeśli
naruszono regulamin