Drukowana wersja tematu

Kliknij tu, aby zobaczyć temat w orginalnym formacie

Forum PHP.pl _ PHP _ odświeżanie strony, zapis

Napisany przez: skowron-line 26.03.2006, 21:56:00

napisalem prosty skrypt dodawania komentarzy na stronke i mam pytanie jak zrobic zeby skrypt nie dodawal ciagle tygo samego po nacisnieciu odswieżania??

----
Posty będące duplikacją postów już zawartych w temacie, będą bez ostrzeżenia usuwane. Ma to zapobiedz tworzeniu się zbędnego śmietnika
moderator

Napisany przez: TomASS 26.03.2006, 22:24:54

Możesz albo zablokować możliwość dwóch postów tego samego usera na dany temat pod sobą, albo sprawdzać np. czy pierwsze (powiedzmy) 50 znaków poprzedniego posta, różnią się od tego właśnie dodawanego.

Napisany przez: mike_mech 27.03.2006, 10:09:24

http://forum.php.pl/index.php?showtopic=36933&hl=1062

Napisany przez: huntercs 27.03.2006, 11:23:36

w prosty sposób można to osiągnąć, mianowicie:
np.:

  1. <?php
  2. if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply();
  3. ?>

a w forumularzu:
  1. <form action="" method="post">
  2. <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?>
  3. <input name="AddReply" type="hidden" value="1">
  4. ...
  5. </form>

teraz po odświeżeniu strony, 2 raz nie doda się wpis do bazy guitar.gif

Napisany przez: skowron-line 27.03.2006, 21:35:11

a jezeli chcem zrobic to przy zapisie do pliku .txt??
Moze jest to banalne pytanie ale naprawde niewiem

Napisany przez: erix 28.03.2006, 07:27:16

to nie ma znaczenia, co robisz po submicie formularza, w skrypcie

Napisany przez: nospor 28.03.2006, 07:34:02

Cytat(huntercs @ 2006-03-27 12:23:36)
w prosty sposób można to osiągnąć, mianowicie:
np.:
  1. <?php
  2. if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply();
  3. ?>

a w forumularzu:
  1. <form action="" method="post">
  2. <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?>
  3. <input name="AddReply" type="hidden" value="1">
  4. ...
  5. </form>

teraz po odświeżeniu strony, 2 raz nie doda się wpis do bazy guitar.gif

no nie do konca tak jest. tu chodzi o taki refresh przez wcisniecie F5 lub ctrl+r, a nie ponowne wcisniecie ręcznie submita.
Taki refresh o którym mowa, wysyla jeszcze raz ten sam formularz, z tymi samymi polami i wartościami. Tu nic nie da, ze ty dodasz dodatkowe pole, gdyż ono nie zostanie przy refreshu uwzględnione

Napisany przez: skowron-line 28.03.2006, 11:11:27

to chyba najlepszym sposobem jest po nacisnieci submita zrobic zapis i przekierowac na stronke na ktorej sa wyswielane komentarze

Napisany przez: nospor 28.03.2006, 12:14:16

Ja to robię jeszcze inaczej.
PRzy tworzeniu formularza, generują unikalny identyfikator, na podsawie chociazby timestampa i czegos tam jeszcze. Identyfikator ten dokladam do formularza, jako wartość pola ukrytego. Po wyslaniu formularza sprawdzam, czy dany identyfikator jest zapisany w sesji. jesli nie, zapisuję go do sesji a formularz akceptuję jako prawidlowy. jesli jednak ten identyfikator jest juz zapisany w sesji, znaczy ze jest to refresh i dane z formularza odrzucam.
Dzieki takiemu podejsciu, mogę pozostac dalej na stronie z formularzem, bez przekierowania. Jest to mi czasami potrzebne.

Napisany przez: skowron-line 28.03.2006, 20:52:50

a do bazy danych to wymyslilem ze moge wyciagnac ostatni rekord z bazy i porownac go z wpisywanym i jesli bedzie identczny to odrzucic. to chyba nienajgorsze rozwiazanie

Napisany przez: huntercs 28.03.2006, 23:01:57

tylko po co mieszać do tego bazę? dodaktowe zapytanie... smile.gif
lepiej zrobić z COOKIE/SESSION
coś podobnego do tego co zaproponował nospor

Napisany przez: Kuziu 28.03.2006, 23:15:40

A nie prościej zrobić np. dodanie commenta po czym header("Location: adres.php");

I wszystkie F5 z głowy ?

Napisany przez: mike_mech 29.03.2006, 08:56:34

Cytat(huntercs @ 2006-03-28 23:01:57)
tylko po co mieszać do tego bazę? dodaktowe zapytanie... smile.gif

Ależ jakie dodatkowe zapytanie?
Wystarczy nałożyć kluch UNIQUE.

Kliknij w linka, którego dałem na górze wątku.
Ja uważam że to jest najlepsze rozwiązanie.

