Tablica post nie istnieje, po jej zatwierdzeniu

Witam, mam taki kontroler i jak widać w metodzie index renderuję widok z formularzem, a w metodzie make waliduję formularz. No i wygląda na to, iż na etapie uruchomienia metody make, tablica POST już nie istnieje. W ogóle nie wiem dlaczego tak się dzieje. Ma ktoś jakiś pomysł ?

 

PS. Kontroler -> http://pastebin.com/xwXmZ2QN

Prawdopodobnie bez kodu począwszy od formularza, który generuje POST, przez stronę na której wywoływany jest kontroler, aż do samego kontrolera, który raczyłeś wkleić jako Post Scriptum, trudno będzie coś ustalić, można co najwyżej zgadywać.

Hmm, dziwna sytuacja, ponieważ jak się okazało nie działa sprawdzanie token’a, które wcześniej działało poprawnie.

 

To klasa Token:

<?php

class Token {
	
	static function create($tokenName = 'token') {
		return Session::set($tokenName, md5(uniqid()));
	}

	static function check($token, $tokenName = 'token') {

                // Czy dany token istnieje w sesji && czy istnieje token && czy token z sesji równa się token-owi z formularza

		if(Session::has($tokenName) && isset($token) && Session::get($tokenName) === $token) {
			Session::delete($tokenName);
			return true;
		}
		return false;
	}

}

No a metody check używam przy walidacji. Walidacja znajduje się w metodzie make kontrolera rejestracji, który raczyłem dodać w 1 poście.

 

Przypomnę, że działało, gdy formularz miałem w tym samym pliku, co formularz. We formularzu mam coś takiego:

<input type="hidden" name="token" value="<?= Token::create() ?>" />

Jak usunę sprawdzanie token’a to walidacja formularza działa poprawnie.

 

#Edit

 

Na stronie z formularzem wypisałem sobie token’a z sesji, który jest tworzony podczas wywołania metody Token::create(), i te token’y so identyczne, więc ja się poddaję. Wszystko powinno działać…

Możesz narzekać, że wszystko jest bez sensu, że się poddajesz, że nie działa i się mazać jak dziecko. Albo możesz zacząć współpracować.

Formularz:

<form method="post" autocomplete="off" action="registration/make">
    <div class="form-group">
	<input type="text" name="username" placeholder="Username..." value="<?= Input::get('username') ?>" class="form-control" />
    </div>
    <div class="form-group">
	<input type="text" name="email" placeholder="Email..." value="<?= Input::get('email') ?>" class="form-control" />
    </div>
    <div class="form-group">
	<input type="password" name="password" placeholder="Password..." class="form-control" />
    </div>
    <div class="form-group">
	<input type="password" name="password_repeat" placeholder="Repeat password..." class="form-control" />
    </div>
    <input type="hidden" name="token" value="<?= Token::create() ?>" />
    <input type="submit" name="submit" value="Sign up" class="btn btn-primary btn-block">
</form>

Klasa Session:

<?php

class Session {
	
	static function start() {
		return session_start();
	}
	
	static function get($key) {
		return $_SESSION[$key];
	}
	
	static function set($key, $value) {
		return $_SESSION[$key] = $value;
	}
	
        // ta metoda jeszcze nie gotowa

	static function flash($key, $value = '') {
		if(self::has($key)) {
			$session = self::get($key);
			self::delete($key);
			return $session;
		} else {
			self::set($key, $value);
		}
	}

	static function has($key) {
		if(isset($_SESSION[$key])) {
			return true;
		}
		return false;
	}
	
	static function delete($key) {
		return session_unset($_SESSION[$key]);
	}

}

 

Ponieważ wcześniej musiałem sprawdzić czy działa mały Query Builder i formularz jak i walidacje, miałem w głównym pliku index. A teraz po rozdzieleniu tych warstw, to nie działa.

Wybacz, ale nie rozdzieliłeś warstw. One nadal są źle zaprogramowane i podlegają tight-coupling. Jedyne co zrobiłeś to wydzieliłeś mocno związaną warstwę do osobnej jednostki kompilacyjnej (bądź w przypadku php interpretacyjnej, jeśli możemy tak powiedzieć). Kod niestety nadal jest mocno związany. Podstawy dependency injection się kłaniają.

 

Oczywiście, że nie musiałeś. Nie słyszałem o technice tymczasowego zaszywania testów w kodzie produkcyjnym. Zapoznaj się z terminem testy jednostkowe.

 

Poza tym nadal nie rozumiem. Napisałeś w skrócie: Miałem  formularz w tym samym pliku co formularz. Dla mnie to masło maślane, bez sensu. Ale jak chcesz może to jakiś głębszy filozoficzny sens…

 

