PHP Session eldobásra tud valaki ésszerű magyarázatot? hátha vannak tapasztalatok.

Fórumok

Sziasztok!

Van egy weboldal ahol gyakran panaszkodik a megrendel, hogy kidobálja őket a rendszer, azaz kilépteti az oldal őket.

Több hónapja megy a szenvedés, átnyálaztam már szinte mindent a kódomban, volt ahol találtam hibát, de nem adott okot egyik sem arra, hogy kidobálja a usereket.

Teljesen véletlenszerűek a kidobálások. Nincs fix idő két kidobálás között, van, hogy 1-2 óra alatt egyszer, van, hogy percenként egymás után 5x. Sokszor ahol egyszer kidob, utána ott nem. Követhetetlen.
Elkezdtem gyanakodni, hogy a tárhelyen lehet valami, gyakran új session-t indított a szerver ilyenkor amikor kidobott.

Azóta sok tesztet lenyomtam, már loggolom a felhasználók minden mozzanatát, mentem a GET-et POST-ot SESSION-t ip-t meg egy halom dolgot.

Abban vagyok biztos, hogy amikor ez a hiba keletkezik, akkor a teljes session megsemmisül. Sehol nem unset-elem a full session-t és sehol nem használok session_destroy-t.

Írtam a szolgáltatónak hibabejelentést, hogy ez a gondom, és esetleg náluk lehet e valami. Nagyon kedvesek és segítőkészek voltak, köszönet nekik tényleg. Nem tudták megmondani, hogy mi lehet a hiba, csak annyit, hogy lehet az adott szerveren van valami limit és át tudják költöztetni a tárhelyet másik szerverre.

Ez meg is történt.
A hiba viszont maradt.

A kérdés, hogy létezhet e olyan szerver beállítás, hiba vagy akármi aminek folytán időnként kiüríti a session tartalmát?

Azt megfigyeltem még, hogy ha a böngészőből törlöm a sütiket, és új sessiont indítok, akkor több esélyem van erre a hibára mintha csak próbálkozok folyamatosan.

Még le fogok tolni egy halom tesztet, mielőtt megint letámadom őket, de addig puhatolózok, hátha valaki tud erre ésszerű magyarázatot.

köszi előre is, ha valaki ír.

Hozzászólások

Nos, a következő hibalehetőségekre tudok gondolni:

  • A PHP saját GC-je fut file alapú sessionre, ami rosszul van beállítva, ezért néha nem fogad el olyan sessiont sem, ami egyébként érvényes lehet. Ad absurdum PHP bug vagy ugrál az óra a szerveren.
  • File alapú session storage, külső script csinálja a GC-t és szarul van megírva.
  • Memcache alapú session storage és betelik a memcache, ezért eltűnik a session.
  • Rosszul megy ki a session süti (pl. nincs megadva időzóna) ezért elveszik a session. Ezt FireCookieval érdemes ellenőrizni, mert akár kódból is el tudsz cseszni valamit.

Összegezve: az az izgalmas kérdés, hogy a session süti tűnik-e el avagy a mögöttes adat. Ezt tudd meg és akkor nézhetjük tovább a hiba okot. Jó lenne látni egy phpinfo() kimenetet is, illetve egy kicsit többet megtudni a szolgáltatóról.

Szia!

Tettem fel képet a session phpinfo-ról, elég ennyi, vagy másról is kellene infó? Ha igen, akkor mentek egyet html-be, replacelem a nem publikus adatokat és feltöltöm azt is.

http://kepfeltoltes.hu/110422/session_www.kepfeltoltes.hu_.png

az órát még ellenőrzöm azt hiszem, ki tudja.

a memcache tűnik reálisabbnak, gondoltam arra, hogy több felhasználó nyúzza a szervert és nem bírja.

a session file:
eleinte az admin oldal és a frontend egy domain alatt futott, így külön mappában tároltam a sessionokat. Ott láttam olyat, hogy a hiba jelentkezésekor új sessiont generált. egy új üreset.

Amióta átköltöztettek új szerverre, azóta többségében a session_id marad, csak a tartalma tűnik el. Direkt loggolok több adatot is, ebből látom.