Nie angażujesz żadnej sesji, ciasteczek ani niczego.

Po prostu działa biggrin.gif

Napisany przez: nospor 29.03.2006, 08:59:38

Cytat
Wystarczy nałożyć kluch UNIQUE.
Ale nalozysz klucz na wszystkie pola? a co jesli rekord moze sie powtorzyc poprzez jawne wpisanie? A co jesli nie mozna zalozyc unique na zadne pole, gdyz kazde z osobna moze sie powtarzac. Osobiscie nie podoba mi ten sposob zabezpieczenia przed refreshem. Nie bedziemy przeciez zmieniac struktury bazy tylko pop to by uniknać refresha. Do tego są inne rzeczy juz tu wymienione

Napisany przez: mike_mech 29.03.2006, 09:12:59

Cytat(nospor @ 2006-03-29 08:59:38)
a co jesli rekord moze sie powtorzyc poprzez jawne wpisanie? A co jesli nie mozna zalozyc unique na zadne pole, gdyz kazde z osobna moze sie powtarzac.

Więc należy wybarć kombinacją pól, które powtarzać się nie powinny.
W 99% przypadków kombinacja taka istnieje.

Cytat(nospor @ 2006-03-29 08:59:38)
Osobiscie nie podoba mi ten sposob zabezpieczenia przed refreshem. Nie bedziemy przeciez zmieniac struktury bazy tylko pop to by uniknać refresha. Do tego są inne rzeczy juz tu wymienione

Prezcież to nie jest zmiana struktury bazy. Przy jej projektowaniu powinno się założyć unikalność na pola, które tego wymagają.
A poza tym gdyby to do aplikacji klienckiej miało należeć kontrolowanie unikalności wprowadzanych danych, to po co w bazach byłby w ogóle ten mechanizm.

Ja uważam że najlepiej baza zadba sama o siebie, mało tego jest to sapoób właśnie do tego stworzony, i jeszcze mniej tego smile.gif najwygodniejszy.
Nie powiesz mi ~nospor, że pisanie mechanizmów ciasteczek, zapisywanie informacji w sesji, ciągłe pilnowanie tego jest wygodniejsze niż blok try ... catch i wyrzucanie wyjątku z odpowienim kodem (1062 w tym przypadku).

Napisany przez: nospor 29.03.2006, 09:18:12

dalej sie z tobą nie zgadzam. Istnieją przecież tabele, w których nie może byc pol unikatowcyh. nie dlatego ze baza na to nie pozwala, ale dlatego, ze zalozenia dla danej tabeli na to nie pozwalają. a konkretnie pozwalają na takie same rekordy. moze tak byc.

Cytat
Nie powiesz mi ~nospor, że pisanie mechanizmów ciasteczek, zapisywanie informacji w sesji, ciągłe pilnowanie tego jest wygodniejsze niż blok try ... catch i wyrzucanie wyjątku z odpowienim kodem (1062 w tym przypadku).
Obys sie nie zdziwil smile.gif Zalezy czego uzywasz. Ja uzywam wlasnej klaski do formualrzy. Wiesz jak sa sprawdzam czy byl refresh czy nie? O tak:
  1. <?php
  2. if ($form->WasThisOperation()) http://www.php.net/echo 'To jest refresh';
  3. ?>
No i niepowiesz mi chyba, ze jest to nie wygodne winksmiley.jpg

edit:
Cytat
Prezcież to nie jest zmiana struktury bazy.
źle sie wyslowilem. chodzilo mi, ze nie bede zakladal uniqow jesli nie potrzebuje, tylko poto by refresha uniknąc

Napisany przez: mike_mech 29.03.2006, 09:30:15

Ładnie, bardzo ładnie.

Ja to robię tak:

  1. <?php
  2.  
  3. try
  4. {
  5. $objModel->addQuestion(); // chwilowe uproszczenie
  6. }
  7. catch( SQLException $objException )
  8. {
  9. switch( $objException->getCode() )
  10. {
  11. case 1062 : 
  12. $objRequest->setError( 'question', 'Takie pytanie już istnieje.' );
  13. break;
  14.  
  15. default : 
  16. $objRequest->setError( 'error', 'Nie można dodać pytania.' );
  17. break;
  18. }
  19.  
  20. return View::ERROR;
  21. }
  22.  
  23. ?>


Połączenie Agavi i Creole'a.

Jak mi wyskoczy wyjątek to mogę z aplikacją zrobić wszystko, zależy to od tego jaki.

Każdy ma swój najlepszy sposób biggrin.gif

Napisany przez: nospor 29.03.2006, 10:00:19

A że ja upierdliwy jestem...
A co w przypadku, gdy mamy formularz, ale jego wynik nie jest zapisywany do bazy, tylko wysylany mailem? Jest to tzw. formularz kontaktowy. Wtedy uniqi na bazie nam nic nie dadzą winksmiley.jpg
Oczywiście można wówczas użyc header, lub sesje.

