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
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.
http://forum.php.pl/index.php?showtopic=36933&hl=1062
w prosty sposób można to osiągnąć, mianowicie:
np.:
<?php if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply(); ?>
<form action="" method="post"> <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?> <input name="AddReply" type="hidden" value="1"> ... </form>
a jezeli chcem zrobic to przy zapisie do pliku .txt??
Moze jest to banalne pytanie ale naprawde niewiem
to nie ma znaczenia, co robisz po submicie formularza, w skrypcie
<?php if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply(); ?>
<form action="" method="post"> <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?> <input name="AddReply" type="hidden" value="1"> ... </form>
to chyba najlepszym sposobem jest po nacisnieci submita zrobic zapis i przekierowac na stronke na ktorej sa wyswielane komentarze
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.
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
tylko po co mieszać do tego bazę? dodaktowe zapytanie...
lepiej zrobić z COOKIE/SESSION
coś podobnego do tego co zaproponował nospor
A nie prościej zrobić np. dodanie commenta po czym header("Location: adres.php");
I wszystkie F5 z głowy ?
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.
No i niepowiesz mi chyba, ze jest to nie wygodne
<?php if ($form->WasThisOperation()) http://www.php.net/echo 'To jest refresh'; ?>
Ładnie, bardzo ładnie.
Ja to robię tak:
<?php try { $objModel->addQuestion(); // chwilowe uproszczenie } catch( SQLException $objException ) { switch( $objException->getCode() ) { case 1062 : $objRequest->setError( 'question', 'Takie pytanie już istnieje.' ); break; default : $objRequest->setError( 'error', 'Nie można dodać pytania.' ); break; } return View::ERROR; } ?>
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ą
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?
ja napisalem cos takiego i dziala
<?php http://www.php.net/mysql_connect('localhost','root',''); http://www.php.net/mysql_select_db('skowron'); $wpis_id = $HTTP_POST_VARS['wpis_id']; $podpis = $HTTP_POST_VARS['podpis']; $wpis = $HTTP_POST_VARS['wpis']; http://www.php.net/echo"<form action=f5.php method=post> podpis: <input type=text name=podpis size=20><br> wpis: <br><textarea rows=5 cols=10 name=wpis></textarea> <input type=submit name=zapisz value=zapisz>"; if(http://www.php.net/isset($zapisz)) { $zapytanie = 'SELECT wpis FROM wpisy ORDER BY wpis_id DESC LIMIT 1'; if($a = http://www.php.net/mysql_query($zapytanie)) { while($wiersz = http://www.php.net/mysql_fetch_array($a)) { http://www.php.net/echo"<input type=hidden name=z_bazy value='".$wiersz['wpis']."'>"; } } http://www.php.net/echo"$z_bazy"; if($wpis == $z_bazy) { http://www.php.net/echo"takie same"; } else { $zapytanie = 'INSERT INTO wpisy values("","'.$podpis.'","'.$wpis.'")'; if(!http://www.php.net/mysql_query($zapytanie)) { http://www.php.net/echo"blad ".http://www.php.net/mysql_error().""; } } } ?>
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
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
nospor zwracam honor przeanalizowalem ten skrypt i nie dziala jak nalezy.
Da sie zrobic jakos tak, zeby dodaj i zapisz bylo w jednym pliku??
Jak wtedy mam uzywac zmiennych?
<http://december.com/html/4/element/form.html method="post" action="dodaj.php"> <http://december.com/html/4/element/input.html class="input" name="pseudo"><http://december.com/html/4/element/br.html> <http://december.com/html/4/element/textarea.html rows="3" cols="28" name="komentarz"></http://december.com/html/4/element/textarea.html> <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> </http://december.com/html/4/element/form.html>
<? $komentarz = $_POST["komentarz"]; $pseudo = $_POST["pseudo"]; ?> <? $plik="../txt/turniej/komentarz.txt"; $text="$komentarz||$pseudo|| \n"; $temp=http://www.php.net/implode(http://www.php.net/file($plik)); $fp=http://www.php.net/fopen($plik ,"w"); http://www.php.net/fwrite($fp ,$text); http://www.php.net/fwrite($fp ,$temp); ?>
nospor, a mógłbyś napisać jak potem z tej sesji wyrzucasz indentyfikator tak aby było gotowe na kolejne użycie formularza ?
@tes ja go nie wyrzucam. Jak pisalem, generuję unikalne identyfikatory. Przy kolejnym uzyciu formularza, generowany jest kolejny unikatowy identyfikator
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ć.
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:
<?php ... { http://www.php.net/echo '<script language="JavaScript">window.location="Twojastrona.php";</script>'; } ... ?>
<?php adres('adres.php'); ?>
<?php function adres($url) { if (!http://www.php.net/headers_sent()) { http://www.php.net/header('Location: http://' . $_SERVER['HTTP_HOST'] . http://www.php.net/dirname($_SERVER['PHP_SELF']) . '/' . $url); } else { http://www.php.net/die('Nie mogę przekierować. Wysłano już nagłówki (wyjście).'); } } ?>
O rany, zaczęliście całą religię do tego problemu dobudowywać 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? ;>
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.
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.
Jeżeli chcemy tylko ochronić skrypt przed przypadkowym wciśnięciem F5, dobrym rozwiązaniem jest wysyłanie formularzy za pomocą AJAX. 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.
ź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.
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:
<?php if(http://www.php.net/isset($_POST['AddReply']) && !http://www.php.net/isset($_POST['Re'])) $class->AddReply(); ?>
<form action="" method="post"> <?php if(!http://www.php.net/empty($_POST)) http://www.php.net/echo '<input name="Re" type="hidden" value="1">'; ?> <input name="AddReply" type="hidden" value="1"> ... </form>
<http://december.com/html/4/element/input.html name="Re" type="hidden" value="1">
<http://december.com/html/4/element/form.html action="wykonaj_akcje.php"> ... </http://december.com/html/4/element/form.html>
<? //jakies akcje http://www.php.net/header("Location: akcja_wykonana.php") ?>
<input type="hidden" id="hash" name="hash" value="<?=generateHash();?>"> <?php function generateHash() { 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 } ?>
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:
<http://december.com/html/4/element/input.html type="hidden" id="hash" name="hash" value="<?php echo generateHash();?>">
<?php function generateHash() { return http://www.php.net/md5(http://www.php.net/time() * http://www.php.net/rand()); } ?>
<?php if (!$_SESSION['adduser'] || $_POST['hash'] != $_SESSION['adduser'] ){ $_SESSION['adduser'] = $_POST['hash']; //dodajemy zmienną sesyjną adduser //wszystko co ma się wykonać po prawidłowym wysłaniu formularza } else { http://www.php.net/echo "Ten formularz był już wysłany"; } ?>
hmm... najprościej to chyba przed przetwarzaniem i zapisem danych sprawdzić czy np.
<?php if($_SESSION['poszłoooo']=='0') {} ?>
<?php if (!$_SESSION[$_SERVER[PHP_SELF]]) { } else {} ?>
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 ;-)
Hmm jak tak czytam wasze wypowiedzi to o mało nie popadam w paranoję "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
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
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
;P
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.
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
dorzuce jeszcze do wypowiedzi wszystkich - prosty i oczywisty sposob: blokowanie przycisku submit, po kliknieciu (wymagane dolaczenie biblioteki jquery do kodu)
<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>
Stare już, ale dodam od siebie:
<?php if (!http://www.php.net/isset($_SESSION['done'][$temat_id])) { $model->add(); $_SESSION['done'][$temat_id] = true; } else { http://www.php.net/echo "dwa razy nie da rady :]"; } ?>
stary temat ale może coś od siebie raz dam
Napisz wiadomość<br /> <form method="post" action="pw.php"> <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())); ?>"/> <input type="text" name="temat"/><br /> <textarea cols="40" rows="5"name="tresc"> </textarea><br /> <input type="submit" value="wyślij" name="wyslij"/> </form> <?php http://www.php.net/session_start(); require 'konfig.php'; if(http://www.php.net/isset($_POST['wyslij'])) { if(http://www.php.net/isset($_SESSION['blockrefreshdump']) && http://www.php.net/in_array($_POST['blockrefresh'],$_SESSION['blockrefreshdump'])) http://www.php.net/echo 'Nie klikaj Refresh'; else { //wstaw tu co chcesz by wysłało do bazy http://www.php.net/echo $_POST['temat'].'<br /> <br />'; http://www.php.net/echo $_POST['tresc'].'<br /> <br />'; http://www.php.net/echo 'wiadomość została wysłana'; // na końcu trza dodać do sesji blockrefresh-a :) $_SESSION['blockrefreshdump'][]=$_POST['blockrefresh']; } } ?>
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?
$_SESSION['crf'] = md5(uniqid()); <input type="hidden" name="crf" value="<?= $_SESSION['crf'];?>" />
if($_POST['crf'] !== $_SESSION['crf']) { http://www.php.net/die(); } else { $_SESSION['crf'] = http://www.php.net/md5(http://www.php.net/uniqid()); // upload pliku itp. }
Dzięki @CuteOne, pomogło.
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ść.
<div id="TRESC"> <?php include("polacz.php"); $query = http://www.php.net/mysql_query("select * from news where id='".(int)$_GET['id']."'"); // 1 $rekord = http://www.php.net/mysql_fetch_array($query); http://www.php.net/echo '<h1>'.$rekord[1].'</h1>Autor: '.$rekord[3].'<br/>Data: '.$rekord[2].'<p>'.$rekord[4].'</p>'; // 2 $id_news = $rekord[0]; ?> <hr> <br> <?php if($_SERVER['REQUEST_METHOD'] == 'POST') { $query = http://www.php.net/mysql_query("insert into komentarze_news values('','".$id_news."',now(),'".$_POST['autor']."','".$_POST['tresc']."')"); } ?> <?php $query = http://www.php.net/mysql_query("select * from komentarze_news where id_news=$id_news"); while($rekord = http://www.php.net/mysql_fetch_array($query)) http://www.php.net/echo 'Autor:<B><I> '.$rekord[3] .' </B>Data dodania: '.$rekord[2].'</I><br>'.$rekord[4].'<p>'; ?> Skomentuj <form action="" method="post"> autor <input type="text" name="autor"> <br/>treść <textarea name="tresc" rows="10" cols="50"></textarea> <br/><input type="submit" value="Dodaj"> </form> </div>
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 :
//zapis do bazy http://www.php.net/header('Location: jakas_strona.php');
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)