Tesztként olyat csináltam, hogy amikor képes voltam generálni egy hibát, akkor visszanéztem az adatbázisban logokban, hogy hol mikor szállt el. Mi volt legutoljára a session tartalma (serializalva tárolom mysql-ben).
kimásoltam a serializalt stringet, létrehoztam egy tök üres teszt.php -t abban egy session_startot toltam és betöltöttem unserialize -vel a stringet. Azt tapasztaltam, hogy miután belepakoltam, és újratöltöttem az oldalt, a tartalma nem maradt meg, kiürült. Ezt többször el tudtam játszani. Utána megjavult. (valószínűleg ilyenkor van az, hogy a user be akar lépni és a belépés után a login oldal fogadja megint, azaz azonnal ki is lép)

tehát most azt kell mondanom, hogy a session süti marad. közben próbálom újra, ez az egésszel a baj, hogy nincs benne rendszer, tök random az egész, van ,hogy 10 percen át tolom az oldalt, de semmi.

Hallod, ha ez a /tmp-be menti a sessionöket, az elég nagy baj. Egyrészt security szempontból is, másrészt pedig ott akár valami scriptek is tevékenykedhetnek. Ha nem akarsz több dolgot kitenni a phpinfo()-ból ide, akkor keress meg privátban, kidebuggoljuk, de ez így nekem elsőre úgy néz ki, mint ha valaki egy full default installt tolt volna föl a PHP-ból és még arra sem vette volna a fáradtságot, hogy rendesen beconfolja. Vagy nagyon tud valamit és nem az, aminek látszik.

au, valamiért nem láttam, hogy jött tőled új post, elnézést kérek.
Eleinte amióta php-zok azóta saját tmp mappába tolom a sessionokat, de egyszerűen itt a sok gondom miatt kivettem ,hátha az megjavítja, de ugyanaz volt, tehát saját tmp mappában is.

szívesen küldök neked phpinfo-t,küldöm privátban, köszönöm!

nah, sikerült eljátszanom megint.

az oldalt teszteltem, kidobott. Gyorsan átmentettem a legutóbbi session tartalmat stringbe. Bepakoltam egy teszt.php -ba, ahol betöltöttem a session-ba ($_SESSION = unserlialize("blabla");)

a kód leírása:
előbb session_start();

utána kiírattam a $_SESSION tartalmát
utána beletöltöttem az unserialize-vel
és kiírattam újra.

Az érdekesség az volt, hogy az első kiíratásra sem üres tömböt adott vissza, hanem mintha egy korábbi állapotát adná vissza a munkamenetnek. volt benne tartalom picike.

második kiíratásra az unserializált betöltés után a tartalmat rendesen ki is tudtam listázni.

ekkor jön az érdekesség, nyomok egy F5-öt, erre ugye az első kiíratásra ugyanazt kell visszaadnia amit előbb betöltöttem. Nem változott semmi. mintha a script végeztével elfelejtené, mintha nem mentené el.

töröltem a sütiket, így az első kiíratásra nem is adott már vissza semmit, üres volt.

sok-sok F5 és semmi, ugyanaz.

ezek után kicsit megbolygattam és betettem egy olyat a kódba, hogy $_SESSION['fff'] = 66;, ez belekerült és hirtelen megjavult minden. Kitöröltem az fff sort, és próbáltam újra az eredeti kódot és működött. Mintha kellene neki egy kis tartalomváltozás, hogy észbe kapjon. érthetetlen.

Na, ez kísértetiesen emlékeztet arra, mint amikor valaki clusterező megoldást alkalmaz és nem jól állította be az órákat. Igazából anélkül, hogy többet tudnánk a szolgáltató infrastruktúrájáról, elég nehéz megmondani, hogy mi lehet a háttérben. Esetleg a szolgáltató nevét elárulhatnád, ha nem túl nagy titok.

