Blockierende Sessions in PHP

Work — Tags: , , — nemesis @ 05:43

Wenn ihr oft mit PHP Skripte schreibt ist es euch vielleicht schonmal aufgefallen. Solange die PHP-Seite lädt kann eine weitere nicht angezeigt werden. Die zweite Seite “hängt” dann einfach. Das fällt vorallem bei Downloadscripts auf. Wenn der Download läuft kann man die Seite selbst nicht mehr aufrufen. Das Problem tritt allerdings nur auf, wenn man Sessions verwendet. Um das Problem zu verstehen, sollte man wissen, wie Sessions in PHP funktionieren.

Mit der Funktion session_start kann ein Script nicht nur Daten in der serverseitigen Session speichern, sondern bekommt auch einen exklusiven Lock auf diese. In dem Moment können andere Scripts die Session nicht benutzen. Die Funktion im zweiten Script wartet dann, bis das erste Script den Lock wieder freigibt und lockt danach die Session für sich selbst. Dies ist recht sinnvoll, da so Seiteneffekte ausgeschlossen werden, da nur ein Script Daten in der Session modifizieren kann.

Problematisch wird das Konzept bei zeitintensiven Aufgaben. Da PHP eine Session automatisch erst am Ende der Laufzeit eines Scripts wieder freigibt bleibt der Lock solange bestehen bis das Script abgearbeitet ist. Zum Beispiel ein Download:

session_start();

authenticationstuff();

// Wir werden eine PDF Datei ausgeben
header('Content-type: application/pdf');

// Es wird downloaded.pdf benannt
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// Die originale PDF Datei heißt original.pdf
readfile('original.pdf');

Während der Download der PDF-Datei läuft kann also keine weitere Seite aufgerufen werden, die session_start benutzt. Umgehen kann man das ganze recht einfach, indem man die Session schließt, nachdem man alle relevanten Bearbeitungen an ihr vorgenommen hat:

session_start();
authenticationstuff();

// session schließen und freigeben
session_write_close();

// Wir werden eine PDF Datei ausgeben
header('Content-type: application/pdf');

// Es wird downloaded.pdf benannt
header('Content-Disposition: attachment; filename="downloaded.pdf"');
// Die originale PDF Datei heißt original.pdf
readfile('original.pdf');

Die Session wird so vor dem zeitintensivem Download wieder freigegeben und weitere Seiten können ohne Probleme aufgerufen werden.

0 Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a comment

powered by WordPress with Barecity