webForumDet fria alternativet

session_cache_expire() hos Binero

25 svar · 2 009 visningar · startad av MickeA.com

MickeA.comMedlem sedan feb. 20034 528 inlägg
#1

Hej,

Jag lyckas inte sätta längden på hur länge mina sessioner ska leva. Sidan ligger hos Binero (Unix).

Högst upp en fil som inkluderas överallt kör jag:

session_cache_expire(60);
session_start();

Men ändå så dör sessionen efter ~20min.
När jag testar det här:

echo session_cache_expire();

...så skrivs "60" ut, men ändå så dör dom.

Förslag på hur jag ska lösa det här?

Tack!

drewMedlem sedan mars 2007748 inlägg
#2

Det fanns en bug-rapport om detta. Men den buggen fixades 1 Aug 2006.

Du kanske skulle påpeka att det är dags för en uppgradering.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#3

drew skrev:

Du kanske skulle påpeka att det är dags för en uppgradering.

Påpeka det för Binero?

drewMedlem sedan mars 2007748 inlägg
#4

Om det är Binero du ligger hos så är det hos dom felet finns.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#5

Jag har mailat dom, får se vad som svarar.

Tack!

MickeA.comMedlem sedan feb. 20034 528 inlägg
#6

MickeA.com skrev:

Jag har mailat dom, får se vad som svarar.Tack!

Binero Support skrev:

Följande är satt i php.ini filen:

session.gc_maxlifetime 1440

Alltså 24 minuter, om man vill ha högre så kanske man bör fundera att använda cookies istället för sessioner på servern.

Det här kan ju inte stämma, oavsett vad som står i INI filen så ska ju värdet gå att ändra, eller hur?

Att använda vanliga kakor i ett system med inloggning, där sessionerna innehåller info om vem som är inloggad och vilka behörigheter man har, det verkar ju sjukt dumt.

Session är ju dessutom en sorts kaka.

drewMedlem sedan mars 2007748 inlägg
#7

Ge sessionen ett id och lägg det i kakan tillsammans med ip-adressen. Sen sparar du resten i databasen i en sessionstabell.

Jag har för mig att session.gc_maxlifetime är just en maxtid. Du kan sätta lägre men inte högre.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#8

Aha, okej.. det här suger ju.. Blir en hel del att göra om med andra ord..
Jag använder en sessionsklass som initieras på varje sida.

Om jag ska gå efter ditt tips så kanske det är lättast att bygga in den här funktionaliteten i min klass? Ge gärna lite exempel kod för nu kändes precis som om jag är tillbaka på steg 0 igen.

Tack,

MickeA.comMedlem sedan feb. 20034 528 inlägg
#9

Jag googlade lite mer och kom fram till att det fick att lösa genom HTACCESS.
Lägg det här i en .htaccess fil:

php_value session.gc_maxlifetime 3600
php_value session.save_path "PATH/TO/SESSIONS"

Lägg SESSIONS mappen utanför wwwroot och sätt chmod 777 SESSIONS så funkar det fint.

Skapa en fil med <?php phpinfo();?> och gå till den.
Gå ner till avsnittet SESSIONS och kolla värdet på "session.gc_maxlifetime" så står det:

----
Variable			Local value	Master value
session.gc_maxlifetime		3600		1440
----

Jag har testat nu och mina sessions lever längre än 24minuter, så det verkar funka.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#10

MickeA.com skrev:

php_value session.gc_maxlifetime 3600
php_value session.save_path "PATH/TO/SESSIONS"

Nu har jag enormt stora problem med det här igen.
Binero har på sina nya servrar förbjudit att sätta php_value i .htaccess så det här sättet fungerar inte längre.

På sidan som ligger på den här servern (Spirou) så död sessionerna varannan minut ungefär, så något är sjukt galet.

Exakt samma kod finns på Majestix och där funkar allt kanon, så koden är det inte fel på.