+1 apache clusternél jártam így, és a problémát megoldotta, hogy a két szerver órája ntp-vel szinkronban van. (egyébként is így lett volna, cask az egyiken hiba miatt leállt az ntp, és 2 perc óra eltérés pont ilyen hibákat okozott (nem mindig megismételhetően)

Ne használd a beépített session kezelőt, többször megjártam vele, még memcached-t használva is.

gondoltam már rá, hogy magam mentem a $_SESSION tömböt és mentem olvasom serializálva, erőforrásban talán nem lenne sokkal több mint az alap. script elején beolvas, a végén kiment.

egy gond van ezzel, hogy ha valahol redirect-elek, akkor nem mentődik el. Kérdés, hogy tudok e definiálni saját eventeket a session eventekre.

A változók még megmaradnak szerintem, tehát tárolhatnék mindent rendesen a $_SESSION tömbben, csak épp a script elején én töltöm fel és a végén mentem le belőle.

De amúgy erre sincs szükség belegondolva. Mehet a script elejére, végére.
A redirectet pedig amúgy is egy függvénnyel hívom meg. Ott max behúzom global -al a $_SESSION-t és lementem mielőtt header-t tolok.

Izgalmasak ezek a megoldások, de azért érdekelne, hogy mit cseszett el a szolgáltató. Fogok írni egy saját kezelőt, ha megoldódik tőle, akkor utána jelzem a tárhelynek és érdeklődök megoldás után.

Nem akartam mondani, mert ezért néhol meg szoktak kövezni, de mifelénk a $_SESSION tömb használatáról egyetemlegesen leszokott mindenki, mert rohadt nehéz debuggolni a PHP saját session kezelőjét. Inkább írunk saját osztályt saját tároló megoldással, az a biztos.

A redirectet meg a rendszereden belül illik megoldani, tehát ha pl. van egy output osztályod, akkor abban beállítani és a feldolgozás végén elküldeni a kliensnek.

Ez azért rendszertől függ.
Ha a rendszered úgy működik, hogy eleinte mindent "begyűjt" magának, hogy milyen utasításokat, parancsokat kell végrehajtania, és a a script legvégén egy "run" paranccsal indítod el őket, akkor jah, ott megoldható az, hogy a'szondod a rendszerednek, hogy redirect ide és akkor a script végén a "session mentés után" végrehajtja.

Nekem egyenlőre a rendszeremben a modulok controll elemei nem a végén futnak, így a redirect-jeim félbeszakítják a scriptet.

Ez a session lekezelése saját rendszerrel, jah izgalmas, de én egyenlőre most találkozom először ilyen problémával, még soha nem volt ilyen gondom.

nem fut tobb geprol az oldal esetleg? akar round-robin, akar valami lvs szeruseg (director mogott)?

t

Azt hiszem értem ,tehát, hogy a tárhelyet több szerver szolgálná ki?
nem hiszem, most költöztettek át, végig úgy mondták, hogy "másik szerverre".

A több gép egy tárhely alatt szerintem elég extrém lenne.
Ez egy sima évi 10-20e Ft-os tárhely, semmi spéci. (olcsó tudom, de ennek azért működnie kellene)

Ha gondolod, adok tárhelyet, ahol le tudod tesztelni.
Aztán ha minden OK, akkor akár bérelhetsz is :D

Ha érdekel, küldj privit.
* html {display: none}

Még ilyen ötletem van, hogy jó helyen van-e a session_start-od mindenhol.
Használsz Ajax-ot ?

* html {display: none}

Akkor viszont tényleg jó volna tudni, hogy hogy tárolja a szolgáltató a session-öket.
Ha file alapú akkor nem írtja-e ki valami globális baromsága (mint pl cron :D)
Egy időben kéne egy kisebb, különálló scriptet futtatni, és figyelni hogy ha a programod sessione kihal, akkor a kis script is elveszíti-e.

* html {display: none}

olvass vissza kicsit ;)
leírtam, hogy ezt tettem, egy kis scripttel alias teszt.php (nah jó, valójában teszt2.php)-val pont ezt próbáltam ki, hogy ott mi történik.

ha cronból írtaná ki a session fájlt, akkor szerintem nem adódna a hiba időnként egymás után sokszor. illetve ha cronból pöcsölne, akkor nem nyúlt volna bele a lokális tmp mappámba amit session_save_path-nak állítottam be. Ilyen is volt.

Nah akit még érdekel.
Végül is többetek tanácsára írtam egy session kezelőt, megkerülve a gyárit. Megoldódott. Megírtam a tárhelynek is a tapasztalataimat, talán tudnak vele kezdeni valamit.
Vicces, hogy tényleg az első alkalom, hogy ilyen hibába futok több év alatt. ez van.

köszönöm mindenkinek a segítséget, jánosszen-nek meg a privát help-et.

Engem érdekel, mert izgalmas! :)
Kár, hogy az nem derült ki pontosan, mi is a tényleges probléma. Mert írtad, hogy saját vm-on jól futott (nem tudom máshol, más gépen kipróbáltad-e?), de a szolgáltatónál nem. Mert nagyon nem mindegy, hogy a PHP session kezelője a hibás vagy...

Csak a tanulás végett: hogyan néz ki egy saját session kezelő, hogy lehet kiváltani a "gyárit"?

