Ü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.