Jag förstår inte riktigt hur jag ska lösa det här, någon som vet?

Tack!

drewMedlem sedan mars 2007748 inlägg
#11

Be att få båda sidorna på Majestix eller byt hotell.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#12

drew skrev:

Be att få båda sidorna på Majestix eller byt hotell.

Vad kan anledningen vara att dom gjort såhär?

Du skrev tidigare:

Ge sessionen ett id och lägg det i kakan tillsammans med ip-adressen. Sen sparar du resten i databasen i en sessionstabell.

Kan du förklara lite mer ingående vad jag måste göra, är inte riktigt med.

Tack,

drewMedlem sedan mars 2007748 inlägg
#13

Varför dom gjort så vet bara dom.
Jag flyttade därifrån för att det påminde för mycket om Proinet (om någon kommer ihåg den) och deras usla kontrollpanel (dom sa att den skulle bytas ut när jag sa upp tjänsten).

Du skapar en sessions-tabell i databasen som innehåller ex användarnamn, tid för inloggning, tid för senaste uppdatering, sessions id och diverse annan intressant information.
Du antas redan ha en tabell för användare (user_id, user_name, password ...)

När du loggar in på sidan så startar du sessionen med session_start(); och hämtar id't med $sid = session_id(); och sätter en kaka som du ex kalla "session" och du stoppar in $sid i den. Sen stoppar du in den i din databas, med tiden för inloggning och tiden för senaste uppdatering.
På alla sidor sen så kollar du om kakan "session" finns och om den innehåller ett session_id som finns i din databas och att tiden för att vara inloggad inte gått ut. Om den är godkänd så uppdaterar du tiden för senaste uppdatering och gör inget mer. Om tiden gått ut är personen inte inloggad.
Vid utloggning så raderar du raden i databasen och tar bort kakan (sätter utgångstiden till nyss).
Någonstans kör du en koll så att det inte finns sessionsrader som är förfallna i databasen och fyller den i onödan.

Jag är säker på att det finns flera exempel någonstans på nätet. Men kommer inte på vad du ska Googla på.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#14

Tack tack,
Ska se först vad Binero svarar, men jag tror att jag kör med din metod också, kan ju vara bra.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#15

Jag håller på och bygger om enligt drew's exempel ovan och har en fråga..
För att slippa eventuella framtida problem så tänkte jag köra på den här metoden istället för sessions.

Är det fortfarande att rekommendera att skapa en session, ta dess id och sen köra vidare med endast en kaka, eller kan jag med hjälp av en funktion eller dylikt skapa den unika stängen som jag sparar i databasen?

Är det dåligt ur säkerhetsperspektiv? Rent spontant känns det bättre att skapa en cookie och låta PHP generera id't åt mig, men är osäker så kom gärna med förslag.

Tack,

drewMedlem sedan mars 2007748 inlägg
#16

Det finns flera sätt att skapa sessions id, det viktiga är att det är ett unikt id. Du har ju samma id i databasen och jämför med ip't. Om både sessions_id och ip stämmer så kan du lita på att det är samma dator. Glöm inte att kolla och uppdatera tiden för senaste aktivitet. Du ska inte ha hur långa sessioner som helst.
Och vid manuell utloggning så raderar du sessionsraden från databasen så går det inte att återanvända. Och ditt cron-skript ska också radera gamla rader för att inte fylla databasen i onödan.

MickeA.comMedlem sedan feb. 20034 528 inlägg
#17

Just nu sparar jag inte ip överhuvudtaget, men självklart ska det läggas till.
Det jag gör nu är att jag skapar en session och tar emot session_id(), det får vara så tills vidare.

Min kaka kommer leva i en timma ungefär. Jag rensar automatiskt gamla rader (> 60min) vid varje ny inloggning, så jag tror inte att ett cronjob behövs. Det rullar riktigt bra nu, ska kolla så att kakan "dör" efter 60 min bara.

