Как предотвратить повторную отправку формы при обновлении страницы (F5 / CTRL+R)
У меня есть простая форма, которая отправляет текст в моей таблице SQL. Проблема в том, что после того, как пользователь отправляет текст, они могут обновить страницу, и данные будут отправлены снова без повторного заполнения формы. Я мог бы перенаправить пользователя на другую страницу после отправки текста, но я хочу, чтобы пользователи оставались на той же странице.
Я помню, что читал что-то о предоставлении каждому пользователю уникального идентификатора сеанса и сравнении его с другим значением, которое решило проблему, которую я имею, но я забыл, где он находится.
18 ответов:
используйте шаблон Post/Redirect/Get. http://en.wikipedia.org/wiki/Post/Redirect/Get
с помощью моего веб-сайта я сохраню сообщение в файле cookie или сеансе, перенаправлю после публикации, прочитаю файл cookie/сеанс, а затем очистите значение этой переменной сеанса или файла cookie.
Я также хотел бы отметить, что вы можете использовать подход javascript,
window.history.replaceStateчтобы предотвратить повторную отправку на кнопку Обновить и назад.<script> if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); } </script>доказательство концепции здесь:https://dtbaker.net/files/prevent-post-resubmit.php
Я бы все равно рекомендовал подход Post/Redirect/Get, но это новое решение JS.
вы действительно должны использовать шаблон Post Redirect Get для обработки этого, но если вы каким-то образом оказались в положении, когда PRG нежизнеспособен (например, сама форма находится в include, предотвращая перенаправления), вы можете хэшировать некоторые параметры запроса, чтобы сделать строку на основе содержимого, а затем проверить, что вы ее еще не отправили.
//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! }
вы можете повторно отправить форму через переменную сеанса, например
сначала вы должны установить rand () в текстовом поле и $_SESSION['rand'] на странице формы
<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>после проверки $_SESSION ['rand' ] с textbox $_POST ['randcheck'] значение Как
if(isset($_POST['submitbtn']) && $_POST['randcheck']==$_SESSION['rand']) { //Your Code here }
использовать заголовок и перенаправить страницу.
header("Location:your_page.php");вы можете перенаправить на ту же страницу или другую страницу.Unset $_POST после вставки его в базу данных.
unset($_POST);
когда форма обработана, вы перенаправляете на другую страницу:
... process complete.... header('Location: thankyou.php');вы также можете перенаправить на ту же страницу.
Если вы делаете что-то вроде комментариев и вы хотите, чтобы пользователь оставался на той же странице, вы можете использовать AJAX для обработки формы представления
довольно верный способ реализовать уникальный идентификатор в пост и кэшировать его в
<input type='hidden' name='post_id' value='".createPassword(64)."'>тогда в вашем коде сделайте следующее:
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; }
я нашел следующее решение. Вы можете избежать перенаправления после обработки
POSTзапрос манипулируяhistoryтакой:$cat process.php <?php process POST data here ... header('Location: /the/result/page'); exit(); ?>после обработки
POSTданные ЭД вы делаете небольшой<script>и результат/the/result/page<?php process POST data here render the <script> // see below render `/the/result/page` // OK ?>The
<script>вы должны предоставить:<script> window.onload = function() { history.replaceState("", "", "/the/result/page"); } </script>результат:
как вы можете видеть данные формы
POSTЭдprocess.phpсценарий.
Этот скрипт процессPOSTЭд данные и рендеринг/the/result/pageсразу с:
- нет перенаправления
- нет re
POSTданные при обновлении страницы (F5)- нет re
POSTпри переходе на предыдущую/следующую страницу через историю браузераUPD
в качестве другого решения я прошу запрос the Mozilla FireFox команда, чтобы позволить пользователям устанавливать
NextPageзаголовок, который будет работать как и сделатьpost/redirect/getшаблон устарел.короче. Когда серверная форма процесса
POSTданные успешно это:
- Setup
NextPageзаголовок вместоLocation- отображать результат обработки
POSTформа данных, как это будет отображаться дляGETзапросpost/redirect/getpatternбраузер, в свою очередь, когда вижу
NextPageзаголовок:
- настройки
window.locationСNextPageстоимостью- когда пользователь обновит страницу, браузер будет вести переговоры
GETзапросNextPageвместо rePOSTданные формыя думаю, что это было бы превосходно, если реализовали бы, не так ли?
=)
просто перенаправьте его на ту же страницу после использования данных формы, и он работает. Я уже пробовал.
header('location:yourpage.php');
уточненная версия сообщения Moob. Создайте хэш сообщения, сохраните его как файл cookie сеанса и сравните хэши каждого сеанса.
// 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 }
после вставки его в базу данных, вызовите метод unset () для очистки данных.
unset ($_POST);
чтобы предотвратить вставку данных обновления, выполните перенаправление страницы на ту же страницу или другую страницу после вставки записи.
заголовок ('Location:'.$_SERVER ['PHP_SELF']);
в принципе, вам нужно перенаправить с этой страницы, но это все еще может создать проблему, пока ваш интернет медленный (заголовок перенаправления с сервера)
пример базового сценария :
нажмите на кнопку Отправить дважды
способ решить
на стороне клиента
- отключить кнопку отправки, как только клиент нажмет на нее
- если вы используете Jquery:Jquery.один
- PRG Шаблон
сервер
- использование дифференцировать на основе хэширования timestamp / timestamp, когда запрос был отправлен.
- токены Userequest. Когда основная загрузка назначает временный запрос tocken, который при повторении игнорируется.
Как предотвратить повторную отправку формы php без перенаправления. Если вы используете $_SESSION (after session_start) и форму $_POST, вы можете сделать что-то вроде этого:
if ( !empty($_SESSION['act']) && !empty($_POST['act']) && $_POST['act'] == $_SESSION['act'] ) { // do your stuff, save data into database, etc }в вашей html форме поставьте это:
<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; } } ?>Ps: Если вы используете форму Get, вы можете легко изменить все сообщения с GET, и это тоже работает.
Я использую эту строку javascript, чтобы заблокировать всплывающее окно с запросом на повторную отправку формы при обновлении после отправки формы.
if ( window.history.replaceState ) { window.history.replaceState( null, null, window.location.href ); }просто поместите эту строку в нижний колонтитул вашего файла и увидеть магию
Использование шаблона Post / Redirect / Get из ответа Keverw-хорошая идея. Однако вы не можете оставаться на своей странице (и я думаю, что это было то, что вы просили?) Кроме того, это может иногда fail:
если веб-пользователь обновляется до завершения первоначальной отправки из-за задержки сервера, что приводит к дублированию запроса HTTP POST в некоторые агенты пользователей.
другой вариант будет хранить в сеансе, если текст должен быть записан в вашу базу данных SQL следующим образом:
if($_SERVER['REQUEST_METHOD'] != 'POST') { $_SESSION['writeSQL'] = true; } else { if(isset($_SESSION['writeSQL']) && $_SESSION['writeSQL']) { $_SESSION['writeSQL'] = false; /* save $_POST values into SQL */ } }
Как говорили другие, невозможно выйти из использования post/redirect/get. Но в то же время это достаточно легко сделать, что вы хотите сделать на стороне сервера.
на странице POST вы просто проверяете пользовательский ввод, но не действуете на нем, вместо этого вы копируете его в массив сеанса. Затем вы снова перенаправляетесь на главную страницу отправки. Ваша главная страница отправки начинается с проверки наличия массива сеансов, который вы используете, и если да, то скопируйте его в локальный массив и снимите его. Оттуда вы можете действовать на него.
таким образом, вы только делаете всю свою основную работу один раз, добиваясь того, что вы хотите сделать.
Я искал решение, чтобы предотвратить повторную отправку в огромный проект после этого. Код очень хорошо работает с $_GET и $_POST, и я не могу изменить поведение элементов формы без риска непредвиденных ошибок. Итак, вот мой код:
<!-- 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"] );Он работает только для того, чтобы избежать повторной отправки $_POST, а не $_GET. Но это то поведение, которое мне нужно. Проблема повторной отправки не работает с загрузкой файлов!
почему бы просто не использовать
$_POST['submit']переменная как логическое утверждение, чтобы сохранить все, что находится в форме. Вы всегда можете перенаправить на ту же страницу (в случае их обновления, и когда они нажмитеgo backв браузере переменная submit post больше не будет установлена. Просто убедитесь, что ваша кнопка отправки имеетnameиidнаsubmit.


Comments