Mam prosty formularz, który przesyła tekst do mojej tabeli SQL. Problem w tym, że po przesłaniu tekstu przez użytkownika może odświeżyć stronę i dane są przesyłane ponownie bez ponownego wypełniania formularza. Mogę przekierować użytkownika na inną stronę po przesłaniu tekstu, ale chcę, aby użytkownicy pozostali na tej samej stronie.
Pamiętam, że przeczytałem coś o nadaniu każdemu użytkownikowi unikalnego identyfikatora sesji i porównaniu go z inną wartością, która rozwiązała problem, który mam, ale zapomniałem, gdzie on jest.
POST
żądaniaPOST
dane. W takim przypadku potrzebujeszSELECT
go od DB. Na przykład, kiedy tworzysz fakturę, zostajesz przekierowany, na/invoices/53
którym wyświetlana jest cała faktura zamiast tylkoOdpowiedzi:
Użyj wzorca Post / Redirect / Get. http://en.wikipedia.org/wiki/Post/Redirect/Get
W mojej witrynie zapiszę wiadomość w pliku cookie lub sesji, przekieruję po poście, przeczytam plik cookie / sesję, a następnie wyczyszczę wartość tej sesji lub zmiennej cookie.
źródło
Chciałbym również zwrócić uwagę, że możesz użyć podejścia javascript,
window.history.replaceState
aby zapobiec ponownemu przesłaniu po naciśnięciu przycisku odświeżania i powrotu.<script> if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); } </script>
Dowód koncepcji tutaj: https://dtbaker.net/files/prevent-post-resubmit.php
Nadal polecałbym podejście Post / Redirect / Get, ale jest to nowatorskie rozwiązanie JS.
źródło
Naprawdę powinieneś użyć wzorca Post Redirect Get do obsługi tego, ale jeśli w jakiś sposób znalazłeś się w pozycji, w której PRG nie jest opłacalne (np. Sam formularz jest zawarty w dołączaniu, zapobiegając przekierowaniom), możesz zaszyfrować niektóre parametry żądania utworzyć ciąg znaków na podstawie zawartości, a następnie sprawdzić, czy jeszcze go nie wysłałeś.
//create digest of the form submission: $messageIdent = md5($_POST['name'] . $_POST['email'] . $_POST['phone'] . $_POST['comment']); //and check it against the stored value: $sessionMessageIdent = isset($_SESSION['messageIdent'])?$_SESSION['messageIdent']:''; if($messageIdent!=$sessionMessageIdent){//if its different: //save the session var: $_SESSION['messageIdent'] = $messageIdent; //and... do_your_thang(); } else { //you've sent this already! }
źródło
session_start();
na początku pliku. w3schools.com/php/php_sessions.asp mówi Uwaga: Funkcja session_start () musi być pierwszą rzeczą w dokumencie. Przed jakimikolwiek tagami HTML.Używam tej linii javascript do blokowania wyskakującego okienka z prośbą o ponowne przesłanie formularza przy odświeżaniu po przesłaniu formularza.
if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); }
Po prostu umieść tę linię w stopce pliku i zobacz magię
źródło
Możesz zapobiec ponownemu przesyłaniu formularzy za pomocą zmiennej sesji.
Najpierw musisz ustawić
rand()
w polu tekstowym i$_SESSION['rand']
na stronie formularza:<form action="" method="post"> <?php $rand=rand(); $_SESSION['rand']=$rand; ?> <input type="hidden" value="<?php echo $rand; ?>" name="randcheck" /> Your Form's Other Field <input type="submit" name="submitbtn" value="submit" /> </form>
Następnie sprawdź
$_SESSION['rand']
z$_POST['randcheck']
wartością pola tekstowego w ten sposób:if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand']) { // Your code here }
źródło
<input type="hidden" name="randcheck" id="randcheck" value="<?php echo microtime(); ?>" />
zamiast tego$_POST
danych formularza ta sama strona ładuje się ponownie, ustawiając sesję i wysyłając zmienne. Również tworzenie zmiennych powinno odbywać się po sprawdzeniu zgodności zmiennych. Dlategounset
nie jest potrzebne.Gdy formularz jest przetwarzany, przekierowujesz na inną stronę:
... process complete.... header('Location: thankyou.php');
możesz również przekierować na tę samą stronę.
jeśli robisz coś w rodzaju komentarzy i chcesz, aby użytkownik pozostał na tej samej stronie, możesz użyć Ajax do obsługi przesyłania formularza
źródło
Znalazłem następne obejście. Możesz uniknąć przekierowania po przetworzeniu
POST
żądania, manipulująchistory
obiektem.Masz więc formularz HTML:
<form method=POST action='/process.php'> <input type=submit value=OK> </form>
Kiedy przetwarzasz ten formularz na swoim serwerze, zamiast przekierowywać użytkownika
/the/result/page
, ustawiającLocation
nagłówek w następujący sposób:$cat process.php <?php process POST data here ... header('Location: /the/result/page'); exit(); ?>
Po przetworzeniu
POST
danych ed renderujesz małe<script>
i wynik/the/result/page
<?php process POST data here render the <script> // see below render `/the/result/page` // OK ?>
<script>
Należy uczynić:<script> window.onload = function() { history.replaceState("", "", "/the/result/page"); } </script>
Wynik to:
jak widać dane formularza są
POST
edytowane doprocess.php
skryptu.Ten skrypt przetwarza
POST
dane ed i renderuje/the/result/page
jednocześnie za pomocą:POST
danych po odświeżeniu strony (F5)POST
gdy przechodzisz do poprzedniej / następnej strony w historii przeglądarkiUPD
Innym rozwiązaniem jest poproszenie zespołu Mozilla FireFox o umożliwienie użytkownikom skonfigurowania
NextPage
nagłówka, który będzie działał jakLocation
nagłówek i sprawi, żepost/redirect/get
wzorzec stanie się przestarzały.W skrócie. Gdy serwer
POST
pomyślnie przetworzy dane formularza, to:NextPage
Nagłówek konfiguracji zamiastLocation
POST
danych formularza tak, jak byłby renderowany naGET
żądanie wepost/redirect/get
wzorcuPrzeglądarka z kolei, gdy zobaczy
NextPage
nagłówek:window.location
pomocąNextPage
wartościGET
żądanieNextPage
zamiast zmieniaćPOST
daneMyślę, że byłoby to doskonałe, gdyby zostało wdrożone, prawda?
=)
źródło
Użyj nagłówka i przekieruj stronę.
header("Location:your_page.php");
Możesz przekierować na tę samą lub inną stronę.Cofnij ustawienie $ _POST po wstawieniu go do bazy danych.
unset($_POST);
źródło
unset
? Dodaj wyjaśnienie do swojej odpowiedzi, aby inni mogli się z niej nauczyćTa metoda działa dla mnie dobrze i myślę, że jest to najłatwiejsza do wykonania tej pracy.
Ogólną ideą jest przekierowanie użytkownika na inne strony po przesłaniu formularza, co zatrzymałoby ponowne przesłanie formularza po odświeżeniu strony. Jeśli jednak potrzebujesz zatrzymać użytkownika na tej samej stronie po przesłaniu formularza, możesz to zrobić na wiele sposobów, ale tutaj opiszę metodę javascript.
Metoda Javascript
Ta metoda jest dość prosta i blokuje wyskakujące okienko z prośbą o ponowne przesłanie formularza przy odświeżaniu po przesłaniu formularza. Po prostu umieść tę linię kodu javascript w stopce pliku i zobacz magię.
<script> if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); } </script>
źródło
Całkiem pewnym sposobem jest zaimplementowanie unikalnego identyfikatora do postu i umieszczenie go w pamięci podręcznej w pliku
<input type='hidden' name='post_id' value='".createPassword(64)."'>
Następnie w swoim kodzie zrób to:
if( ($_SESSION['post_id'] != $_POST['post_id']) ) { $_SESSION['post_id'] = $_POST['post_id']; //do post stuff } else { //normal display } function createPassword($length) { $chars = "abcdefghijkmnopqrstuvwxyz023456789"; srand((double)microtime()*1000000); $i = 0; $pass = '' ; while ($i <= ($length - 1)) { $num = rand() % 33; $tmp = substr($chars, $num, 1); $pass = $pass . $tmp; $i++; } return $pass; }
źródło
Javascript
Ta metoda jest dość prosta i blokuje wyskakujące okienko z prośbą o ponowne przesłanie formularza przy odświeżaniu po przesłaniu formularza. Po prostu umieść tę linię kodu javascript w stopce pliku i zobacz magię.
<script> if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); } </script>
źródło
Po prostu przekieruj go na tę samą stronę po użyciu danych formularza i działa. Próbowałem tego.
header('location:yourpage.php');
źródło
Udoskonalona wersja postu Mooba. Utwórz skrót POST, zapisz go jako plik cookie sesji i porównaj skróty w każdej sesji.
// Optionally Disable browser caching on "Back" header( 'Cache-Control: no-store, no-cache, must-revalidate' ); header( 'Expires: Sun, 1 Jan 2000 12:00:00 GMT' ); header( 'Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT' ); $post_hash = md5( json_encode( $_POST ) ); if( session_start() ) { $post_resubmitted = isset( $_SESSION[ 'post_hash' ] ) && $_SESSION[ 'post_hash' ] == $post_hash; $_SESSION[ 'post_hash' ] = $post_hash; session_write_close(); } else { $post_resubmitted = false; } if ( $post_resubmitted ) { // POST was resubmitted } else { // POST was submitted normally }
źródło
Zasadniczo musisz przekierować z tej strony, ale nadal może to powodować problem, gdy twój internet jest wolny (nagłówek przekierowania z serwera)
Przykład podstawowego scenariusza:
Kliknij dwukrotnie przycisk przesyłania
Sposób na rozwiązanie
Strona klienta
Po stronie serwera
źródło
Jak zapobiec ponownemu przesyłaniu formularza php bez przekierowania. Jeśli używasz $ _SESSION (po session_start) i formularza $ _POST, możesz zrobić coś takiego:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) { // do your stuff, save data into database, etc }
W formularzu HTML umieść to:
<input type="hidden" id="act" name="act" value="<?php echo ( empty($_POST['act']) || $_POST['act']==2 )? 1 : 2; ?>"> <?php if ( $_POST['act'] == $_SESSION['act'] ){ if ( empty( $_SESSION['act'] ) || $_SESSION['act'] == 2 ){ $_SESSION['act'] = 1; } else { $_SESSION['act'] = 2; } } ?>
Tak więc za każdym razem, gdy przesyłany jest formularz, generowany jest nowy akt, zapisywany w sesji i porównywany z aktem post.
Ps: jeśli używasz formularza Get, możesz łatwo zmienić wszystkie POST za pomocą GET i to też działa.
źródło
Po wstawieniu go do bazy danych wywołaj metodę unset (), aby wyczyścić dane.
nieustawiony ($ _ POST);
Aby zapobiec odświeżaniu wstawiania danych, wykonaj przekierowanie strony na tę samą lub inną stronę po wstawieniu rekordu.
nagłówek ('Lokalizacja:'. $ _ SERVER ['PHP_SELF']);
źródło
unset
wezwanie jest potrzebne? Co by się stało, gdybyś to pominął?Użycie wzorca Post / Redirect / Get z odpowiedzi Keverw jest dobrym pomysłem. Nie jesteś jednak w stanie pozostać na swojej stronie (a myślę, że o to prosiłeś?) Ponadto czasami może się nie udać :
Inną opcją byłoby zapisanie w sesji, jeśli tekst powinien zostać zapisany w bazie danych SQL w następujący sposób:
if($_SERVER['REQUEST_METHOD'] != 'POST') { $_SESSION['writeSQL'] = true; } else { if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL']) { $_SESSION['writeSQL'] = false; /* save $_POST values into SQL */ } }
źródło
Jak powiedzieli inni, nie można zrezygnować z używania post / redirect / get. Ale jednocześnie dość łatwo jest robić to, co chcesz, po stronie serwera.
Na swojej stronie POST po prostu zatwierdzasz dane wejściowe użytkownika, ale nie wykonujesz na nich żadnych działań, zamiast tego kopiujesz je do tablicy SESSION. Następnie ponownie przekierowujesz z powrotem do głównej strony przesyłania. Twoja główna strona przesyłania zaczyna się od sprawdzenia, czy tablica SESSION, której używasz, istnieje, a jeśli tak, skopiuj ją do tablicy lokalnej i usuń jej ustawienie. Stamtąd możesz na nim działać.
W ten sposób wykonujesz całą swoją główną pracę tylko raz, osiągając to, co chcesz.
źródło
Szukałem rozwiązania, aby zapobiec ponownemu złożeniu później dużego projektu. Kod bardzo dobrze działa z $ _GET i $ _POST i nie mogę zmienić zachowania elementów formularza bez ryzyka nieprzewidzianych błędów. Oto mój kod:
<!-- language: lang-php --> <?php // Very top of your code: // Start session: session_start(); // If Post Form Data send and no File Upload if ( empty( $_FILES ) && ! empty( $_POST ) ) { // Store Post Form Data in Session Variable $_SESSION["POST"] = $_POST; // Reload Page if there were no outputs if ( ! headers_sent() ) { // Build URL to reload with GET Parameters // Change https to http if your site has no ssl $location = "https://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; // Reload Page header( "location: " . $location, true, 303 ); // Stop any further progress die(); } } // Rebuilt POST Form Data from Session Variable if ( isset( $_SESSION["POST"] ) ) { $_POST = $_SESSION["POST"]; // Tell PHP that POST is sent $_SERVER['REQUEST_METHOD'] = 'POST'; } // Your code: ?><html> <head> <title>GET/POST Resubmit</title> </head> <body> <h1>Forms:</h1> <h2>GET Form:</h2> <form action="index.php" method="get"> <input type="text" id="text_get" value="test text get" name="text_get"/> <input type="submit" value="submit"> </form> <h2>POST Form:</h2> <form action="index.php" method="post"> <input type="text" id="text_post" value="test text post" name="text_post"/> <input type="submit" value="submit"> </form> <h2>POST Form with GET action:</h2> <form action="index.php?text_get2=getwithpost" method="post"> <input type="text" id="text_post2" value="test text get post" name="text_post2"/> <input type="submit" value="submit"> </form> <h2>File Upload Form:</h2> <form action="index.php" method="post" enctype="multipart/form-data"> <input type="file" id="file" name="file"> <input type="submit" value="submit"> </form> <h1>Results:</h1> <h2>GET Form Result:</h2> <p>text_get: <?php echo $_GET["text_get"]; ?></p> <h2>POST Form Result:</h2> <p>text_post: <?php echo $_POST["text_post"]; ?></p> <h2>POST Form with GET Result:</h2> <p>text_get2: <?php echo $_GET["text_get2"]; ?></p> <p>text_post2: <?php echo $_POST["text_post2"]; ?></p> <h2>File Upload:</h2> <p>file: <pre><?php if ( ! empty( $_FILES ) ) { echo print_r( $_FILES, true ); } ?></pre> </p> <p></p> </body> </html><?php // Very Bottom of your code: // Kill Post Form Data Session Variable, so User can reload the Page without sending post data twice unset( $_SESSION["POST"] );
Działa tylko w celu uniknięcia ponownego przesłania $ _POST, a nie $ _GET. Ale to jest zachowanie, którego potrzebuję. Problem z ponownym przesłaniem nie działa w przypadku przesyłania plików!
źródło
To, co działa dla mnie, to:
if ( !refreshed()) { //Your Submit Here if (isset( $_GET['refresh'])) { setcookie("refresh",$_GET['refresh'], time() + (86400 * 5), "/"); } } } function refreshed() { if (isset($_GET['refresh'])) { $token = $_GET['refresh']; if (isset($_COOKIE['refresh'])) { if ($_COOKIE['refresh'] != $token) { return false; } else { return true; } } else { return false; } } else { return false; } } function createToken($length) { $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < $length; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } ?>
I w swojej Formie
<form action="?refresh=<?php echo createToken(3)?>"> </form>
źródło
Ten
form.php
przykład pokazuje, jak poprawnie używać PRG (kiedy formularz jest prawidłowy lub nie).<?php session_start(); function doSelfRedirect() { header('Location:'.$_SERVER['PHP_SELF']); exit; } function setFlashMessage($msg) { $_SESSION['message'] = $msg; } function getFlashMessage() { if (!empty($_SESSION['message'])) { $msg = $_SESSION['message']; unset($_SESSION['message']); } else { $msg = null; } return $msg; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Validation primitive example. if (empty($_POST['valid'])) { $formIsValid = false; setFlashMessage('Invalid form submit'); } else { $formIsValid = true; } if ($formIsValid) { // Perform any actions here. // ... // Cool! setFlashMessage('Form is valid. Action performed.'); // Prevent form resubmission. doSelfRedirect(); } } ?> <h1>Hello form</h1> <?php if ($msg = getFlashMessage()): ?> <div><?= $msg ?></div> <?php endif; ?> <form method="post"> <input type="text" name="foo" value="bar"><br><br> <button type="submit" name="invalid" value="0">Invalid submit</button> <button type="submit" name="valid" value="1">Valid submit</button> </form>
źródło
if (($_SERVER['REQUEST_METHOD'] == 'POST') and (isset($_SESSION['uniq']))){ if($everything_fine){ unset($_SESSION['uniq']); } } else{ $_SESSION['uniq'] = uniqid(); }
źródło
$everything_fine
wzięło?Dlaczego nie użyć tej
$_POST['submit']
zmiennej jako logicznej instrukcji, aby zapisać wszystko, co jest w formularzu. Zawsze możesz przekierować na tę samą stronę (w przypadku, gdyby się odświeżyły i gdy trafiągo back
w przeglądarce, zmienna przesyłania wiadomości nie będzie już ustawiana. Upewnij się tylko, że przycisk przesyłania ma aname
iid
ofsubmit
.źródło