A jeszcze pytanko bo nie sprawdzalem tego nigdy. Zalozmy ze uzywamy header, zeby przekierowac po wyslaniu formularza. A czy jest mozliwa sytuacja, ze koles zanim zostanie przekierowany zdązy wcisnąć F5, czyli tym samym ponownie wysle ten sam formularz?

Napisany przez: skowron-line 29.03.2006, 10:00:31

ja napisalem cos takiego i dziala

  1. <?php
  2. http://www.php.net/mysql_connect('localhost','root','');
  3. http://www.php.net/mysql_select_db('skowron');
  4.  
  5. $wpis_id = $HTTP_POST_VARS['wpis_id'];
  6. $podpis = $HTTP_POST_VARS['podpis'];
  7. $wpis = $HTTP_POST_VARS['wpis'];
  8.  
  9. http://www.php.net/echo"<form action=f5.php method=post>
  10. podpis: <input type=text name=podpis size=20><br>
  11. wpis: <br><textarea rows=5 cols=10 name=wpis></textarea>
  12. <input type=submit name=zapisz value=zapisz>";
  13.  
  14. if(http://www.php.net/isset($zapisz))
  15. {
  16. $zapytanie = 'SELECT wpis FROM wpisy ORDER BY wpis_id DESC LIMIT 1';
  17. if($a = http://www.php.net/mysql_query($zapytanie))
  18. {
  19. while($wiersz = http://www.php.net/mysql_fetch_array($a))
  20. {
  21. http://www.php.net/echo"<input type=hidden name=z_bazy value='".$wiersz['wpis']."'>";
  22. }
  23. }
  24. http://www.php.net/echo"$z_bazy";
  25. if($wpis == $z_bazy)
  26. {
  27. http://www.php.net/echo"takie same";
  28. }
  29. else
  30. {
  31. $zapytanie = 'INSERT INTO wpisy values("","'.$podpis.'","'.$wpis.'")';
  32. if(!http://www.php.net/mysql_query($zapytanie))
  33. {
  34. http://www.php.net/echo"blad ".http://www.php.net/mysql_error()."";
  35. }
  36. }
  37. }
  38. ?>

prosze o lekka krytyke jesli komus sie nie bedzie podobac winksmiley.jpg

Napisany przez: nospor 29.03.2006, 10:20:24

ale o ile dobrze wczytuje sie w ten kod, to ty zrobiles to, co zaproponowal wczesniej huntercs (i to nie dokladnie tak). Jak juz pisalem wczesniej to nie zadzial przy refreshu.

W jaki sposob ty to testowales?
Bo to wyglada tak:
jesli wcisniesz zapisz, to dogenerowujesz do formularza hiddena, z ostatnim wpisem z bazy, ale ten wpis nie jest tym, co aktualnie dodajesz. Potem sprawdzasz, czy wpis z bazy z hiddena rowny jest aktualnemu. To bedzie rowne dopiero przy ktoryms tam razie.
A wsytuacji, gdy wygenerujesz formularz pierwszy raz, wscisniesz zapisz a potem dasz refresh, to ci nie zadziala. No chyba ze mamy co innego na mysli mówiąc refresh winksmiley.jpg

Napisany przez: skowron-line 29.03.2006, 10:38:41

To ma byc tak:
wpisujesz jakis text i naciskasz submit wtedy on wyciaga ostatni wpis porownuje go z tym co wpisales jesli jest inny to zapisuje.
Potem jak nacisniesz F5 to znow sprawdza i jesli jest taki sam to go odrzuca.

P.S trzeba dopisac jeszcze jesli pola sa puste zeby nie zapisywal do bazy

Napisany przez: nospor 29.03.2006, 10:41:49

Cytat
wpisujesz jakis text i naciskasz submit wtedy on wyciaga ostatni wpis porownuje go z tym co wpisales jesli jest inny to zapisuje.
Ale Twoj skrypt co pokazales, tego nie realizuje. Po wcisnieciu submita, ty ostatni wpis do bazy zapisujesz w polu ukrytym, a potem sprawdzasz, czy to pole ukryte zgadza się z tym co wpisales. Tylko sęk w tym, ze zmienna pola ukrytego, nie jest jeszcze utworzona... Nie po pierwszym submicie. A po refreshu tez nie będzie, gdyz refresh wysyla jeszcze raz poprzednio wyslany formularz

Napisany przez: skowron-line 30.03.2006, 10:16:35

nospor zwracam honor przeanalizowalem ten skrypt i nie dziala jak nalezy.

Napisany przez: Krisu 31.03.2006, 19:55:20

Da sie zrobic jakos tak, zeby dodaj i zapisz bylo w jednym pliku??
Jak wtedy mam uzywac zmiennych?

  1. <http://december.com/html/4/element/form.html method="post" action="dodaj.php">
  2. <http://december.com/html/4/element/input.html class="input" name="pseudo"><http://december.com/html/4/element/br.html>
  3. <http://december.com/html/4/element/textarea.html rows="3" cols="28" name="komentarz"></http://december.com/html/4/element/textarea.html>
  4. <http://december.com/html/4/element/center.html><http://december.com/html/4/element/input.html class="input" type="button" value="komentuj" onclick="location='index.php'" /></http://december.com/html/4/element/center.html>
  5. </http://december.com/html/4/element/form.html>

  1. <? 
  2. $komentarz = $_POST["komentarz"];
  3. $pseudo = $_POST["pseudo"];
  4. ?>
  5. <?
  6. $plik="../txt/turniej/komentarz.txt";
  7. $text="$komentarz||$pseudo|| \n";
  8. $temp=http://www.php.net/implode(http://www.php.net/file($plik));
  9. $fp=http://www.php.net/fopen($plik ,"w");
  10. http://www.php.net/fwrite($fp ,$text);
  11. http://www.php.net/fwrite($fp ,$temp);
  12. ?>

Napisany przez: tes 11.04.2006, 01:21:35

nospor, a mógłbyś napisać jak potem z tej sesji wyrzucasz indentyfikator tak aby było gotowe na kolejne użycie formularza ?

Napisany przez: nospor 11.04.2006, 06:47:36

@tes ja go nie wyrzucam. Jak pisalem, generuję unikalne identyfikatory. Przy kolejnym uzyciu formularza, generowany jest kolejny unikatowy identyfikator smile.gif

Napisany przez: Pilsener 19.04.2006, 08:31:30

Porównać IP gościa i czas - moim zdaniem najlepszy i uniwersalny sposób.

$_SERVER['REMOTE_ADDR'] - pobiera IP gościa
time() - czas

Można zapisać IP i czas w bazie txt/sql (dużo baz standardowo zapisuje IP i czas dodania, wtedy już jesteśmy w domu), lub przejściowo w zmiennych.

Potem wystarczy użyć prostego warunku IF - jeśli IP są różne to wysyła, jeśli identyczne to liczy różnicę czasów, jeśli różnica czasów jest mniejsza niż np. 60 sekund to nie pozwala wysłać.

Napisany przez: free 16.11.2006, 13:44:16

Ja stosuje prosta metode, poprostu za pomocą JS lub php przenosze gościa do nowej strony z podziekowaniami lub z wyswietleniem wynikow /w zaleznosci od potrzeb/.
JS:

  1. <?php
  2. ...
  3. {
  4. http://www.php.net/echo '<script language="JavaScript">window.location="Twojastrona.php";</script>';
  5. }
  6. ...
  7. ?>


php:
  1. <?php
  2. adres('adres.php');
  3. ?>

gdzie funkcja adres ma postac:
  1. <?php
  2. function adres($url) {
  3. if (!http://www.php.net/headers_sent()) {
  4. http://www.php.net/header('Location: http://' . $_SERVER['HTTP_HOST'] .
  5.  http://www.php.net/dirname($_SERVER['PHP_SELF']) . '/' . $url);
  6. } else {
  7. http://www.php.net/die('Nie mogę przekierować. Wysłano już nagłówki (wyjście).');
  8. }
  9. }
  10. ?>

Napisany przez: Cypherq 19.04.2007, 14:42:07

O rany, zaczęliście całą religię do tego problemu dobudowywać tongue.gif Ja używam czegoś co jednocześnie jest filtrem antyspamowym. Tworzę przy dodawaniu komentarza cookie z czasem dodania ostatniego komenta i później przy dodawaniu następnego, sprawdzam kiedy dodany był poprzedni.

Chyba, że czegoś nie doczytałem i problem rzeczywiście wymaga większego sprytu? ;>

Napisany przez: Sedziwoj 19.04.2007, 15:41:41

Może większego nie, ale jak ja szybko piszę i odpowiadam na wiele postów, to musiał byś wiedzieć czy to było w tym dziale i czy to ten sam post czy następny...
Czasem jest szybka wymiana zdań i ciężko ustalić czy się coś dodaje drugi raz czy pierwszy.

Napisany przez: l0co 6.09.2007, 12:58:17

Niepotrzebnie zakładałem nowy wątek - więc dopisuję tu swoje trzy grosze na temat techniki z headerem - czyli http://nexoft.pl/wiki/index.php?title=Redirect_After_POST pattern (w linku).

Rozwiązanie które proponuję nie wymaga żadnego kombinowania z "natywnym" kodem aplikacji ani z kombinowaniem na bazie danych. Zadziała dla wszystkich skryptów aplikacji napisanych wcześniej i nie będzie też trzeba wymyślać nowych sposobów zabezpieczania dla kolejnego formularza - skryptu.

Napisany przez: WebCM 30.12.2007, 14:52:26

Jeżeli chcemy tylko ochronić skrypt przed przypadkowym wciśnięciem F5, dobrym rozwiązaniem jest wysyłanie formularzy za pomocą AJAX. smile.gif W wyznaczonym miejscu (np. między nawigacją) otrzymujemy taki wynik (np. komentarze, informację o przebiegu akcji, wypełniony formularz + błędy do poprawy), jaki otrzymalibyśmy, wysyłając je tradycyjnie. Oczywiście kod JS powinien nadpisywać atrybuty <form> lub submit i przejąć kontrolę nad formularzem.

Napisany przez: nospor 30.12.2007, 14:57:21

źle.
Ajax/js nie jest rozwiązaniem na problemy. Owszem, ma to wspomóc ale nie zastąpic. Zabezpieczenia po stronie serwera muszą być, niezależnie czy wspomagasz się js/ajax czy nie. Bo jak ktoś sobie wyłączy js to albo twoja strona nie bedzie dla niego dostępna, albo co gorsza - Twoja strona będzie bezbronna bo nie pomyslales ze ktos moze nie uzywac js.

Napisany przez: be2k 26.01.2008, 12:50:49

to moze i ja dorzuce swoje 3 grosze.

# rozwiazanie w stylu js/ajax jest moim zdaniem chybione, bo po co wogole angazowac ajaxa do rzeczy tak banalnej jak wyslanie formularza.

# rozwiazanie z dodawaniem ukrytego pola do formularza po kliknieciu submit w formularzu tez nie bedzie dzialalo, bo klikniecie F5 powoduje wyslanie ponownie TEGO SAMEGO formularza, wiec nie zostanie wyslany nowy z nowo wygenerowanym polem - a chodzi tutaj chyba o zabezpieczenie przez refresh'em a nie ponownym klikaniem w submit.
kolega wczesniej podawal przyklad:

  1. <?php
  2. if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply();
  3. ?>

a w forumularzu:
  1. <form action="" method="post">
  2. <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?>
  3. <input name="AddReply" type="hidden" value="1">
  4. ...
  5. </form>

i tak jak napisalem to oczywiscie nie dziala, bo klikniecie F5 (refresh) nie powoduje ponownej generacji formularza czyli pole
  1. <http://december.com/html/4/element/input.html name="Re" type="hidden" value="1">

nie zostanie wyslane z formularzem

# rozwiazanie z zapisywaniem IP oraz czasu i sprawdzanie czy nowy post jest z tego samego IP co ostatni, jesli tak to ile minelo czasu - jest rowniez niepoprawne. po pierwsze co jesli dodaje dwa posty w roznych topicach w bardzo krotkim czasie? z tym oczywiscie mozna sobie poradzic, bo mozna sprawdzac czy nowy post jest z tego samego topicu czy nie, ale na jakiej zasadzie ma byc liczony czas po ktorym mozna ponownie dodac posta? 60 sekund jak zaproponowal kolega wyzej? to klikne F5 po 65 sekundach. 120 sekund? to klikne F5 po 125 sekundach? 240 sekund? itd. To rozwiazanie moze byloby i dobre, ale na calkowicie inny problem. Na spamerow, trolli czy inne typu wynalazki, czyli zablokowanie mozliwosci wysylanie duzej ilosci postow przez tego samego uzytkownika w krotkim czasie. Ale bynajmniej nie jest to rozwiazanie na refresh o ktory sie w tym topicu rozchodzi.

# rozwiazanie z przechwytywaniem wyjatkow z bazy owszem dziala, ale tylko jesli zapisujemy tresc formularza do bazy. a co jesli ma byc zapisywany do pliku, wyslany mailem, czy cokolwiek innego ma sie z nim dziac?

# rozwiazanie z dodawaniem atrybutow UNIQUE do pol bazy zadziala jak wyzej - tylko w przypadku, gdy dane z formularza maja wyladowac w bazie.



Wiec jak to najlepiej zrobic i tak zeby dzialalo zawsze?

# jednym z rozwiazan jest to o czym zapewne wiekszosc z was wie. czyli przekierowanie w pliku do ktorego odwoluje sie akcja formularza.
jesli mamy formularz:
  1. <http://december.com/html/4/element/form.html action="wykonaj_akcje.php">
  2. ...
  3. </http://december.com/html/4/element/form.html>


to w pliku wykonaj_akcje.php zapisujemy:
  1. <?
  2. //jakies akcje
  3. http://www.php.net/header("Location: akcja_wykonana.php")
  4. ?>


# drugie rozwiazanie, ktore ja osobiscie najczesciej stosuje, jest to o czym pisal nospor.
w momencie generowania formularza generujemy pole typu "hidden" z jakims hashem/tokenem czy jak tam kto woli nazywac. ma to byc jakis unikalny ciag znakow/liczb:
  1. <input type="hidden" id="hash" name="hash" value="<?=generateHash();?>">
  2. <?php
  3. function generateHash()
  4. {
  5. return http://www.php.net/md5(http://www.php.net/time() * http://www.php.net/rand()); //samo time() nie wystarczy, gdyz jego wartosc zmienia sie co sekunde a to za malo
  6. }
  7. ?>


wartosc tego pola zapisujemy do sesji, do cookie, do pliku albo do bazy - jak komu w danej chwili wygodniej/jakie ma mozliwosci.
w przypadku zapisu da bazy tabela z postami bedzie miala dodatkowe pole "hash". po kliknieciu F5 (refresh) zostanie wyslany ten sam formularz, czyli dokladnie z tym samym hashem - nie bedzie on od nowa wygenerowany. teraz wystarczy sprawdzic czy dany hash mamy juz w sesji, w bazie, w cookie, w pliku czy gdziekolwiek indziej i problem z powtorzeniem zalatwiony
i tutaj juz nie chodzi o sprawdzenie czy to ten sam uzytkownik, to samo IP, ponownie ten sam tekst czy cokolwiek innego - sprawdzamy dokladnie to o co chodzi - czy jest proba ponownego wyslania tego samego formularza.

Napisany przez: mroczek 9.11.2008, 13:23:14

Jeżeli chcemy zrobić to za pomocą sesji to sugerując się wskazówkami be2k możemy to zrobić w następujący sposób:

Dodajemy wpis do formularza pamiętając, że same wywołanie funkcji nie wyświetli danych. Musimy dodać echo:

  1. <http://december.com/html/4/element/input.html type="hidden" id="hash" name="hash" value="<?php echo generateHash();?>">


Funkcja generateHash():
  1. <?php
  2. function generateHash()
  3. {
  4. return http://www.php.net/md5(http://www.php.net/time() * http://www.php.net/rand());
  5. }
  6. ?>


A teraz nasz plik php, który odbiera dane z formularza:
  1. <?php
  2. if (!$_SESSION['adduser'] || $_POST['hash'] != $_SESSION['adduser'] ){
  3. $_SESSION['adduser'] = $_POST['hash']; //dodajemy zmienną sesyjną adduser
  4. //wszystko co ma się wykonać po prawidłowym wysłaniu formularza
  5. }
  6. else
  7. {
  8. http://www.php.net/echo "Ten formularz był już wysłany";
  9. }
  10. ?>


Po odświeżeniu strony jeszcze raz zostaną wysłane wszystkie zmienne z formularza do skryptu. Jeżeli zawartość sesji adduser już istnieje i jest identyczna jak zawartość $_POST['hash']; tzn. że ten formularz był już wysłany.

Napisany przez: mlattari 27.02.2009, 01:31:26

hmm... najprościej to chyba przed przetwarzaniem i zapisem danych sprawdzić czy np.

  1. <?php
  2. if($_SESSION['poszłoooo']=='0') {}
  3. ?>

no i oczywiście po zapisaniu danych do bazy ustawiasz $_SESSION['poszlooo']='1' a jak już będzie bezpiecznie to znów zmieniasz wartość na '0' czyli można wysyłać formularz :-)
A jeżeli np. ma być jeden komentarz na stronkę przy każdej sesji to można

  1. <?php
  2. if (!$_SESSION[$_SERVER[PHP_SELF]]) { } else {}
  3. ?>


czy coś podobnego :-)

Pozdrawiam

Napisany przez: piotr94 12.11.2009, 16:39:52

u mnie problem znika wraz z samym tokenem - za każdym razem po wysłaniu skryptu zapisany wcześniej klucz z obrazka antyspamowego jest czyszczony do postaci '', wtedy przy naciśnięciu F5 skrypt wyświetli komunikat z prośbą o przepisanie poprawnego kodu z obrazka, a to oznacza że za pomocom F5 się nie będzie dało zdublować wpisu. Druga rzecz to oczywiście sesja + adresy IP, ale o tym już pisano wyżej ;-)

Napisany przez: Thorang Hoog 17.12.2009, 23:28:55

Hmm jak tak czytam wasze wypowiedzi to o mało nie popadam w paranoję blinksmiley.gif "Czy aby na pewno dobrze to rozwiązałem". Zapisanie w sesji informacji w stylu $_SESSION['poszło']==true sprawdza się jeśli masz tylko jeden formularz a i też nie zawsze bo wystarczy otworzyć stronę z formularzem w nowej zakładce i zmienna zostanie wyczyszczona.
Jak już doszliście do wspólnego wniosku jeśli dane nie są wysyłane do bazy danych sprawa się komplikuje. Pomyślałem więc kiedyś, że wykonam hash md5 z wysłanych danych przez użytkownika i zapiszę w sesji ale jako jedną z wartość tablicy winksmiley.jpg
A żeby się nie nazbierało multum kluczy to sesja wygasa po 30 minutach braku aktywności. Czekam na maratończyka co mi serwer zapcha aarambo.gif
Dobre jest też rozwiązanie usera powyżej. Skrypt po odświeżeniu zacznie się domagać prawidłowego klucza z obrazka.
...
Chociaż po otwarciu w nowej zakładce formularza po wypełnieniu tego pierwszego trzeba będzie odświeżać obrazek itp. itd...
Trudno o idioto-odporny program sciana.gif
;P

Napisany przez: andycole 1.10.2010, 22:55:14

Temat trochę leciwy, ale jako że przyklejony to chyba ważny i swoje 5 groszy do niego też wrzucę.

# Zgadzam się z Wami, że JS to nie rozwiązanie. Z problemem musi sobie radzić skrypt po stronie serwera na wypadek jeżeli JS będzie wyłączone.
# Co do unikalności wpisów w bazie. Jest to dodatkowy indeks, dodatkowe obciążenie przy jego przebudowywaniu (pomijając już kwestię miejsca na dysku).

Osobiście korzystam z przekierowania zaraz po wysłaniu formularza. Wszelkie komunikaty o powodzeniu/błędach trzymam w jednej zmiennej sesyjnej.

Napisany przez: radziopoke 7.02.2011, 17:13:44

Odkopię trochę temat bo i ja zacząłem poszukiwać sposobu na zablokowanie ponownego wysłania danych. Więc opowiem o swoim sposobie jak wykryć, czy strona została odświeżona lub czy ktoś wycofał się na stronę, która również chce ponownie wysłać dane bo takie przypadki wg mnie zdarzają się częściej.
No to to rzeczy:
2. Kolejne to sprawdzam czy dane ciasteczko jest takie same jak zmienna przesłana przez formularz

Kod
<?php
if (!isset($_COOKIE['krok'])) //sprawdzam czy ciasteczko kontrolujące istnieje
{
  setcookie('krok', 0, time()+259200); //jeżeli nie przypisuje mu wartość 0 i ustawiam tam na jakiś okres czasu )czym dłużej tym lepiej)
}
//jeżeli formularz został wysłany otrzymamy zmienną $_POST['krok']
if ($_COOKIE['krok']==$_POST['krok'])
{
  $refresh='nie';//jeżeli zmienna z formularza jest równa ciasteczku oznacza to, że nie było odświeżenia strony
  setcookie('krok', $_POST['krok']+1, time()+259200);i ustawiamy wartość ciasteczka o 1 większą
}
else
{
  $refresh='tak';
}
?>
... //jakiś tam kod html
<?php
  if ($refresh=='nie') //strona nie była odświeżana więc można przesłać dane
  {
    echo 'Przesłane dane: '.$_POST['krok'];
  }
  else
  {
    echo 'strona została odświeżona!!!'; //albo można pominąć blok else
  }
?>

<form action="" method="POST">
<input type="hidden" name="krok" value="'.$_COOKIE['krok'].'">;
<input type="text" name="jakiesdane">
<input type="submit">
</form>
...


Jedno ciasteczko, a może nadać się na kilku podstronach, bo nawet wycofanie się na stronę, która musi przetworzyć dane nic nie da smile.gif
Oczywiście przydało by się by jeszcze strona sprawdzała czy ciasteczka są włączone

ps. jest to skrypt, który sam wymyśliłem bo te sposoby, które podawaliście jakąś mi nie pasowały smile.gif skrypt wpisany tutaj został z lekka okrojony od mojego, wprawdzie mówiąc został napisany od nowa i dlatego jakieś literówki mogą się znaleźć smile.gif

Napisany przez: AndyPSV 11.03.2011, 12:08:54

dorzuce jeszcze do wypowiedzi wszystkich - prosty i oczywisty sposob: blokowanie przycisku submit, po kliknieciu (wymagane dolaczenie biblioteki jquery do kodu)

  1. <http://december.com/html/4/element/script.html type="text/javascript">jQuery(function($){$("form").submit(function(){$("button[type=submit]",this).attr("disabled","disabled");});});</http://december.com/html/4/element/script.html>

Napisany przez: picios 6.06.2011, 23:13:50

Stare już, ale dodam od siebie:

  1. <?php
  2. if (!http://www.php.net/isset($_SESSION['done'][$temat_id])) {
  3. $model->add();
  4. $_SESSION['done'][$temat_id] = true;
  5. } else {
  6. http://www.php.net/echo "dwa razy nie da rady :]";
  7. }
  8. ?>

oneeyedsmiley02.png dla małych projektów to wystarczy, przy większych sesja się "wypcha".

Napisany przez: olszam 11.10.2012, 15:52:08

stary temat ale może coś od siebie raz dam

  1. Napisz wiadomość<br />
  2. <form method="post" action="pw.php">
  3. <input type="hidden" name="blockrefresh" value="<?php http://www.php.net/echo http://www.php.net/md5(http://www.php.net/uniqid(http://www.php.net/rand())); ?>"/>
  4. <input type="text" name="temat"/><br />
  5. <textarea cols="40" rows="5"name="tresc">
  6. </textarea><br />
  7. <input type="submit" value="wyślij" name="wyslij"/>
  8. </form>
  9. <?php
  10. http://www.php.net/session_start();
  11. require 'konfig.php';
  12. if(http://www.php.net/isset($_POST['wyslij']))
  13. {
  14.  
  15. if(http://www.php.net/isset($_SESSION['blockrefreshdump']) && http://www.php.net/in_array($_POST['blockrefresh'],$_SESSION['blockrefreshdump']))
  16. http://www.php.net/echo 'Nie klikaj Refresh';
  17. else {
  18. //wstaw tu co chcesz by wysłało do bazy
  19. http://www.php.net/echo $_POST['temat'].'<br /> <br />';
  20. http://www.php.net/echo $_POST['tresc'].'<br /> <br />';
  21.  
  22. http://www.php.net/echo 'wiadomość została wysłana';
  23.  
  24. // na końcu trza dodać do sesji blockrefresh-a :)
  25. $_SESSION['blockrefreshdump'][]=$_POST['blockrefresh'];
  26. }
  27. }
  28. ?>


oczywiście jest to troszkę przerobiony pomysł z innego forum ale do dziś stosuję ten wzorek i zapewniam że działa. Z głowy pisałem bo nie chciało mi się po skryptach szukać czy na tym innym forum.

Napisany przez: mruz 16.03.2013, 20:40:22

Mam problem przy wysyłaniu takiego formularza z uploadem plików. Po wciśnięciu submit pliki jest przesyłany na serwer i w tym momencie możemy submit kliknąć parę razy, a tym samym zdublować upload. Ma ktoś jakiś pomysł jak temu zapobiec?

Napisany przez: CuteOne 16.03.2013, 21:01:43

  1. $_SESSION['crf'] = md5(uniqid());
  2. <input type="hidden" name="crf" value="<?= $_SESSION['crf'];?>" />


  1. if($_POST['crf'] !== $_SESSION['crf']) {
  2. http://www.php.net/die();
  3. }
  4. else {
  5.  
  6. $_SESSION['crf'] = http://www.php.net/md5(http://www.php.net/uniqid());
  7.  
  8. // upload pliku itp.
  9. }

Napisany przez: mruz 16.03.2013, 21:23:27

Dzięki @CuteOne, pomogło.

Napisany przez: Khartas 31.03.2013, 23:15:17

Mam podobny problem z powtarzaniem wpisów. Gdzie i co trzeba wpisać aby było ok? Headera nie mam jeszcze więc jeśli to pomoże powiedzcie gdzie i jak. Dopiero zaczynam PHP więc proszę o wyrozumiałość.

  1. <div id="TRESC">
  2. <?php
  3. include("polacz.php");
  4. $query = http://www.php.net/mysql_query("select * from news where id='".(int)$_GET['id']."'"); // 1
  5. $rekord = http://www.php.net/mysql_fetch_array($query);
  6. http://www.php.net/echo '<h1>'.$rekord[1].'</h1>Autor: '.$rekord[3].'<br/>Data: '.$rekord[2].'<p>'.$rekord[4].'</p>'; // 2
  7. $id_news = $rekord[0];
  8. ?>
  9. <hr>
  10. <br>
  11.  
  12.  
  13.  
  14. <?php
  15. if($_SERVER['REQUEST_METHOD'] == 'POST')
  16. {
  17. $query = http://www.php.net/mysql_query("insert into komentarze_news values('','".$id_news."',now(),'".$_POST['autor']."','".$_POST['tresc']."')");
  18. }
  19.  
  20. ?>
  21. <?php
  22. $query = http://www.php.net/mysql_query("select * from komentarze_news where id_news=$id_news");
  23. while($rekord = http://www.php.net/mysql_fetch_array($query))
  24. http://www.php.net/echo 'Autor:<B><I> '.$rekord[3] .' </B>Data dodania: '.$rekord[2].'</I><br>'.$rekord[4].'<p>';
  25.  
  26. ?>
  27. Skomentuj
  28. <form action="" method="post">
  29. autor <input type="text" name="autor">
  30. <br/>treść <textarea name="tresc" rows="10" cols="50"></textarea>
  31. <br/><input type="submit" value="Dodaj">
  32. </form>
  33. </div>

Napisany przez: gitbejbe 20.06.2013, 10:14:36

odgrzewam kotleta.

co do @up. to po 17stej linijce. czyli robisz header location po zapisie do bazy.

Co do całego tematu, to nie wierze w to co tutaj przeczytałem... Po przeczytaniu waszych wypocin stwierdzam, ze sens w tym temacie jest tylko jeden, to idealny przykład na to jak ludzie szukają dziury w całym.
kurna, jakieś funkcje, ciastka, sesje, bazy danych... ja pierdziele

uwaga, podaje jedyne słuszne rozwiązanie :

  1. //zapis do bazy
  2. http://www.php.net/header('Location: jakas_strona.php');


niesamowite co ?

Napisany przez: Damonsson 20.06.2013, 10:24:22

Niesamowitą głupotę, to napisałeś, co najwyżej. Po drugie, nie każdy chce robić przekierowanie.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)