Pull to refresh

Comments 30

Просто не делайте переадресацию если форма оказалась невалидной.
А я уже и забыл как это отправлять не ассинхронные запросы :)
Или можно сделать отправку данных формы через ajax, сразу проверить валидность, выдать комментарии по ошибкам, если таковые нашлись, а в случае успешной отправки убрать саму форму, оставив сообщение о том, что данные отправлены. При необходимости, можно после этого устроить редирект на нужную страницу. Обязательно на время отправки данных и получения отклика заблокировать возможность повторной отправки.

Как альтернатива — блокировать повторную отправку формы одним пользователем на определенное время. Например, на минуту-две. Чаще всего истории с повторными отправками случаются, когда человек сразу или почти сразу пытается вернуться назад, а через пару минут эта проблема уже не так часто случается… хотя, это вариант не особо надежный — для ленивых.
Если данные были некорректны — то зачем редирект на самого себя, они ничем не угрожают?
Проблема ведь именно в непреднамеренном повторении запрошенного действия и делать редирект надо только если форма успешно прошла валидацию и выполнено запрошенное действие.
Удивительно! Я пока писал эту статью, меня как раз посетила эта мысль: а какого фига я вообще редиректю если форма заполнена не правильно? Ведь можно редиректить только после успешной отправки. Выдать сообщение «ваши данные отправлены, все гуд».
Видимо, пока писал, невольно все прокрутил в башке и дошел до такой вот мысли.
Спасибо за то что подкрепили ее!
Тогда вопрос вот в чем: как узнать что произошла успешная отправка и нужно делать переадресацию? Ведь header нужно вызывать раньше любого вывода на экран, иначе не работает. Поэтому header в моих кодах всегда стоит «выше» всего остального. И функция, которая его вызывает, ориентируется на $_POST, в котором содержится идентификатор нажатой кнопки. Т.е. функция проверяет $_POST['send_message'] и если есть такое, то вызывает редирект.

Теперь же, после того как мы решили, что редирект не нужно вызывать все время когда нажата send_message, а только в момент когда она нажата и произошла УСПЕШНАЯ отправка. Как отследить этот момент? Нужно тогда чтобы функция, вызывающая редирект, «видела» признак успешной отправки, возвращенный функцией отправки. А в моей структуре это невозмножно. Распределение зон видимости не позволяет.
Это проблема вашей структуры, в нормальной ситуации вся логика отрабатывает до начала любого вывода.
Поройте на досуге исходники популярных фреймворков.

Тем не менее, в качестве решения можно применять буферизацию вывода.
Согласен с вами! Печально… но согласен!
Вам точно нужно изменить структуру вашего web приложения. С таким подходом, как у вас, вы закопаетесь в коде и вскоре его поддержка выльется в мысль, а возьму-ка я и перепишу весь сайт нафиг. Гуглите в сторону MVC подхода, а по проблеме, что вы обозначили — делайте все проверки ДО ТОГО как будете выводить HTML.
Предлагаю прочитать про CSRF

P.S. Почему пост, а не вопрос?
В смысле я не понял вашего вопроса! ))
Уже понял! Ответил ниже!
есть более простое: ru.wikipedia.org/wiki/Post/Redirect/Get
Редирект надо делать только после успешной обработки формы. А при ошибках это делать не обязательно.

И — да, это тянет на вопрос, а совсем не на статью.
Да, пардон, ошибся! А теперь никак не могу поменять пост на вопрос. Это вообще возможно? Выбираю «вопрос» обновляется страница и предлагается создать новый.
Мне кажется, что нет. Но я не силён в механике этого сайта.
Надо спрятать пост в черновики и создать вопрос
А разве ru.wikipedia.org/wiki/Post/Redirect/Get — это примерно не то о чем я говорил?
Да, как раз об этом пишу.
Я почему-то полагал, что в описание паттерна входит и обработка ошибок. А сейчас посмотрел — там просто про редирект.
Так что мой комментарий оказался лишним, стоило просто плюсануть самый первый.