Tack,

MickeA.comMedlem sedan feb. 20034 528 inlägg
#18

Jag har lite problem nu. Det är så att tidigare använde jag två klasser (Session/Auth) för att:

- Logga in användare
- Logga ut användare
- Kolla behörigheter/åtkomst

Jag har byggt om dom här två, så att dom ser ut såhär:

<?php
define("cookieName", "myCookie");

class Auth {
	var $userName;
	var $userPassword;
	var $session;
	var $hashKey;

	/**
	* Auth constructor
	* Checks for valid user automatically
	* @param object database connection
	* @param string URL to redirect to on failed login
	* @param string key to use when making hash of user name and
	*               password
	* @param boolean if passwords are md5 encrypted in database
	*               (optional)
	* @access public
	*/

	function Auth($userName = '', $userPassword = '', $md5 = TRUE, $hashKey = 'jPDVDVdvdvDVhhy565466%¤&65&%¤&¤%/(/(,rN.W2y5vzFzzVAhHa.3sw'){
		$this->userName  = $userName;
		$this->userPassword  = $userPassword;
		$this->userAdminLevel  = 0;
		$this->md5  = $md5;
		$this->hashKey  = $hashKey;
		$this->session  = &new Session();
		$this->login();   
	}

	/**
	* Checks username and password against database
	* @return void
	* @access private
	*/
	function login(){
		if($this->confirmAuth()){
			return true;
		}

		$login = mysql_real_escape_string($this->userName);
		if($this->md5){
			$password = mysql_real_escape_string(md5($this->userPassword));
		}else{
			$password = mysql_real_escape_string($this->userPassword);
		}
		
		// Query to count number of users with this combination
		$query = "SELECT COUNT(*) AS num_users "
				."FROM " . USER_TABLE . " "
				."WHERE " . USER_TABLE_LOGIN . " = '" . $login . "' "
				."AND " . USER_TABLE_PASSW . " = '" . $password ."'";
		
		// echo $query  . "<br />\n";
		$result = mysql_query($query) or die(mysql_error());
		$row = mysql_fetch_assoc($result);

		// If there isn't is exactly one entry
		if ($row['num_users'] != 1){
			return false;
			
			// Else it's a valid user; set the session variables
		}else {
			$this->storeAuth($login, $password);
		}
	}

	/**
	* Sets the session variables after a successful login
	* @return void
	* @access protected
	*/
	function storeAuth($login, $password) {
		//Take out user id from database
		$query = "SELECT user_id, user_group " 
				."FROM " . USER_TABLE . " "
				."WHERE " . USER_TABLE_LOGIN . " = '$login'";

		$result  = mysql_query($query) or die(mysql_error());
		$userid  = mysql_result($result, 0, 0);
		$groupid = mysql_result($result, 0, 1);
		mysql_free_result($result);

		$this->session->set(USER_USERID_VAR, $userid);
		if(!(setcookie(cookieName, $this->session->sessid(), time() + 3600)))
			die("Couldn't set cookie, please contact site admin.");
		
		$query = "INSERT INTO user_session "
				."(sess_session, sess_user, sess_group, sess_page, sess_ipaddr, sess_browser, sess_login, sess_refresh) "
				."VALUES "
				."("
				."'" . $this->session->sessid() . "', "
				."" . $userid . ", "
				."" . $groupid . ", "
				."" . $this->getPageId(basename($_SERVER['PHP_SELF'])) . ", "
				."'" . $_SERVER['REMOTE_ADDR'] . "', "
				."'" . $_SERVER['HTTP_USER_AGENT'] . "', "
				."UNIX_TIMESTAMP(), "
				."UNIX_TIMESTAMP()"
				.")";
		mysql_query($query) or die("Couldn't save data to session table, please contact site admin.\\n " . mysql_error() . $query);
		return true;
	}

