Üdv!
Röviden az alapsztori:
"...éppen most írom a szakdolgozatomat. A feladat egy olyan webes alapú rendszer készítése, amelyen keresztül hallgatókat lehet felvenni egy adatnázisba (mysql adatbázis). A rendszernek a lényege, hogy azokat a hallgatókat akik elkezdték/befejezték/leadták stb... a szakdolgozatukat tudjuk kezelni elektronikusan, illetve nyomon tudjuk követni ki hol tart, valamint statisztikát lehessen készíteni pl hány PTI-s hallgató írt szakdogát 2010 második félévében. A lényeg, hogy az egésznek az alapja php, de mivel ez egy admin felület lesz (értsd: localhoston megy és csak jelszóval lehet bármilyen funkcióját is elérni) ezért úgy érzem, hogy itt megengedhető a js..."
Most éppen ott akadtam el, hogy nem szeretném, hogy a session lejárjon egy bizonyos idő után. De mivel a php.ini-ben a session.gc_maxlifetime = 1440 ezért 24 perc elteltével minden session törlődik...
Na de én azt szeretném, hogy a saját session-öm megmaradjon, ergo míg nem kattintok a kilépésre nem lépjen ki a rendszer, bár amikor kilépek akkor törlődhet a session! A legegyszerűbb megoldás az lenne, ha a php.ini-ben a session.gc_mxlifetime-ot levenném 0-ra, de ez azért mégis csak elég "brutális" a többi domain-el szemben. Tehát valami olyan kéne, hogy csak az én session-jeimre vonatkozzon a beállítás. Itt jön a képbe ez. Amint látjuk az ini_set("session.gc_maxlifetime", 24 * 3600); parancs önmagában még nem megoldás mert a garbage collector a többi domain miatt ugyanugy lezúzza az én session-ömet is. Én az első megoldást választottam vagyis saját könyvtárba rakom a session-ömet. Na most itt jön a képbe az amit még nem mondtam, hogy Debian rendszeren fut a szerver.
Idézet a php.net fórumából: http://hu2.php.net/manual/en/function.session-save-path.php#98106
"Debian does not use the default garbage collector for sessions. Instead, it sets session.gc_probability to zero and it runs a cron job to clean up old session data in the default directory.
As a result, if your site sets a custom location with session_save_path() you also need to set a value for session.gc_probability, e.g.:
<?php
session_save_path('/home/example.com/sessions');
ini_set('session.gc_probability', 1);
?>
Otherwise, old files in '/home/example.com/sessions' will never get removed!"
Vagyis Debian alatt nem is a gc végzi a piszkos munkát hanem a crontab? Hogy is van ez akkor?
Ami eddig van:
public function setSession() {
strstr ( strtoupper ( substr ( PHP_OS, 0, 3 ) ), "WIN" ) ? $sep = "\\" : $sep = "/";
$sessDir = ini_get ( "session.save_path" ) . $sep . "my_sessions";
if (! is_dir ( $sessDir )) {
mkdir ( $sessDir, 0777 );
}
ini_set ( "session.save_path", $sessDir );
}
Szerintem ez azért nem lesz jó mert az almappákba (/var/lib/php5/my_sessions/) Ugyanúgy benéz a crontab és a gc is és letörli a session-öket. A másik, hogy van ez a setSession() függvény, minden php oldalam ugyebár a session_start() hívással kezdődik, akkor ezt minden oldal elejére be kell elé vágnom, vagy csak az index.php? Ez sem teljesen tiszta.
Összegzés:
- Szeretném, hogy soha ne léptesse ki a rendszer a userem, viszont nem szeretném, hogy egy idő után sok sok "szemét" session legyen a könyvtáramban.
- Nem szeretnék semmit se piszkálni a szerver configban. (Ha feltöltöm akármilyen szerverre a rendszerem működjön állítgatás nélkül)
Szóval ez ügyben kérném a segítségeteket.
MEGOLDÁS:
A megoldás végül az lett, hogy a session-t adatbázisban tároltam. Leírom részletesen az egészet, hátha valakinek még jó lesz (ha más nem nekem dokumentáció céljából :)) Az egészet rootkit leírása alapján csináltam (ezért köszönet neki) némi változtatással.
MySQL táblák felépítése:
mysql> desc users;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| user_id | int(11) | NO | PRI | NULL | auto_increment |
| logname | varchar(20) | YES | | NULL | |
| logpass | varchar(32) | YES | | NULL | |
+---------+-------------+------+-----+---------+----------------+
mysql> desc manage_session;
+-----------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| sess_id | varchar(32) | NO | PRI | NULL | |
| user_id | int(11) | YES | MUL | NULL | |
| lastlogin | datetime | YES | | NULL | |
+-----------+-------------+------+-----+---------+-------+
mysql> select * from users;
+---------+---------+----------------------------------+
| user_id | logname | logpass |
+---------+---------+----------------------------------+
| 2 | phppityu| 1337123456re4343szupertitkosmd5 |
+---------+---------+----------------------------------+
mysql> select * from manage_session;
+----------------------------------+---------+---------------------+
| sess_id | user_id | lastlogin |
+----------------------------------+---------+---------------------+
| 412732ewsdsd32ds323232ffds31dshr2| 2 | 2010-09-16 15:22:16 |
+----------------------------------+---------+---------------------+
Itt érdemes megemlíteni a manage_session tábla létrehozását (adtam nevet a függőségnek a későbbi könnyebb módosítás édekében):
create table manage_session( sess_id varchar(32) not null, user_id
INTEGER, lastlogin DATETIME, PRIMARY KEY (sess_id), CONSTRAINT
fk_userid_id FOREIGN KEY(user_id) REFERENCES users(user_id));
Akkor most jöjjenek a php-s részek:
Az általam használt függvények:
public function Login() {
if (! empty ( $_POST )) {
$logname = $_POST ['logname'];
$logpass = $_POST ['logpass'];
}
if (! empty ( $logname ) && ! empty ( $logpass )) {
$logname = addslashes ( $logname );
$logpass = md5 ( $logpass );
$check = " SELECT user_id FROM users WHERE (logname='" . $logname . "' AND logpass='" . $logpass . "') ";
try {
$result = connectToDb::getInstance ()->query ( $check );
} catch ( PDOException $e ) {
echo $e->getMessage ();
}
if ($result->rowCount () !== 0) {
foreach ( $result as $row ) { $user_id = $row ['user_id'];}
$_SESSION['user_id'] = $user_id;
$sess_id = session_id ();
$replace = "REPLACE INTO manage_session (sess_id,user_id,lastlogin) VALUES ('" . $sess_id . "','" . $user_id . "', NOW() )";
$result = connectToDb::getInstance ()->query ( $replace );
header ( "Location: /szakdoga/new/useriface.php" );
}
}
}
public function isLogged() {
session_set_cookie_params ( 3600 * 24 * 365 ); //egy év
session_start ();
if (empty ( $_SESSION ['user_id'] )) {
$sess_id = session_id ();
$check = "SELECT user_id FROM manage_session WHERE sess_id = '" . $sess_id . "' ";
try {
$result = connectToDb::getInstance ()->query ( $check );
} catch ( PDOException $e ) {
echo $e->getMessage ();
}
foreach ( $result as $row ) { $user_id = $row ['user_id']; }
if ( $user_id > 0) {
$_SESSION['user_id'] = $user_id;
} else {
header ( 'Location: /szakdoga/new/index.php' );
exit ();
}
}
}
public function delSess()
{
$sess_id = session_id ();
$del_sess = "DELETE FROM manage_session WHERE sess_id = '".$sess_id."'";
try {
$result = connectToDb::getInstance ()->query ( $del_sess );
} catch ( PDOException $e ) {
echo $e->getMessage ();
}
}
A Login() fgv-t az index.php-ban hívom meg, az isLogged()-et minden védett oldal legelején, a delSess()-t pedig a logut.php-ban.
Ha van benne valami hiba, backdoor vagy bug akkor pls szóljatok.
Köszi mégegyszer rootkit-nek!
szerk: Azért nem raktam a kódot fel valamilyen pastebin oldalra. Mert azt tapasztaltam, hogy mikor olvasok mondjuk egy 2 éves postot akkor az esetek 99%-ban, az ott lévő linkek már halottak lesznek. Így meg legalább megmarad, úgyse zavar senkit.
- 1394 megtekintés
Hozzászólások
- A hozzászóláshoz be kell jelentkezni
Lehet akkor nem a jó eszközt használtam a probléma megoldására. Tehát a cookie ugye kliens oldalon tárolódik most így néz ki a rendszerem: http://pastebin.com/i0KiaJbD
Akkor a 'login' változót nem sessionbe hanem a cookiba kéne tárolni? De akkor nem lehetséges az, hogy fogja a user és a cookie-ban a login-t átírja 1 re és meg van oldva, vagy nem manipulálható? Akkor mire jó a session? Mind a kettőnek értem a működését, csak még azt nem látom, hogy melyik milyen funkciót lát el. Esetleg tudnál te vagy valaki más példát írni, hogy mégis hogy használjuk egyszerre a kettőt?
szerk:
Most van a cookie-m amiben benne van a session_id. Tehát amit a szerveren tárolok session-öket abból megnézi melyik az enyém és megnézi hogy abban mi van. Ha az én session-öm tartalma login:1 akkor beenged ha nem akkor nem. Ez így tökéletes, nem azzal van a baj hogy a cookie tűnik el mert az megmarad a gépen, hanem hogy a session jár le.
- A hozzászóláshoz be kell jelentkezni
Gondolom a "login" utáni "1" itt a felhasználói azonosító.
- A hozzászóláshoz be kell jelentkezni
A login utáni 1 arra utal hogy be van e éppen léptetve vagy nem.
- A hozzászóláshoz be kell jelentkezni
És honnan tudod, hogy ki van beléptetve? Egy másik cookie-ban utazik a userid? Vagy ez nem fontos?
Egyébként még mindig az adatbázist javaslom neked. Ilyen hosszú távú session-öket ott szokás tárolni.
Ezt nézd meg: session_set_save_handler
- A hozzászóláshoz be kell jelentkezni
Gondolom dbben tarolod a user adatokat. Keszitesz meg 1 tablat remember_me neven, amiben lerakod a useridjat, az ip cimet, meg valami kulcsot, amit utana leraksz sutiben es kesz. Ha ip es a kulcs egyezik, a usert be lehet leptetni, amugy meg nem, ha megfejeled meg 1 timestamppel, akkor lehet ra siman expiret is rakni, oszt csokolom.
Bar teny, hogy megoldhato session handler izelasssal is.
- A hozzászóláshoz be kell jelentkezni
És ez mindig is ilyen körülményes volt? :) Vagy mindenki így csinálja? Nincs valami bevett szokás?
- A hozzászóláshoz be kell jelentkezni
Ellenőrizd, hogy a session-cookie-k expire-ra nagyon hosszú.
Tárold adatbázisban a session adatokat.
Egyébként igen. Alapból egy cron folyamat takarítja a session-fájlokat mtime alapján.
Azért nem lesz egy idő után nagyon sok szemét, mert én az adott felhasználóhoz tárolnám le a session-t (meg annak azonosítóját is). Azaz nem lehetne több session-adat, mint felhasználó. Így felhasználó munkafolyamata csak 1 gépen "tárolódna" egyszerre és egy gépen csak 1 felhasználó munkafolyamata "tárolódna".
Remélem érthető volt.
- A hozzászóláshoz be kell jelentkezni
Ezt kifejtenéd egy kicsit bővebben mert nem volt teljesen világos. A következő képen néz ki most a users táblám (akik beléphetnek):
id | logname | logpass (md5 el kodolva)
1 phppisti pityu23
Nézzük akkor gyakorlatban. Van a session_start() hívás ami fogja legenerál egy sess_123454532 file-t, ha nem létezik. Ezt berakja a cookie-ba, mármint csak ezt a file nevet. Nálam így néz ki a cookie: PHPSESSID a süti neve és a tartalma sess_123454532. Ezzel párhuzamban fogja és a szerveren a /var/lib/php5 alá létrehozza a sess_12345453 file-t. Ez kezdetben üres, majd mikor bejelentkezek akkor a tartalma login=1 re vált. Mindig amikor egy jelszóval védett oldalt akarok lekérni megnézi a sütiben tárolt sess_id-t, majd benéz a /var/lib/php5 alá, hogy van e ilyen file, ha van megnézi a tartalmát, ha login=1 megnézhetem az oldalt. Kilépéskor ennek a file-nak a tartalmát módosítom login=0 ra.
Kérdés: Hogyan nézzen ez ki MySQL es megoldással? Legyen plusz 2 oszlop a users-be, egy sess_id meg egy login_state? És akkor mindig mikor be akarok lépni, vagy meg akarok nézni egy jelszóval védett oldalt kérjem le a users tábla login_state állapotát, majd mikor kilépek upateeljem 0 ra? A sess_id statikus legyen (pl sess_phppisti) és cookie ba ezt rakjam be? Majd beléptetésnél:
SELECT login_state from uses WHERE sess_id=$_COOKIE[sess_id];
Így gondoltad vagy félre értettem? Ez nekem így elég macerásnak tűnik, szerintem nem így gondoltad és én értettem félre.
szerk: Nem is rossz ötlet, ezt így megoldani... :D Most már tényleg kíváncsi vagyok a te megoldásodra is. Esetleg konkrét példával, táblával. :)
szerk2: Mire jó akkor a $_SESSION? Pár oldalon át hordozni néhány adatot, vagy...?
- A hozzászóláshoz be kell jelentkezni
Nézd meg ezt: http://php.net/manual/en/function.session-set-cookie-params.php
Állítsd a cookie-t jó hosszúra, mondjuk 5 évre.
SEMMIT SEM ELLENŐRIZTEM, SZÓVAL LEHET BENNE HIBA!!! Az SQL-es részek nincsenek mindenhol kifejve PHP-ben.
Ahogy a kolléga már leírta:
CREATE TABLE remember_me
(
sessid CHAR(32) NOT NULL,
userid INTEGER,
lastlogin DATETIME,
PRIMARY KEY (sessid),
KEY (userid)
)
Sikeres login esetében:
$_SESSION['userid'] = [a-beloginolt-júzer-ájdíja];
$sess_uid = (int) $_SESSION['userid'];
"REPLACE INTO remember_me SET sessid = '".mysql_escape_string(session_id())."', userid = $sess_uid, lastlogin=NOW()"
Időnként lehet takarítani a lastlogin alapján, ha nem lépett be már hónapok óta, akkor mehet a levesbe a remember_me táblából.
Ha kilépést nyom:
"DELETE FROM remember_me WHERE sessid = '".mysql_escape_string(session_id())."'"
Ha törölsz egy felhasználót:
"DELETE FROM remember_me WHERE userid = $sess_uid"
csinálsz egy session.inc fájlt, amit minden oldal elején behúzol (kivéve login.php !!!) és beleírod ezt:
<?php
session_set_cookie_params([ide-kell-valami-jó-nagy-expire]);
session_start();
$sess_uid = (int) @$_SESSION['userid'];
if ($sess_uid <= 0)
{
"SELECT userid FROM remember_me WHERE sessid = '".mysql_escape_string(session_id())."'"
if ($row->userid > 0)
{
$sess_uid = (int) $row->userid;
$_SESSION['userid'] = $sess_uid;
}
else
{
header('Location: login.php');
exit;
}
}
?>
- A hozzászóláshoz be kell jelentkezni
á_ll_talában?
t
- A hozzászóláshoz be kell jelentkezni
Sose ment a nyelvtan... :)
- A hozzászóláshoz be kell jelentkezni
Vagy csinálsz egy ajax requestert, ami pl. 10 (vagy legyen akár 15) percenkét csinál egy semmi php aktivitást: a session_start() legyen benne, és annyi.
Ha már "mersz" JS-t használni.
Persze ezt csak akkor, ha mást nem akarsz megcsinálni, mert ez kicsit barkács. :)
- A hozzászóláshoz be kell jelentkezni
raadasul nem teljes megoldas, mert amikor ejszaka a tisztelt user kinyomja a gepet, reggel megint csak nem lesz bejelentkezve
- A hozzászóláshoz be kell jelentkezni