Напишу тогда про сессии.
С ними тоже не всё слава богу: если удалять данные поста сразу после редиректа, то перезагрузка страницы позволит-таки юзеру очистить форму от введённых в нее данных (понятно, что он будет сам дурак, но ведь юзабилити — это и есть забота о как раз таких вот пользователях...).
А если удалять после успешной обработки, то надо предусматривать наличие в сессии зоопарка из заполненных форм — пользователи часто заполняют по две сразу.
Если ты сделал какую-то ошибку в кодах (которая проявляется именно в момент отправки), то она даже не высветится, т.к. произойдет переадресация и ты даже не увидишь сообщение об ошибке.

В дев-окружении появится две ошибки (если первая не фатальная) — основная и headers already sent или как там её. В продакшене — основная зафиксируется в логах (а пользователю её показывать всё равно незачем). Если же так сильно боитесь её пропустить, то можно сделать два ридиректа в случае ошибки валидации, что-то вроде:
— form.php — вывод формы с полями по умолчанию из $_SESSION и ошибками оттуда же.
— form_prehandler — тупое заполнение $_SESSION из формы с очисткой ошибок и редиректом на form_handler.php (вероятность допустить ошибку минимальна)
— form_handler — валидация и основная обработка, с редиректом в случае ошибок на form.php
>И продолжаю задаваться вопросом: а есть ли другие, более элегантные решения?
Допустим форма и ее обработчик находятся в form.php (это только для простоты):

<?

...

if (isset($_POST["secret"]) && $_POST["secret"] != $_SESSION["secret"] )
{
  // Произошла повторная отправка, принимаем меры
}

else
{
  // Все отлично, можем обрабатывать данные
}

...

$_SESSION["secret"] = mt_random();

...

// Вывод формы

?>

...

<input type="hidden" value="<?=$_SESSION["secret"]?>" />

...

Вы, я уверен, такое решение никогда на практике не использовали.
Такой эффект получался от использования псевдокапчи.
Какие у этого решения недостатки?
Пользователи имеют склонность открывать больше одной страницы сайта.
Как минимум, нужно иметь пул этих «секретов».

Но я сейчас не о недостатках конкретно этого метода, а о недостатках сайтов типа хабрахабр. На которых можно увидеть миллион полезных советов… которые никто из советчиков никогда не применял на практике. А все только лишь переписывают друг у друга.
> Как минимум, нужно иметь пул этих «секретов»
Не вижу в этом проблемы.

>На которых можно увидеть миллион полезных советов… которые никто из советчиков никогда не применял на практике. А все только лишь переписывают друг у друга.

Пожалуй, это не про меня.
Почему же, я, например такой подход применял и могу сказать, что это лучше, чем ничего. Такой подход вполне жизнеспособен, в случае если мы в любом случае каждому посетителю стартуем сессию.
Раз уж вы так заморочились, и раз не подходит аякс, постите в iframe. Старо как интернет
1. Указываем в target атрибуте формы имя iframe (скрытого или сгенеренного на onsubmit)
2. В качестве ответа на POST в iframe выводится JS, который совершает в top или parent необходимые действия (вывод ошибки, очистка полей и т.д.) либо устанавливает новый document.location
3. Profit

Плюс: не надо заморачиваться с повторной подстановкой данных формы из POST
Минус: iframe, ну и не очень элегантно
Вот уже 5 лет я использую следующий простой принцип:

1. Тэг form ничего никуда отправляет, он служит скорее для группировки полей, но в принципе можно обойтись и без него. Очень часто я использую div — это не имеет большого значения.

2. По событию нажатия на submit (или какому-то другому — для сложных форм) js собирает данные из контролов и отправляет их на адрес обработчика с помощью ajax.

3. Обработчик на PHP (каждая форма считается объектом и у него есть просто метод onFormSubmit()) анализирует данные и через JSON возвращает последовательность простых команд по дальнейшей работе клиента. Это могут быть: подсветить поле(-я), вывести alert, сделать редирект, выполнить js-код или обновить кусок DOM. Редирект не делается только в том случае, если есть ошибки в форме и надо повторить отправку после их исправления.

Куда делать редирект — решает сам контроллер, и это, я считаю, правильно. Сам клиент ничего не валидирует и не принимает никаких решений (валидация на клиенте бессмысленна), а просто следует командам сервера.
Sign up to leave a comment.

Articles