session_handler
Ik ben de laatste tijd bezig geweest met een session handler om sessies naar de database te schrijven. Nu gaat er alleen iets mis met het schrijven naar de database. De sessie wordt geschreven, alleen is het sessie_id regelmatig 0 en wordt de waarde nooit ingevuldt. De schrijf functie van de handler is:
Code (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
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
<?
function write($ses_id,$ses_data)
{
//$ses_id is het id van de sessie, net zoals bij de read functie
//$ses_data is de data die geschreven moet worden
//we gaan de controle aanmaken, zodat de sessie ook alleen bij 1 ip geldig is:
$controle = md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT']);
//uiteraard willen we alles weer in de DB schrijven. Hiervoor weer een query opstellen:
$query = "INSERT INTO Sessies"; //we gaan de gegevens in de tabel Sessies opslaan
$query .= " (sessie_id,tijd_aangemaakt,waarde, controle)"; //de velden waar de gegevens moeten komen
$query .= " VALUES"; //uiteraard moeten er gegevens in komen
$query .= " ('".mysql_real_escape_string($ses_id)."', NOW(),
'".mysql_real_escape_string($ses_data)."', '".$controle."')"; //en dit zijn de gegevens die we in de DB zetten
//nu gaan we die query weer uitvoeren
$result = mysql_query($query);
//en kijken of dat gelukt is
if(!$result)
{
//niet gelukt
return false; //terugsturen dat het verkeerd ging
}
else
{
//het is gelukt waarschijnlijk gelukt. Nog 1 laatste check:
if(mysql_affected_rows() != 1)
{
//het aantal aangepaste rijen is niet 1. Dus blijkbaar ging er toch iets fout.
return false; //terugsturen dat er iets fout ging
}
else
{
//alles ging goed en de sessie is opgeslagen
return true; //terugsturen dat alles gelukt is
}
}
}?>
function write($ses_id,$ses_data)
{
//$ses_id is het id van de sessie, net zoals bij de read functie
//$ses_data is de data die geschreven moet worden
//we gaan de controle aanmaken, zodat de sessie ook alleen bij 1 ip geldig is:
$controle = md5($_SERVER['REMOTE_ADDR'].$_SERVER['HTTP_USER_AGENT']);
//uiteraard willen we alles weer in de DB schrijven. Hiervoor weer een query opstellen:
$query = "INSERT INTO Sessies"; //we gaan de gegevens in de tabel Sessies opslaan
$query .= " (sessie_id,tijd_aangemaakt,waarde, controle)"; //de velden waar de gegevens moeten komen
$query .= " VALUES"; //uiteraard moeten er gegevens in komen
$query .= " ('".mysql_real_escape_string($ses_id)."', NOW(),
'".mysql_real_escape_string($ses_data)."', '".$controle."')"; //en dit zijn de gegevens die we in de DB zetten
//nu gaan we die query weer uitvoeren
$result = mysql_query($query);
//en kijken of dat gelukt is
if(!$result)
{
//niet gelukt
return false; //terugsturen dat het verkeerd ging
}
else
{
//het is gelukt waarschijnlijk gelukt. Nog 1 laatste check:
if(mysql_affected_rows() != 1)
{
//het aantal aangepaste rijen is niet 1. Dus blijkbaar ging er toch iets fout.
return false; //terugsturen dat er iets fout ging
}
else
{
//alles ging goed en de sessie is opgeslagen
return true; //terugsturen dat alles gelukt is
}
}
}?>
Schrijven gebeurt gewoon door $_SESSION['bla'] = "tekst";
Heeft iemand een idee waarom het fout gaat?
gebruik anders error_reporting(E_ALL | E_NOTICE);
Wat geeft mysql_error() terug? Wat krijg je te zien als je de query echo'd? Klopt dan alles?
session_start(); staat overal boven. mysql_error() geeft ook niets.
Wat zou je moeten krijgen als je de query echo'd
Gewijzigd op 01/01/1970 01:00:00 door Bjorn Vennema
In je huidige script geef je nergens een foutmelding als je query mislukt. Het enige dat je doet is de functie false terug laten geven, maar een SQL foutmelding wordt nergens getoond...
Edit: Er worden bij het uitvoeren van het script ook geen foutmeldingen geproduceerd. Ik denk dat de variabelen ses_data en ses_id dan leeg zijn? Maar dat zouden variabelen moeten zijn die door de sessie meegegeven moeten worden...toch?
Gewijzigd op 01/01/1970 01:00:00 door Bjorn Vennema
Komt er niets in de database, komen er incorrecte gegevens in de database, etc? Probeer nu eens precies te omschrijven wat er fout gaat. 'Niet juist' en 'niet goed' zijn zo nietszeggend. Dat is het zelfde als dat ik zou zeggen: 'Mijn script werkt niet goed, kun je me helpen?'...
Ik heb in de database een tabel met de velden: sessie_id, tijd_aangemaakt, waarde en controle. De velden controle en tijd_aangemaakt worden ingevuld zoals het hoort. Het veld sessie_id krijgt steeds als waarde 0. Leeg dus. Het veld waarde blijft ook leeg.
Nou dan weet je dus direct dat de variabelen $ses_id en $ses_data niet correct en dus blijkbaar ook leeg zijn. Dat zul je dus moeten gaan controleren...
Wat voor datatypes zijn al je velden in je database? En dan vooral de sessieid.
Edit: sessie_id is type Int(eger) en waarde is Varchar
Gewijzigd op 01/01/1970 01:00:00 door Bjorn Vennema
Björn schreef op 19.03.2008 16:29:
Er ontstaan geen foutmeldingen. Dat is juist het hele probleem. Hij wil alleen gewoon de data niet juist in de DB zetten. Snap niet waarom dat niet gebeurt?
session_start(); staat overal boven. mysql_error() geeft ook niets.
Wat zou je moeten krijgen als je de query echo'd
session_start(); staat overal boven. mysql_error() geeft ook niets.
Wat zou je moeten krijgen als je de query echo'd
session_start is niet nodig indien er een eigen session handler is. Je moet geloof ik zorgen dat de sessie pas wordt gesloten na de laatste </html> dmv.
session_set_save_handler.
Verder, weet je zeker dat sessie_id een nummer is? PHP Sessies zijn namelijk een md5-hash van iets, en ik merk niet dat je ergens een eigen sessie-id genereert. Een type CHAR(32) zou beter op z'n plaats zijn.
Overigens is de Varchar wel groot genoeg? Bij mijn weten heeft die een limiet van 255 karakters, en wanneer je grotere dingen in de sessie zet (de data van een sessie is het resultaat van serialize uitgevoerd op de $_SESSION array) wordt je data maar deels opgeslagen. Met als gevolg dat bij de eerst volgende keer dat je de sessie probeert uit te lezen, unserialize (wat intern gebruikt wordt om de $_SESSION array vervolgens weer te vullen) zal zeuren over een niet geldige waarde, en niets zal teruggeven. Resultaat: geen sessie meer. Ik zou voor een TEXT of misschien wel BLOB veld gaan. BLOB omdat je de data niet als tekst hoeft te behandelen, al is het in weze gewoon een enorme string waar je niet veel mee kan. Het vertoont op zich vrij veel overeenkomsten met binaire data.
Hoe registreer je de functie, en kloppen de andere callbacks wel? Zie ook Verder, weet je zeker dat sessie_id een nummer is? PHP Sessies zijn namelijk een md5-hash van iets, en ik merk niet dat je ergens een eigen sessie-id genereert. Een type CHAR(32) zou beter op z'n plaats zijn.
Overigens is de Varchar wel groot genoeg? Bij mijn weten heeft die een limiet van 255 karakters, en wanneer je grotere dingen in de sessie zet (de data van een sessie is het resultaat van serialize uitgevoerd op de $_SESSION array) wordt je data maar deels opgeslagen. Met als gevolg dat bij de eerst volgende keer dat je de sessie probeert uit te lezen, unserialize (wat intern gebruikt wordt om de $_SESSION array vervolgens weer te vullen) zal zeuren over een niet geldige waarde, en niets zal teruggeven. Resultaat: geen sessie meer. Ik zou voor een TEXT of misschien wel BLOB veld gaan. BLOB omdat je de data niet als tekst hoeft te behandelen, al is het in weze gewoon een enorme string waar je niet veel mee kan. Het vertoont op zich vrij veel overeenkomsten met binaire data.
Gewijzigd op 01/01/1970 01:00:00 door Jelmer -
Jurgen schreef op 19.03.2008 17:45:
Is dat zo? Bij mijn weten behandel je in jouw php-code een sessie zoals je altijd een sessie behandeld, maar wordt de sessie intern alleen anders verwerkt. Niet meer in een bestandje maar in de database. session_start() heb je dan ook gewoon nodig.session_start is niet nodig indien er een eigen session handler is.
Of ik sla de plank flink mis, wat nooit helemaal is uit te sluiten...
pgFrank schreef op 19.03.2008 17:53:
Of ik sla de plank flink mis, wat nooit helemaal is uit te sluiten...
Jurgen schreef op 19.03.2008 17:45:
Is dat zo? Bij mijn weten behandel je in jouw php-code een sessie zoals je altijd een sessie behandeld, maar wordt de sessie intern alleen anders verwerkt. Niet meer in een bestandje maar in de database. session_start() heb je dan ook gewoon nodig.session_start is niet nodig indien er een eigen session handler is.
Of ik sla de plank flink mis, wat nooit helemaal is uit te sluiten...
Zoals ik gelezen heb in PHP 5 voor gevorderden is dit niet nodig (ik dacht nl. ook eerst dat de schrijver het fout had). Zelf heb ik dit nog niet getest maar zo zou het moeten zijn. Wel benadrukte hij dat er na de laatste </html> een session_write_close() moet komen anders wordt de sessie niet geschreven naar de database. Omdat hij 2 functies aanroept bij het sluiten, nl. schrijven en sluiten.
Zend er van zegt, dus inclusief het gebruik van session_start(). Maar wellicht zijn er meerdere wegen naar die naar Rome leiden.
Dit is wat @Jelmer: De waarde is in mijn geval niet zo heel groot, het slaat 2 sessie variabelen op en dat past prima in een varchar veld. Ik snap echter je punt, waardoor het inderdaad handiger wordt. Daarnaast ga ik nu eens testen of het id in een char veld werkt.
Edit: Inderdaad is een char veld hier de oplossing. Ik ging ervanuit dat het id uit een nummer zou bestaan, maar dat is niet het geval. Een char veld van 32 karakters biedt uitkomst, daar het id ook precies 32 karakters lang wordt.
Gewijzigd op 01/01/1970 01:00:00 door Bjorn Vennema