[PHP/MySQL] sessies in db, sessiedata leeg op andere pagina

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • siggy
  • Registratie: Juni 2001
  • Laatst online: 27-05 12:07

siggy

Wait.... what?

Topicstarter
Ik ben al een tijdje uit PHP geweest en het werken met normale sessies in een bestand op de server werkt zonder problemen. Maar ik wil de sessies in een database hebben. Daarvoor heb ik de onderstaande class van internet geplukt.

De sessie maak ik aan met:

PHP:
1
2
require_once("sessions.php");
$session = new Session();


Ik zie ook in de tabel die ik hiervoor heb aangemaakt dat de data erin kom als ik $_SESSION['user_name'] = "blaat"; doe.

Zodra ik echter naar een andere pagina ga, op wat voor manier dan ook, dan wordt het dataveld in de tabel geleegd zodra ik $session = new Session(); uitvoer. Doe ik dit niet, dan blijft de data in de tabel staan, maar krijg ik met echo $_SESSION["user_name"] niks terug. Tot zover heb ik met trial en error het probleem weten op te sporen, maar geen idee hoe ik dit kan oplossen. Op andere fora wordt aangegeven dat exact dezelfde code gewoon wel werkt.

Ik weet niet wat er fout gaat. Zover ik begrijp zou je met deze class sessies kunnen handlen zoals sessies normaal behandeld worden.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
<?php

class Session
{
  private $alive = true;
  private $dbc = NULL;
 
  function __construct()
  {
    session_set_save_handler(
      array(&$this, 'open'),
      array(&$this, 'close'),
      array(&$this, 'read'),
      array(&$this, 'write'),
      array(&$this, 'destroy'),
      array(&$this, 'clean'));
 
    session_start();
  }
 
  function __destruct()
  {
    if($this->alive)
    {
      session_write_close();
      $this->alive = false;
    }
  }
 
  function delete()
  {
    if(ini_get('session.use_cookies'))
    {
      $params = session_get_cookie_params();
      setcookie(session_name(), '', time() - 42000,
        $params['path'], $params['domain'],
        $params['secure'], $params['httponly']
      );
    }
 
    session_destroy();
 
    $this->alive = false;
  }
 
  private function open()
  {    
       
      require('serverinfo.php');
      $this->dbc = new MYSQLi($dbhost, $dbuser, $dbpass, $dbname)
      OR die('Could not connect to database.');
 
    return true;
  }
 
  private function close()
  {
    return $this->dbc->close();
  }
 
  private function read($sid)
  {
    $q = "SELECT `session_data` FROM `sessions` WHERE `session_id` = '".$this->dbc->real_escape_string($sid)."' LIMIT 1";
    $r = $this->dbc->query($q);
 
    if($r->num_rows == 1)
    {
      $fields = $r->fetch_assoc();
 
      return $fields['data'];
    }
    else
    {
      return '';
    }
  }
 
  private function write($sid, $data)
  {
    $q = "REPLACE INTO `sessions` (`session_id`, `session_data`) VALUES ('".$this->dbc->real_escape_string($sid)."', '".$this->dbc->real_escape_string($data)."')";
    $this->dbc->query($q);
 
    return $this->dbc->affected_rows;
  }
 
  private function destroy($sid)
  {
    $q = "DELETE FROM `sessions` WHERE `sessions_id` = '".$this->dbc->real_escape_string($sid)."'"; 
    $this->dbc->query($q);
 
    $_SESSION = array();
 
    return $this->dbc->affected_rows;
  }
 
  private function clean($expire)
  {
    $q = "DELETE FROM `sessions` WHERE DATE_ADD(`last_accessed`, INTERVAL ".(int) $expire." SECOND) < NOW()"; 
    $this->dbc->query($q);
 
    return $this->dbc->affected_rows;
  }
}
?>

"I don't take life too seriously, no one gets out alive anyways..."


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

En nu wil je dat wij een class voor je gaan debuggen die je zelf niet geschreven hebt? Wat zegt de schrijver van de code?

Er zijn twee regels die data uit je DB kunnen gooien. De ene wordt aangeroepen bij een session_destroy (de destroy-functie) en de andere als de garbage collector voorbij komt (de clean-functie). Die laatste klinkt als de boosdoener, ga die eens debuggen. ;)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • siggy
  • Registratie: Juni 2001
  • Laatst online: 27-05 12:07

siggy

Wait.... what?

Topicstarter
NMe schreef op dinsdag 03 januari 2012 @ 13:46:
En nu wil je dat wij een class voor je gaan debuggen die je zelf niet geschreven hebt? Wat zegt de schrijver van de code?