Co do samego problemu:

Generalnie masz trochę małe pojęcia o tym co się dzieje w tzw. under the hood podczas tworzenia sesji. Sam fakt, że w kodzie zadeklarujesz sesje nie oznacza, że przeglądarka o niej wie. Wie o niej serwer (stąd na lokalnej stronie wiadomo, że ona istnieje), a do czasu przeładowania strony (a dokładniej otrzymania nagłówków), nie będzie o niej wiedziała przeglądarka. Dzieje się tak dlatego, że sesja jest finalnie i tak implementowana przy pomocy ciastka (dane są przechowywane po stronie serwera, ale musi istnieć identyfikator, który pozwoli nam powiązać sesję z użytkownikiem), które trzeba jakoś przesłać. Nie wiem co chcesz osiągnąć swoim spaghetti, więc proponuje generyczne rozwiązanie, które nie jest najlepsze, ale powinno działać w większości przypadków.

 

jesli (w tablicy $_SESSION nie istnieje klucz "s") { // to nie wykona się drugi raz, bo zmienną ustawiliśmy w ciele if-a + poinformowaliśmy przeglądarkę z użyciem przekierowania
   ustaw obiekt pod kluczem "s" w tablicy $_SESSION
   wykonaj przekierowanie, z użyciem GET na stronę na której jesteś //zwrotne przekierowanie, wymagane, aby przesłać nagłówki do przeglądarki (w tym ciastko), dopiero wtedy przeglądarka jest świadoma otrzymania sesji
   zapewnij ze dalsza część skryptu się nie wykona // just-in-case, aby nie polegać na "racing condition"
}
 
// reszta kodu, zależna od sesji

Jeśli mimo wszystko opornie idzie ci zrozumieć co napisałem: Google ->  php session need refresh

Jednak u mnie nie zachodzi to co Pan mi wytłumaczył, ponieważ w widoku(tym z formularzem) mam ifa, który sprawdza czy sesja z tokenem istnieje, i to działa. Tzn. po sprawdzeniu czy dana sesja istnieje, wypisuje sobie i to działa, lecz gdy wyślę formularz, ta sesja już nie istnieje.

 

Zauważyłem jednak coś dziwnego, gdy przechodzę na następną stronę(metodę), to wszystkie zmienne w sesji się kasują. Np. w tym kontrolerze rejestracji tworzę sobie metodę test , w której mam to:

public function test() {
    Session::set('test', 'lolololo');
    echo "<pre>" , print_r($_SESSION) , "</pre>";
}

a w test2

public function test2() {
    echo "<pre>" , print_r($_SESSION) , "</pre>";
}

to mi php wypisuje, że zmienna “_SESSION” jest nieznana ;/ Jak to jest możliwe, że po wywołaniu innej metody, zmienna sesja jest czyszczona ?

Możesz pokazać, jak wyglądają pliki (pełna zawartość pliku, to ważne nie pomijaj niczego z tego pliku), w którym wołasz powyższe metody?

PS Możesz nawet wkleić cały projekt (wszystkie pliki) gdzieś, np. na github. Bo niestety bez podglądu całości projektu, trudno coś powiedzieć, można zgadywać:

  1. Jednak nie robisz przekierowania, tylko tobie się tak wydaje i zmienna z sesja ci się nie wysyła do przeglądarki.

  2. W zasadzie w całości wklejonego kodu nie widziałem wywołania metody session_start() (wołasz ją w ogóle?) bez tego sesja się nie rozpocznie i serializowane dane nie zostaną deserializowane i wepchnięte do tablicy SESSION. Przez to $_SESSION zachowuje się jak zmienna lokalna.

  3. Może to coś konfiguracyjnego, w serwerze, albo w przeglądarce

Tylko tak jak mówię to zgadywanie, bo:

  1. Możesz robić przekierowanie, tylko nie pokazujesz mi tego fragmentu

  2. Możesz wołać session start, tylko nie pokazujesz jakiegoś include’a

  3. Można to wykluczyć, dopiero jak zrobię całościowy code review.

Aż głupio się przyznać, ale session_start(), był wywoływany zbyt późno i to był błąd… ](*,)

Cóż bywa. Z kodu, który podałeś, nie wynika, że w ogóle było takie wywołanie. Połowicznie zgadłem.

Rada na przyszłość, wrzuć sobie kod na jakiś serwis hostujący system kontroli wersji, który można przeglądać z zewnątrz. Następnym razem poza podaniem klasy, gdzie lokalizujesz efekt końcowy błędu warto też dołączyć całość. Błąd koniec, końców nie musi być tam, gdzie występuje efekt, ale wynikać z jakiś zależności.