Лечение «Бэк-кнопок»

Когда-либо наткнулся на учебник, который, по вашему мнению, имеет большую ценность, но не совсем объяснен должным образом? Это моя дилемма. Я знаю, что ЭТОТ учебник имеет некоторую ценность, но я просто не могу его получить.

  1. Где вы называете каждую функцию?
  2. Какую функцию следует вызывать первым, а затем, а третью?
  3. Будут ли все функции вызываться во всех файлах приложения?
  4. Кто-нибудь знает, как лучше вылечить «Back Button Blues»?

Мне интересно, не помешает ли это хороший разговор, включающий автора статьи. Мне особенно интересна роль управления кнопкой «Назад», чтобы предотвратить дублирование записей в базе данных при нажатии кнопки «Назад». В принципе, вы хотите управлять кнопкой «Назад», вызывая следующие три функции во время выполнения скриптов в вашем приложении. В каком порядке точно назвать функции (см. Вопросы выше) не ясно из учебника.

Все движения вперед выполняются с помощью моей функции 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 

Когда какой-либо скрипт завершил свою обработку, он завершается вызовом моей функции scriptPrevious. Это приведет к удалению текущего сценария с конца массива стека и повторной активации предыдущего скрипта в массиве.

 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, либо с помощью скрипта, либо из-за кнопки BACK в браузере, он вызывает следующую функцию, чтобы проверить, является ли это текущим скриптом в соответствии с содержимым стека программ и предпринимать соответствующие действия, если это не так.

 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. Это ожидаемая ситуация. Напитки повсюду!

Solutions Collecting From Web of "Лечение «Бэк-кнопок»"

Это хорошая дискуссия, но более важно то, что вы должны смотреть в Post Redirect Get (PRG), также известную как «Get after Post».

http://www.theserverside.com/patterns/thread.tss?thread_id=20936

Если вы не понимаете мою статью, вы должны внимательно ознакомиться с рисунком 1, где изображен типичный сценарий, когда пользователь проходит через серию экранов – вход в систему, меню, список, поиск, добавление и обновление. Когда я описываю движение FORWARDS, я имею в виду, что текущий экран заблокирован, когда активирован новый экран. Это происходит, когда пользователь нажимает ссылку на текущем экране. Когда я описываю движение как BACKWARDS, я имею в виду, что пользователь завершает текущий экран (нажав кнопку QUIT или SUBMIT) и вернется к предыдущему экрану, который возобновляет обработку с того места, где она была остановлена. Это может включать включение любых изменений, сделанных на экране, который только что был завершен.

Здесь важна поддержка стека страниц, который не зависит от истории браузера – стек страницы поддерживается приложением и используется для проверки всех запросов. Они могут быть действительными в отношении браузера, но могут быть идентифицированы приложением как недействительные и рассматриваются соответствующим образом.

Стек страницы поддерживается двумя функциями:

  • scriptNext () используется для обработки движения FORWARDS, который добавляет новую запись в конец стека и активирует новую запись.
  • scriptPrevious () используется для обработки движения BACKWARDS, которое удаляет последнюю запись из стека и повторно активирует предыдущую запись.

Теперь рассмотрим ситуацию в примере, когда пользователь перешел на страницу 4 экрана LIST, перешел на экран ADD, а затем вернулся на страницу 5 экрана LIST. Последним действием на экране ADD было нажатие кнопки SUBMIT, которая использовала метод POST для отправки данных на сервер, которые были добавлены в базу данных, после чего она автоматически завершилась и вернулась на экран LIST.

Если вы поэтому нажмете кнопку BACK, находясь на странице 5 экрана LIST, история браузера создаст запрос на последнее действие на экране ADD, которое было POST. Это действительный запрос в отношении браузера, но это не касается приложения. Как приложение может решить, что запрос недействителен? Проверяя его стек страниц. Когда экран ADD был завершен, его запись была удалена из стека страниц, поэтому любой запрос на экран, который не находится в стеке страниц, всегда может считаться недействительным. В этом случае неверный запрос может быть перенаправлен на последнюю запись в стеке.

Поэтому ответы на ваши вопросы должны быть очевидны:

  • В: Где вы называете каждую функцию?
  • A: Вы вызываете функцию scriptNext (), когда пользователь выбирает переход вперед к новому экрану и вызывает функцию scriptPrevious (), когда пользователь завершает текущий экран.
  • Q: Какую функцию следует вызывать первым, а затем, а третью?
  • A: Каждая функция вызывается в ответ на действие, выбранное пользователем, поэтому одновременно используется только одна функция.
  • В: Будут ли все функции вызываться во всех файлах в приложении?
  • A: Все функции должны быть доступны во всех файлах в приложении, но вызываться только при выборе пользователем.

Вы хотите видеть эти идеи в действии, тогда вы можете загрузить мое приложение-образец .

Мне особенно интересна роль управления кнопкой «Назад», чтобы предотвратить дублирование записей в базе данных при нажатии кнопки «Назад».

Ваша предпосылка неверна. Нет такой вещи, как «Back Button Blues», если вы разрабатываете приложение как веб-приложение. Если вы разрабатываете приложение без какого-либо состояния на стороне сервера, вы никогда не столкнетесь с этой проблемой в первом случае. Этот минималистический подход к веб-приложениям работает замечательно хорошо и обычно называется REST.

@ troelskn

Если вы разрабатываете приложение без какого-либо состояния на стороне сервера …

Невозможно создать эффективное приложение, которое не имеет состояния, в противном случае все, что у вас есть, – это набор отдельных страниц, которые не общаются друг с другом. Поскольку сохранение состояния на клиенте чревато проблемами, нет эффективной альтернативы, кроме как поддерживать состояние на сервере.

@Marston.

Я решил проблему с post / redirect / get, но я считаю, что у учебника есть некоторые достоинства, и, возможно, Тони Марстон может рассказать об этом. И как его можно было использовать для решения не обязательно моей конкретной проблемы, но, возможно, что-то подобное. Или как это лучше, чем post / redirect / get, если на самом деле функции можно использовать для решения моей конкретной проблемы. Я думаю, что это будет хорошим дополнением к сообществу здесь.

 if ($_POST) { process_input($_POST); header("Location: $_SERVER[HTTP_REFERER]"); exit; }