Duplikacja kluczy w sesji - Framework

0
Notice: Undefined variable: result in /framework/lib/db/mysql.php on line 299
MySQL error: Powt�rzone wyst?pienie '4361f55119491e4b6162c1396319be50' dla klucza 'session_id'
INSERT INTO coyote_session (session_id, session_start, session_stop, session_user_id, session_ip, session_page) VALUES("4361f55119491e4b6162c1396319be50", 1230646950, 1230646950, 2, "212.76.*.*", "/index.php")
Warning: Cannot modify header information - headers already sent by (output started at /framework/lib/db/mysql.php:299) in /framework/lib/output.class.php on line 73

Wydaje mi się, że coś jest nie tak, linia 73:

setcookie(Config::item('cookie_prefix') . $name, $value, $expired, $path, $host, $secure);

Zastanawia mnie, dlaczego nie są aktualizowane sesje w bazie. Moim zdaniem, trzeba by było zrobić jakiś wyjątek, który sprawdzałby czy użytkownik się loguje czy już jest zalogowany.

//Edit: chodzi o przechodzenie na inne subdomeny (wildcard). np. www.4p.net ->> 4p.net - takie przejście spowoduje błąd. Błąd również spowoduje długa nieaktywność i ponowne odświeżenie strony.

0

Co do klasy user.class.php:

  • Masz aktualna wersje z SVN? ;]
  • Jaki mas ustawiony cookie host? Ustaw .4p.net (z kropka na poczatku!!) jezeli cookie ma byc dostepny rowniez w subdomenach.

A a propoS tego pliku: http://4programmers.net/trac/coyote/ticket/8

0

Właśnie sęk w tym, że wszystko zaczęło tak działać po aktualizacji z svn. zarówno na apache jak i na IIS7 jest ten problem. host jest z "."(kropka na początku).

Siedzę nad tym już jakiś czas, ale może znajdę przyczynę. Czytałem ten ticket, ale mam co do niego pewne wątpliwości (chyba, że nie miało by się to opierać o triggery, bo o ile dobrze pamiętam to można tylko jeden dla każdej akcji).

//Edit: głupia sprawa, ale problem zniknął, nic nie zostało zmienione, po za wyczyszczeniem tabeli session. Siedzę i sprawdzam, ale chyba nic już nie zmieni się.

0

No tak, te klase trzeba bedzie troche potestowac ;) Ze zniknal po wyczyszczeniu tabeli to normalne - ten blad sql wynikal, ze probowal ponownie dodac rekord o tym samym ID sesji. Czyli byles juz w bazie, a ten probuje dodac kolejny raz. Czemu?

No gdzies, w ktoryms warunku moze byc blad to fakt. Generalnie ciastko {prefix}ip okresla, ze user jest w systemie. Jezeli nie moze tego ciacha znalezc probuje dodac sesje w tabeli.

Co do tego ticketa to chodzilo mi cos w ten descen (procedura mysql):

CREATE PROCEDURE `SET_SESSION`(sessionId VARCHAR(32), sessionUser INT, sessionIp VARCHAR(15))
BEGIN
        DELETE FROM coyote_session WHERE session_stop < (UNIX_TIMESTAMP() - 600);

        SET @isSession = (SELECT session_id FROM coyote_session WHERE session_id = sessionId);
        IF @isSession IS NOT NULL THEN
                UPDATE coyote_session SET session_stop = UNIX_TIMESTAMP() WHERE session_id = sessionId;
        ELSE
                INSERT INTO coyote_session VALUES(sessionId, sessionUser, sessionIp, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
        END IF;
END

Oczywscie, w uproszczeniu... ;)

Co do klasy user.class.php to w paru slowach idea jej dzialania:

W systemie dziala klasa User (zlokalizowana w lib/user.class.php), ktora odpowiada za obsluge uzytkownika.

Klasa wywolywana jest przed wykonaniem faktycznego kodu kontrolera. Jest to klasa statyczna, dostepna w calej aplikacji. Jest zainicjowanie nastepuje w pliku trigger/initialize.trigger.php (trigger). Wspolpracuje ona z tabela coyote_session, ktora przechowuje informacje o userach online, aktualnie zalogowanych w systemie.

