Избавление от «синдрома кнопки «Назад»»
Вопрос
Вы когда-нибудь натыкались на учебник, который, по вашему мнению, имеет большую ценность, но не совсем правильно объяснен?Это моя дилемма.Я знаю ЭТОТ РУКОВОДСТВО имеет некоторую ценность, но я просто не могу ее получить.
- Где вы вызываете каждую функцию?
- Какая функция должна быть названа первой, а какая следующая, а какая третья?
- Будут ли вызываться все функции во всех файлах приложения?
- Кто-нибудь знает лучший способ вылечить «блюз кнопки «Назад»»?
Мне интересно, вызовет ли это какой-нибудь хороший разговор с участием автора статьи.Часть, которая меня особенно интересует, — это управление кнопкой «Назад», чтобы предотвратить дублирование записей в базе данных при нажатии кнопки «Назад».По сути, вы хотите управлять кнопкой «Назад», вызывая следующие три функции во время выполнения сценариев в вашем приложении.В каком именно порядке вызывать функции (см. вопросы выше) из туториала не понятно.
Все движения Forwards выполняется с помощью моей функции ScriptNext.Это вызывается в текущем сценарии, чтобы активировать новый сценарий.
function scriptNext($script_id) // proceed forwards to a new script { if (empty($script_id)) { trigger_error("script id is not defined", E_USER_ERROR); } // if // get list of screens used in this session $page_stack = $_SESSION['page_stack']; if (in_array($script_id, $page_stack)) { // remove this item and any following items from the stack array do { $last = array_pop($page_stack); } while ($last != $script_id); } // if // add next script to end of array and update session data $page_stack[] = $script_id; $_SESSION['page_stack'] = $page_stack; // now pass control to the designated script $location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id; header('Location: ' .$location); exit; } // scriptNext
Когда любой сценарий завершил свою обработку, его завершает, вызывая мою сценарию.Это отбросит текущий сценарий с конца массива стека и повторно активирует предыдущий сценарий в массиве.
function scriptPrevious() // go back to the previous script (as defined in PAGE_STACK) { // get id of current script $script_id = $_SERVER['PHP_SELF']; // get list of screens used in this session $page_stack = $_SESSION['page_stack']; if (in_array($script_id, $page_stack)) { // remove this item and any following items from the stack array do { $last = array_pop($page_stack); } while ($last != $script_id); // update session data $_SESSION['page_stack'] = $page_stack; } // if if (count($page_stack) > 0) { $previous = array_pop($page_stack); // reactivate previous script $location = 'http://' .$_SERVER['HTTP_HOST'] .$previous; } else { // no previous scripts, so terminate session session_unset(); session_destroy(); // revert to default start page $location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php'; } // if header('Location: ' .$location); exit; } // scriptPrevious
Всякий раз, когда активируется сценарий, который может быть либо через функции ScriptNext, либо ScriptPrevious, либо из -за кнопки на спине в браузере, он вызовет следующую функцию, чтобы убедиться, что это текущий скрипт в соответствии с содержимым программного стека и и Примите соответствующие действия, если это не так.
function initSession() // initialise session data { // get program stack if (isset($_SESSION['page_stack'])) { // use existing stack $page_stack = $_SESSION['page_stack']; } else { // create new stack which starts with current script $page_stack[] = $_SERVER['PHP_SELF']; $_SESSION['page_stack'] = $page_stack; } // if // check that this script is at the end of the current stack $actual = $_SERVER['PHP_SELF']; $expected = $page_stack[count($page_stack)-1]; if ($expected != $actual) { if (in_array($actual, $page_stack)) {// script is within current stack, so remove anything which follows while ($page_stack[count($page_stack)-1] != $actual ) { $null = array_pop($page_stack); } // while $_SESSION['page_stack'] = $page_stack; } // if // set script id to last entry in program stack $actual = $page_stack[count($page_stack)-1]; $location = 'http://' .$_SERVER['HTTP_HOST'] .$actual; header('Location: ' .$location); exit; } // if ... // continue processing } // initSession
Предпринятое действие зависит от того, существует ли текущий сценарий в стеке программы или нет.Есть три возможности:
- Текущий сценарий не находится в массиве $ page_stack, и в этом случае его не разрешается продолжать.Вместо этого он заменяется сценарием, который находится в конце массива.
- Текущий сценарий находится в массиве $ page_stack, но это не последняя запись.В этом случае все следующие записи в массиве удаляются.
- Текущий скрипт является последней записью в массиве $ page_stack.Это ожидаемая ситуация.Пьет по всему кругу!
Решение
Это хорошее обсуждение, но, более того, вам следует изучить функцию Post Redirect Get (PRG), также известную как «Get after Post».
http://www.theserverside.com/patterns/thread.tss?thread_id=20936
Другие советы
Если вы не поняли мою статью, то вам следует внимательно прочитать Рисунок 1 который описывает типичный сценарий, когда пользователь проходит через ряд экранов — вход в систему, меню, список, поиск, добавление и обновление.Когда я описываю движение ВПЕРЕД, я имею в виду, что текущий экран приостанавливается, пока активируется новый экран.Это происходит, когда пользователь нажимает ссылку на текущем экране.Когда я описываю движение как НАЗАД, я имею в виду, что пользователь завершает текущий экран (нажимая кнопку ВЫХОД или ОТПРАВИТЬ) и возвращается к предыдущему экрану, который возобновляет обработку с того места, где он остановился.Это может включать в себя внесение любых изменений, внесенных в экран, который только что был закрыт.
Именно здесь крайне важно поддерживать стек страниц, независимый от истории браузера: стек страниц поддерживается приложением и используется для проверки всех запросов.Они могут быть действительными с точки зрения браузера, но могут быть идентифицированы приложением как недействительные и обработаны соответствующим образом.
Стек страниц поддерживается двумя функциями:
- ScriptNext () используется для обработки движения вперед, которое добавляет новую запись в конце стека и активирует новую запись.
- ScriptPrevious () используется для обработки обратного движения, которое удаляет последнюю запись из стека и повторно активирует предыдущую запись.
Теперь возьмем ситуацию в примере, когда пользователь перешел на страницу 4 экрана СПИСОК, перешел на экран ДОБАВИТЬ, а затем вернулся на страницу 5 экрана СПИСОК.Последним действием на экране «ДОБАВИТЬ» было нажатие кнопки «ОТПРАВИТЬ», которая использовала метод POST для отправки на сервер данных, которые были добавлены в базу данных, после чего процесс автоматически завершился и вернулся на экран «СПИСОК».
Поэтому, если вы нажмете кнопку НАЗАД на странице 5 экрана СПИСОК, история браузера сгенерирует запрос на последнее действие на экране ДОБАВИТЬ, которым была POST.Это допустимый запрос с точки зрения браузера, но не с точки зрения приложения.Как приложение может решить, что запрос недействителен?Проверяя его стек страниц.Когда экран ADD был завершен, его запись была удалена из стека страниц, поэтому любой запрос экрана, которого нет в стеке страниц, всегда можно рассматривать как недействительный.В этом случае неверный запрос может быть перенаправлен на последнюю запись в стеке.
Поэтому ответы на ваши вопросы должны быть очевидными:
- Вопрос:Где вы вызываете каждую функцию?
- А:Вы называете функцию scriptNext (), когда пользователь выбирает перемещаться на новом экране и вызовать функцию ScriptPrevious (), когда пользователь завершает текущий экран.
- Вопрос:Какая функция должна быть названа первой, а какая следующая, а какая третья?
- А:Каждая функция вызывается в ответ на действие, выбранное пользователем, поэтому одновременно используется только одна функция.
- Вопрос:Будут ли все функции вызваны во всех файлах в приложении?
- А:Все функции должны быть доступны во всех файлах в приложении, но вызываются только при выборе пользователем.
Если вы хотите увидеть эти идеи в действии, вы можете скачать мой образец заявления.
Часть, которая меня особенно интересует, — это управление кнопкой «Назад», чтобы предотвратить дублирование записей в базе данных при нажатии кнопки «Назад».
Ваша предпосылка неверна.Не существует такого понятия, как «синяя кнопка «Назад», если вы разрабатываете свое приложение как веб-приложение.Если вы разрабатываете свое приложение без какого-либо состояния на стороне сервера, в первом случае вы никогда не столкнетесь с этой проблемой.Этот минималистичный подход к веб-приложениям работает удивительно хорошо и обычно известен как REST.
@троэлскн
Если вы разрабатываете свое приложение без какого-либо состояния на стороне сервера....
Невозможно создать эффективное приложение, не имеющее состояния, иначе все, что у вас есть, — это набор отдельных страниц, которые не взаимодействуют друг с другом.Поскольку сохранение состояния на клиенте чревато проблемами, нет эффективной альтернативы, кроме как поддерживать состояние на сервере.
@Марстон.
Я решил проблему с помощью post/redirect/get, но считаю, что это руководство имеет определенную ценность, и, возможно, Тони Марстон сможет подробно рассказать об этом.И как его можно использовать для решения не обязательно моей конкретной проблемы, но, возможно, чего-то похожего.Или чем это лучше, чем post/redirect/get, если эти функции действительно можно использовать для решения моей конкретной проблемы.Я думаю, что это будет хорошим дополнением к здешнему сообществу.
if ($_POST) {
process_input($_POST);
header("Location: $_SERVER[HTTP_REFERER]");
exit;
}