Er zijn twee regels die data uit je DB kunnen gooien. De ene wordt aangeroepen bij een session_destroy (de destroy-functie) en de andere als de garbage collector voorbij komt (de clean-functie). Die laatste klinkt als de boosdoener, ga die eens debuggen. ;)
Thanks. Sorry dat het zo overkomt.

"I don't take life too seriously, no one gets out alive anyways..."


Acties:
  • 0 Henk 'm!

Verwijderd

waarom wil je je sessies in een DB hebben?
Bied een cookie geen uitkomst?

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
siggy schreef op dinsdag 03 januari 2012 @ 13:36:
Tot zover heb ik met trial en error het probleem weten op te sporen, maar geen idee hoe ik dit kan oplossen.
Het lijkt me een erg goed idee om dit eens met ons te delen.

Edit:
Inderdaad niet meer van toepassing

[ Voor 64% gewijzigd door CurlyMo op 04-01-2012 00:39 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Hij zegt dat zijn tabel geleegd wordt, dat komt niet overeen met gek replace into-gedrag, toch?
Verwijderd schreef op dinsdag 03 januari 2012 @ 22:12:
waarom wil je je sessies in een DB hebben?
Bied een cookie geen uitkomst?
Sessies in je database kunnen wel degelijk voordelen hebben, bijvoorbeeld het overnemen van een sessie (oftewel: impersonaten) door een admin of het remote kunnen uitloggen van sessies die gekaapt zijn danwel remote uit laten loggen door admins.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
NMe schreef op dinsdag 03 januari 2012 @ 22:46:
Sessies in je database kunnen wel degelijk voordelen hebben, bijvoorbeeld het overnemen van een sessie (oftewel: impersonaten) door een admin of het remote kunnen uitloggen van sessies die gekaapt zijn danwel remote uit laten loggen door admins.
Nr 1 reden voor sessies in de DB: Load balancing :Y)
En dan wil je dit misschien wel even lezen: http://www.mysqlperforman...-files-vs-database-based/