W klasie najwazniejsza metoda jest metoda load(). W niej nastepuje odczytanie cookies znajdujacych sie na komputerze uzytkownika. System zapisuje 3 ciastka zwiazane z obsluga uzytkownika:

  • coyote_sid - Unikalny 32 znakowy identyfikator sesji. Identyfikator jest unikalny dla kazdego uzytkownika
  • coyote_ip - Ostatnie IP, z ktorego logowal sie uzytkownik
  • coyote_data - Opcjonalnie, informacje o zalogowanym uzytkowniku (ID konta, haszowane haslo

Po odczytaniu informacji z ciastek, nastepuje uruchomienie garbage collectora. Jest on uruchamiany co jakis czas. Jak czesto? To reguluje parametr session_gc z pliku konfiguracji. Informacja o ostatnim uruchomieniu collectora, znajduje sie w tabeli coyote_config, w polu session_last_gc (jako timestamp). Garbage collector czysci nieaktywne sesje. W tabeli coyote_session kasowane sa rekordy, ktore stracily "waznosc". Dlugosc sesji regulowana jest polem session_length w pliku konfiguracji. W tabeli coyote_session, pod polem session_stop, znajduje sie informacja o godzinie i dacie ostatniej aktywnosci danego uzytkownika. Jezeli ten nie uczynil nic w przeciagu - dajmy na to - 10 min, system uznaje, ze opuscil on strone. Taki rekord nalezy skasowac.

Po uruchomieniu collectora, nastepuje uaktualnienie sesji. Czyli na podstawie SID (session ID) uaktualniamy w tabeli coyote_session czas ostatniej aktywnosci. W tym momencie oczytujemy rowniez informacje o uzytkowniku z tabeli coyote_user.

W przypadku, gdy sesja nie istnieje w tabeli coyote_session, nastepuje jej utworzenie w metodzie create() klasy User.

Informacje odczytane z tabeli coyote_session, coyote_user sa dostepne poprzez metode data(). Np. :

echo User::data('user_name'); // odczyt pola user_name

Albo skrocona werja tego zapisu:

echo User::data('name'); // system sam domysli sie, ze chodzi o pole user_name

Wiecej informacji o dzialaniu klasy, znajduje sie w pliku user.class.php. Tam kod jest opatrzony komentarzami.

0
Adam Boduch napisał(a)

No tak, te klase trzeba bedzie troche potestowac ;) Ze zniknal po wyczyszczeniu tabeli to normalne - ten blad sql wynikal, ze probowal ponownie dodac rekord o tym samym ID sesji. Czyli byles juz w bazie, a ten probuje dodac kolejny raz. Czemu?

Bardziej chodziło mi oto, że nie powtórzył sie ponownie, pomimo moich starań.

//Edit: zbyt szybko powiedziałem te słowa. Błąd powrócił.
Zatem opiszę jak to się stało.

Zalogowałem się w systemie powiedzmy z godzinę temu. Musiałem wyjść, więc zamknąłem przeglądarkę, ale nie system. Wróciłem, wchodzę na stronę testową i ... błąd. Prawdę mówiąc nie sądzę, że to jest problemem, aczkolwiek sprawa jest ważna. Postaram się wykryć co jest nie tak.

//Edit2
Ten sam problem występuje przy próbie wylogowania (jeżeli wystąpił wcześniej). A co za tym idzie, nie możliwe jest wylogowanie.

błąd jest gdzies tu:

public static function load()
	{
		self::$core = &Core::getInstance();
		Log::add('User class initialized', E_DEBUG);
		$time = time();

		self::$sid = self::$core->input->cookie('sid');
		
		if (self::$sid)
		{
			if (strlen(self::$sid) != 32)
			{
				trigger_error('Invalid session key!', E_USER_ERROR);
			}
		}
		self::$ip = self::$core->input->cookie('ip');
		self::$page = self::$core->input->page();

		if (self::$core->input->cookie('data'))
		{ 
			self::$sessiondata = unserialize(stripslashes(self::$core->input->cookie('data')));

			// ID usera pobrane z cookie. Na tym etapie nie mamy pewnosci, ze ID jest prawidlowe
			self::$id = (int)self::$sessiondata['user_id'];
		}

		/* metode gc() wywolujemy jedynie co jakis czas */
		if ($time > Config::item('session_last_gc') + Config::item('session_gc'))
		{
			self::gc();
		}

		if (!self::$ip)
		{  
			self::create();
		}
		else
		{ 
			self::update();
		}
	}

jakiś czas temu na swoje potrzeby pisałem coś takiego:

function sessionGC()
	{
		$time = (time() - $this->sessionLifeTime);
		$sql = "DELETE FROM usersSession
						WHERE sessionTime < '" .$time . "'"; 

		if ( $this->db->query($sql) )
		{
			setcookie('PHPSESSID', self::sessionId(), 0);
			return true;
		} else {
			return false;
		}
	}

Było to uruchamianie przy ładowaniu klasy i wywalało nieaktywne sesje z bazy.

0

User.class.php, lina 293: tez jest metoda gc().
A cos takiego zrobisz na http://dev.4programmers.net ?

0
Adam Boduch napisał(a)
CREATE PROCEDURE `SET_SESSION`(sessionId VARCHAR(32), sessionUser INT, sessionIp VARCHAR(15))
BEGIN
        DELETE FROM coyote_session WHERE session_stop < (UNIX_TIMESTAMP() - 600);

        SET @isSession = (SELECT session_id FROM coyote_session WHERE session_id = sessionId);
        IF @isSession IS NOT NULL THEN
                UPDATE coyote_session SET session_stop = UNIX_TIMESTAMP() WHERE session_id = sessionId;
        ELSE
                INSERT INTO coyote_session VALUES(sessionId, sessionUser, sessionIp, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
        END IF;
END

Oczywscie, w uproszczeniu... ;)