Az alapjait vettem át kb. Illetve a sessionId generálást. Elsőre meg is szívtam vele, mert nem 32 karakter hosszan generál, hanem 40, az adatbázisom ahol a beléptetési adatokat tároltam ott VARCHAR(32) -re volt állítva:) Ennek eredménye az volt, hogy a user-t 1 óra múlva kidobta és kapásból jött a teló, hogy izé most is. Én viszont tudtam, hogy kidobta, mert alert mailt kaptam róla és mire hívtak, már javítottam is:)

Igazából még a saját VM-emen is sikerült a hibát előhozni.
Amit janosszen adott alapnak, az alapján csináltam egy nagyon egyszerű cuccot. Semmi xtra.

Ha nincs cooki-ban a SESSID, akkor generálok egyet (olyat ami még nincs kiosztva) és mentem. fájlt nyitok neki abban tárolom a session adatokat serializalva plusz base64-el. a fájlt minden script indításkor lockolom, a végén unlock.

Ami egy csavaros pont volt az az, hogy a $_SESSION tömbbe pakoltam mindent. Mivel egy eléggé nagy projectről van szó, nem írhatom át mindenhol utólag, nincs időm rá. De megy rendesen.

Még annyi hiányzik, hogy majd cron-ból törölgessem a régi session fájlokat, de ez már részletkérdés.

Azért van kizárva, hogy a kódomban van a hiba, mivel ezek után megjavult az egész. Nincs több kidobálás. Ha a programomban lett volna a hiba, akkor nem javult volna meg.

Azt figyeltem meg, hogy a szolgáltatónál és a VM-emen is van suhosin. De, hogy konkrétan ki a hibás. nem tudom.

Óvatosan az ilyenekkel, a shutdown function akkor fut le, amikor a PHP már bontja lefele a dolgokat, tehát koránt sem biztos, hogy lesz még működő adatbázis kapcsolatod. Nekem ezzel sikerült régebben előhoznom segfaultolós hibákat, aztán csak lestünk, hogy ezt most miért. Szerintem, hívja csak meg a kódból a session_write_close függvényt.

erdemes lehet tudni, hogy a debian alapu disztrokon a php session kezeles nem a php sajat session gc-jen keresztul tortenik, ott ki van kapcsolva, hanem fel van veve egy kulon cronjob (/etc/cron.d/php5) ami 30 percenkent torli a session.gc_maxlifetime-nel regebben modositott session fajlokat.
a masik amit el tudok kepzelni, hogy atraktak a session kezelest memcache alapura (transzparensen beallithato), es kiszoritjak egymast a rendelkezesre allo memoriabol a sessionok.

ps: elnezest, nem olvastam vegig az osszes postot, lehet hogy mar mas bedobta.

Tyrael

nem tudom, milyen verzio, de regebben volt suhosin-ban egy olyan bug, hogy volt egy olyan bug, hogy ha tul sok request parameter volt, akkor a limitben beallitott szamu feletti parametereket eldobta.
a limitet meg ugy kezelte, hogy a sutik voltak az utoljara hagyva, ezert ha sok request paramot kaptal, akkor nem jottek letre a sutik.
ez azt a tunetet produkalta, hogy a sutiben kuldott session_id cookie-t nem kapta vissza a php, ez alapjan a session_start uj sessiont inditott.
a megoldas az volt, hogy a http://www.hardened-php.net/suhosin/configuration.html#suhosin.request… erteket magasabbra vettem, de gondolhatod, hogy nem egyszeru fejet vagtam eloszor, amikor latom firebug-ban, hogy elmegy a suti, a php script elso soraban meg mar nem latja. :/

a masik, amit megprobaltam volna, az ez:

register_shutdown_function('session_write_close');
(de persze ra lehetne rakni a session osztaly destructorara is.)

hatha hibaval all meg bizonyos esetekben a script, es nem irja ki a modositasokat a sessionbe.

mindenesetre a logokat kellene nezni, meg a leheto legkissebb reprodukalhato testcase-t csinalni.
erdekes lett volna az is, hogy milyen php, es honnan/hogyan lett telepitve.
lehet hogy mar megoldodott ez a hiba, de ha mondjuk a telepites vagy a konfiguracio lett elszabva, akkor elojohetnek meg problemak a jovoben.

Tyrael

marmint mire?
ha rakeresel a "vbulletin suhosin" kulcsszavakra google-on, akkor latni fogod, hogy nagyon gyakori problema, en itt futottam bele (forum admin felulete tobbszaz beallitast akart 1 formon menteni), sot a vbulletin mar csekkolja is a suhosin jelenletet, es jelzi a felhasznalonak, hogy problemak lehetnek, es mely config valtozokat kellene atallitania.

Tyrael