[ Voor 13% gewijzigd door RobIII op 03-01-2012 22:56 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
NMe schreef op dinsdag 03 januari 2012 @ 22:46:
Hij zegt dat zijn tabel geleegd wordt, dat komt niet overeen met gek replace into-gedrag, toch?
Zo ziet mijn class eruit, heb degene die jij hebt gebruik geprobeerd maar daarbij werkte überhaupt de session_destroy niet bij mij.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<?PHP
class session
    {
    var $iLifeTime;
    var $iSessionId;
    
    function session()
        {
        $this->iLifeTime = 1;
        $this->connect();
        }   
    
    function connect()
        {
        }
        
    function open($sSavePath, $sSessionName)
        {
        $this->gc($this->iLifeTime);
        $this->write(session_id(),'',1);
        return true;
        }
        
    function close()
        {
        return true;
        }
    
    function read($sSessionId)
        {
        $rSelect = mysql_query("SELECT data FROM session WHERE name = '".mysql_real_escape_string($sSessionId)."'",SQL_CONNECTION);
        $iRows = mysql_num_rows($rSelect);
        if($iRows == 0)
            return true;
        else
            {
            $aData = mysql_fetch_assoc($rSelect);
            return $aData['data'];
            }
        }
        
    function write($sSessionId, $sVal, $bOpen=0)
        {
        $rSelect = mysql_query("SELECT data FROM session WHERE name = '".mysql_real_escape_string($sSessionId)."'",SQL_CONNECTION);
        $iRows = mysql_num_rows($rSelect);

        if($iRows == 0)
            {
            $rInsert = mysql_query("INSERT INTO session VALUES (DEFAULT,
            '".mysql_real_escape_string($sSessionId)."',
            NOW(),
            '".mysql_real_escape_string($sVal)."')") or die(mysql_error());
            }
        else if(!$bOpen)
            {
            $rInsert = mysql_query("UPDATE session SET expires = NOW(), data = '".mysql_real_escape_string($sVal)."' WHERE name = '".mysql_real_escape_string($sSessionId)."'",SQL_CONNECTION);
            }
        return true;
        }
    
    function destroy($sSessionId)
        {
        $rQuery = mysql_query("DELETE FROM session WHERE name = '".mysql_real_escape_string($sSessionId)."'",SQL_CONNECTION);
        
        return true;
        }
    
    function gc($iMaxLifeTime)
        {
        $rSelect = mysql_query("DELETE FROM session WHERE expires <= '".date('Y-m-d',strtotime("-".$iMaxLifeTime." day"))."'",SQL_CONNECTION);
        return true;
        }
    }
?>


Edit:
Let niet op de sql injections verhaal. Dat is nog niet verwerkt, het gaat hier puur over de juiste query's op de juiste plaatsen.

Zelf gebruik ik sessies in db (naast alle andere voor de hand liggende redenen) voor een bezoekers teller. Aan de hand van de sessies wordt er in een aparte tabel opgeslagen dat je de site bezocht hebt en welke pagina's. Dat was de makkelijkste manier om dubbele entries per bezoeker/pagina te voorkomen zonder gebruik te maken van lelijke cookies. Zodra de sessie verwijderd wordt, wordt de foreign key gewoon op null gezet en blijft dus mijn bezoekers teller lekker oplopen zonder met de sessies te interveniëren.

Edit 2:
De nette versie van dezelfde class

[ Voor 50% gewijzigd door CurlyMo op 04-01-2012 00:40 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Raynman
  • Registratie: Augustus 2004
  • Laatst online: 11:53
CurlyMo schreef op dinsdag 03 januari 2012 @ 22:52:

[Pagina 2]
session_start()
Er wordt een lege sessie weggeschreven in de database. Wacht! de sessie bestaat al dus REPLACE INTO zegt oude sessie verwijderen en nieuwe sessie toevoegen. Op dit moment moet er dus een check zitten of de sessie al bestaat en dan een UPDATE query uitvoeren
Jouw UPDATE replacet toch ook gewoon de oude data? Die REPLACE INTO bespaart dan enkele regels code.

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
Raynman schreef op dinsdag 03 januari 2012 @ 23:12:
[...]
Jouw UPDATE replacet toch ook gewoon de oude data? Die REPLACE INTO bespaart dan enkele regels code.
Edit:

Niet meer van toepassing

[ Voor 34% gewijzigd door CurlyMo op 04-01-2012 00:41 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

CurlyMo schreef op dinsdag 03 januari 2012 @ 23:14:
[...]

Volgens mij kan ik het niet duidelijker uitleggen dan ik al had gedaan. Maar we proberen het nog eens.

Mijn UPDATE verwijderd niet eerst de oude INSERT maar werkt hem alleen bij.

REPLACE INTO verwijdert!!! eerst de oude INSERT en voegt dan dus een lege in.
Dan moet je het artikel dat je linkt nog eens goed lezen want daar staat niets in over het leeggooien van de tabel. Daar staat alleen in dat het record eerst verwijderd wordt en daarna weer wordt toegevoegd, mocht het al bestaan. Onder geen beding zou een REPLACE INTO dus een lege tabel mogen opleveren.

Het artikel klopt wel, de performance van REPLACE INTO is slecht en zeker op een tabel die zo groot zal worden als een sessiontabel potentieel kan zijn is dat een slecht plan, maar dat verklaart geenszins de symtomen van de topicstarter. De enige twee stukjes code die dat kunnen verklaren staan in de gc- en destroy-functies.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
NMe schreef op dinsdag 03 januari 2012 @ 23:18:
[...]

Dan moet je het artikel dat je linkt nog eens goed lezen want daar staat niets in over het leeggooien van de tabel. Daar staat alleen in dat het record eerst verwijderd wordt en daarna weer wordt toegevoegd, mocht het al bestaan. Onder geen beding zou een REPLACE INTO dus een lege tabel mogen opleveren.
Tenzij er maar 1 sessie is; in dat geval heb je (een split second weliswaar) een lege tabel.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
Inderdaad. Niemand hier heeft het over een tabel die wordt leeggegooid en dat artikel ook niet

"the old row is deleted prior to the new INSERT"

De oude rij wordt verwijderd (als die al bestaat) en daarvoor in de plaats wordt een nieuwe ingevoegd, in plaats van de oude te updaten.

Edit:
Niet meer van toepassing

[ Voor 196% gewijzigd door CurlyMo op 04-01-2012 00:41 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
CurlyMo schreef op dinsdag 03 januari 2012 @ 23:23:
Inderdaad. Niemand hier heeft het over een tabel die wordt leeggegooid en dat artikel ook niet

"the old row is deleted prior to the new INSERT"

De oude rij wordt verwijderd (als die al bestaat) en daarvoor in de plaats wordt een nieuwe ingevoegd, in plaats van de oude te updaten. Duidelijker kan het toch niet?

Deze query verklaar dus juist! het probleem van de TS. Elke keer dat hij een sessie start wordt zijn huidige sessie gereset. We zullen het zien. Als de TS de REPLACE INTO vervangt door een INSERT & REPLACE variant zoals te zien in mijn script dan weten we of het werkt.
Ehm nee...

Technisch klopt het wat je zegt, maar praktisch niet. Een replace into gooit binnen de dbase wel de row weg en maakt een nieuwe aan, maar dit gebeurt wel binnen 1 db-connectie, oftewel je script merkt er niets van.
Voor je script (behalve snelheids-gewijs) is er geen verschil tussen een replace into en een insert - update scenario mits je hem niet benadert via db-generated keys (auto_increment etc).

Lockings-technisch kan je wat issues hebben met concurrent users of performance technisch kan je wat issues hebben. Maar zolang jij de tabel niet benaderd via db-generated values kan wat jij zegt helemaal niet voorkomen.

Dat is net zoiets als zeggen dat je geen lelijke cookies wilt en tegelijk met sessies gaan werken. Sessie werken of met lelijke cookies of met lelijke _get / _post opties. Heb je sessies dan heb je zeer waarschijnlijk "lelijke" cookies.

Concurrency issues benaderen via "lelijke" cookies is wel een heel aparte aanpak moet ik zeggen (cookies zijn simpel user-data) en daarom vind ik het wel slim dat je voor concurrency issues geen "lelijke cookies" wilt, ze hebben er namelijk niets mee te maken.

[ Voor 0% gewijzigd door RobIII op 03-04-2013 18:55 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
Gomez12 schreef op dinsdag 03 januari 2012 @ 23:58:
[...]

Ehm nee...

Technisch klopt het wat je zegt, maar praktisch niet. Een replace into gooit binnen de dbase wel de row weg en maakt een nieuwe aan, maar dit gebeurt wel binnen 1 db-connectie, oftewel je script merkt er niets van.
Voor je script (behalve snelheids-gewijs) is er geen verschil tussen een replace into en een insert - update scenario mits je hem niet benadert via db-generated keys (auto_increment etc).

Lockings-technisch kan je wat issues hebben met concurrent users of performance technisch kan je wat issues hebben. Maar zolang jij de tabel niet benaderd via db-generated values kan wat jij zegt helemaal niet voorkomen.

Dat is net zoiets als zeggen dat je geen lelijke cookies wilt en tegelijk met sessies gaan werken. Sessie werken of met lelijke cookies of met lelijke _get / _post opties. Heb je sessies dan heb je zeer waarschijnlijk "lelijke" cookies.

Concurrency issues benaderen via "lelijke" cookies is wel een heel aparte aanpak moet ik zeggen (cookies zijn simpel user-data) en daarom vind ik het wel slim dat je voor concurrency issues geen "lelijke cookies" wilt, ze hebben er namelijk niets mee te maken.
Edit:
Ik heb het net even uitgetest op mijn server met dezelfde class, maar aan de REPLACE INTO ligt het niet.

Het is trouwens wel goed om je 'clean' te controleren. Daarbij sluit ik me dus aan bij NMe. Misschien klopt de tijd vergelijking niet en wordt je rij ook bij elke aanroep verwijderd aangezien je rij daarvoor in aanmerking is gekomen. Wat is de waarde van $expire? en wat is de default value van het veld 'last_accessed'? Is dat NOW()? Dan is het ook wat makkelijker om je query te debuggen.

[ Voor 18% gewijzigd door CurlyMo op 04-01-2012 00:42 ]

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Gomez12
  • Registratie: Maart 2001
  • Laatst online: 17-10-2023
CurlyMo schreef op woensdag 04 januari 2012 @ 00:01:
[...]
Ik heb het net even uitgetest op mijn eigen server. Dit is wat er gebeurt:
...
REPLACE INTO sessions VALUES (DEFAULT,'test','');
...
REPLACE INTO sessions VALUES (1,'','');

Hoe verklaar je dit dan?
Ehm, gewoon doen wat je vraagt?

Jij zegt replace alles met key 1 met lege data en dat doet hij...
Ik mag toch hopen dat een update hetzelfde doet, anders moet je even naar je sql-server gaan kijken.

Je update query moet dus zijn : update sessions set data='', lastaccessed='' where test_id=1;

[ Voor 1% gewijzigd door RobIII op 03-04-2013 18:56 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 09:25
Inderdaad "I admit defeat". Er zit inderdaad wat inconsistentie in het technische en praktische verhaal. Wanneer ik dezelfde class probeer dan ligt het niet aan de REPLACE INTO. Mijn data wordt netjes weggeschreven en kan ook gewoon weer opgevraagd worden. Wat ik wel merk is dat bij mij überhaupt de session_destroy het niet doet. De clear() en destroy() worden bij mij nooit aangeroepen.

Ik zou dus gewoon een andere class proberen die ook de REPLACE INTO vervangt voor iets beters want het gebruik van deze commando's is niet aan te raden. Daar waren we het wel met zijn allen over eens :)

Sinds de 2 dagen regel reageer ik hier niet meer

Pagina: 1