Nie ma to jak sobie uprościć...

INSERT INTO coyote_session VALUES(sessionId, sessionUser, sessionIp, UNIX_TIMESTAMP()) ON DUPLICATE KEY UPDATE session_stop=UNIX_TIMESTAMP()

Oczywiście zostaje kwestia gc, które trzeba uruchamiać ręcznie, np przy starcie korzystania z bazy tak jak napisal Dominium. No i wtedy można czas sesji zapisać sobie w configu zamiast na sztywno w procedurze w bazie.

0
Adam Boduch napisał(a)

User.class.php, lina 293: tez jest metoda gc().
A cos takiego zrobisz na http://dev.4programmers.net ?

Tak, najpierw błąd był na dev.4p.net, więc sprawdziłem u siebie i też był.

Notice: Undefined variable: result in /home/coyotedev/framework/lib/db/mysql.php on line 299
MySQL error: Powt�rzone wyst?pienie 'f8dd390d1ecbd45d4e99126b8cf191cd' dla klucza 1
INSERT INTO coyote_session (session_id, session_start, session_stop, session_user_id, session_ip, session_page) VALUES("f8dd390d1ecbd45d4e99126b8cf191cd", 1230722872, 1230722872, 3, "212.76.*.*", "/index.php")
Warning: Cannot modify header information - headers already sent by (output started at /home/coyotedev/framework/lib/db/mysql.php:299) in /home/coyotedev/framework/lib/output.class.php on line 73

Ok, wiem co jest problemem. Jeżeli cookie "coyotedev_ip" wygaśnie, to właśnie wtedy pojawia się ten błąd (oczywiście można usunąć go ręcznie). Można by zatem było sprawdzać integralność sesji, aby to wyeliminować.

u mnie cookie "coyotedev_ip" wygasa 31 grudnia 2008 1225. czyli jak już wygaśnie, to będzie ten dokładnie błąd.

//Edit: błąd pojawia się tylko w przypadku ręcznego usunięcia cookie.

http://weblog.cityblend.pl/4pdeverror.jpg

Jest jeszcze taki błąd:

Notice: Undefined variable: result in /framework/lib/db/mysql.php on line 299
MySQL error: Powt�rzone wyst?pienie 'b882fe1280507634356ed39172399e74' dla klucza 'session_id'
INSERT INTO coyote_session (session_id, session_start, session_stop, session_user_id, session_ip, session_page) VALUES("b882fe1280507634356ed39172399e74", 1230816146, 1230816146, 2, "212.76.*.*", "/index.php/adm")
Warning: Cannot modify header information - headers already sent by (output started at /framework/lib/db/mysql.php:299) in /framework/lib/output.class.php on line 74

Warning: Cannot modify header information - headers already sent by (output started at /framework/lib/db/mysql.php:299) in /framework/lib/controller.class.php on line 88
0

No tak. Ale ciastko coyote_ip bylo ustawione z data waznosci na czas trwania sesji, czyli domyslnie - 10 min. Czyli po tym czasie sesja powinna wygasnac w bazie danych (skasowanie rekordu) oraz w cookie.

Niewazne. W kazdym razie zmienilem nieco kod zwiazany z sesja. Poprawki na SVN, timeline tutaj: http://4programmers.net/trac/coyote/timeline?from=01%2F03%2F09&daysback=0&ticket=on&changeset=on&milestone=on&wiki=on&update=Update

0

Wiem, sprawdzałem wszystko i niestety, ale w bazie nie wygasa, może coś nie tak z wywołaniem SessionGC

0

Ja tylko pozwolę sobie na małe ostrzeżenie: trzeba BARDZO uważać jeśli porównuje się czas w bazie mysql z czasem z php - serwery moga być na różnych maszynach i mieć lekko rozsynchronizowane zegary, może być ustawiona niewłaściwa strefa czasowa w serwerze mysql itp.

0

Poprawilem powazny blad w user.class.php polegajacy na wywolaniu nie tej metody co trzeba ;) Zrob SVN Update i powiedz mi, czy nadal nie usuwa w razie potrzeby? Chociaz to akurat nie powinno miec zwiazku z tym bledem.

Masz wlaczony tryb DEBUG? Tzn. pasek narzedziowy u gory? Tam na zaklace SQL powinienes widziec zapytania SQL. Co jakis czas tam na liscie powinno znalezc sie zapytanie kasujace z coyote_session przeterminowane sesje.

0

Zrobiłem update już kilka godzin temu, od kliku godzin testuje i nie powtarza się już ten błąd. Jeszcze będę próbował, ale wydaje mi się, że już jest ok. Zrobiłem tez update output.class.php w sprawie cookie, możliwe, że problemem było to, że testuje system z wykorzystaniem w pełni wildcard.

0

Mam nadzieje, ze bedzie dobrze :)
Co do output.class.php, to wiem - widzialem. <ort>Zamknelem </ort>ten ticket w trakcerze.

Dzieki.

1 użytkowników online, w tym zalogowanych: 0, gości: 1