	/**
	* Confirms that an existing login is still valid
	* @return void
	* @access private
	*/
	function confirmAuth(){
		if(!isset($_COOKIE[cookieName]))
			return false;

		$query = "DELETE FROM user_session "
				."WHERE DATE_ADD(FROM_UNIXTIME(sess_refresh, '%Y-%m-%d %H:%i:%s'), INTERVAL 60 MINUTE) >= CURRENT_TIMESTAMP";
		mysql_query($query) or die("Couldn't prune session table, please contact site admin");

		$authCookie = safesql($_COOKIE[cookieName]);
		$query = "SELECT "
				."COUNT(sess_id) "
				."FROM user_session "
				."WHERE sess_session = '" . $authCookie . "' "
				."LIMIT 1";

		$result = mysql_query($query) or die(mysql_error());
		if(!(mysql_num_rows($result) == false)){
			$query = "UPDATE user_session SET "
					."sess_refresh = UNIX_TIMESTAMP() "
					."WHERE sess_session = '" . $authCookie . "' "
					."LIMIT 1";
			mysql_query($query) or die("Couldn't update session table, please contact site admin");
			if(!(mysql_affected_rows() == -1)){
				return true;
			}else{
				return false;
			}
			return false;
		}else{
			return false;
		}
		mysql_free_result($result);
	}
}
?>

Min inloggning:

<?php
$username = safesql($_POST['username']);
$userpass = safesql($_POST['passwd']);
$return	  = safesql($_POST['return']);

/* ask for mandatory data or print an error if missing
------------------------------------------------------*/
if(strlen($username) <= 0){
	$error[] = "Ange ditt användarnamn";
}
if(strlen($userpass) <= 0){
	$error[] = "Ange ditt lösenord";
}else{

	/* Check authorization
	------------------------------------------------------*/
	$auth = new Auth($username, $userpass);
	
	if(!($auth->confirmAuth())){
		$error[] = "Du angav ett felaktigt användarnamn eller lösenord";
	
	}else{
		if(!write_to_log("user_log", $session->get("userid"), $_SERVER['REMOTE_ADDR'], 2, "n/a", $_SERVER['HTTP_USER_AGENT']))
			send_errorreport(basename($_SERVER['PHP_SELF']), __LINE__, "Error when writing to log", "");

		/* User logged in, redirect to splashscreen
		------------------------------------------------------*/
		echo "200|Success";

	}
}
?>

Problemet är att vi första inloggning ges meddelandet "Du angav ett felaktigt användarnamn eller lösenord". Grejen är att kakan + raden i sessionstabellen skapas, så allt funkar.

Trycker jag F5 så är jag inne, utan problem.
Det här är det enda som återstår, så jag vore sjukt tacksam om någon kunde hitta felet i koden ovan.

Verkar som sagt som om $auth->confirmAuth(); inte returnerar bool(true) första gången den anropas.

Tack!

MickeA.comMedlem sedan feb. 20034 528 inlägg
#19

Nu testade jag att lägga det här i en fil:

<?php
setcookie("foo", "doo");

print_r($_COOKIE);
?>

Och det blir samma här, måste ladda om sidan för att kakan ska visas.
Det är alltså förklaringen till mitt problem ovan, men hur kommer jag runt det?

Går det inte att läsa en cookie strax efter att man satt den, utan att ladda om sidan?

MickeA.comMedlem sedan feb. 20034 528 inlägg
#20

Har kommit på hur jag "kan" lösa det.
Jag skulle ju kunna använda mig av $this->session->sessid() även i confirmAuth(), men då är ju grejen att jag använder sessions (som time'ar ut) istället för kakan.

Skulle man kunna kolla att om:
- Kakan finns, använd den
- Om kakan inte finns, använd $this->session->sessid()
- Om varken kakan eller $this->session->sessid() finns, logga ut och "börja om".

Kan det vara en lösning?

Genererad på 624 ms · cache AV · v20260730165559-full.f96bc7eb