治愈“后退按钮忧郁症”

发布于 2024-07-11 16:08:11 字数 3784 浏览 12 评论 0原文

您是否曾经偶然发现过一个您认为很有价值但解释不正确的教程? 这就是我的困境。 我知道 本教程 有一些价值,但我就是无法理解。

  1. 每个函数在哪里调用?
  2. 应该调用哪个函数 第一个,接下来哪个,以及哪个 第三?
  3. 是否会在应用程序的所有文件中调用所有函数?
  4. 有谁知道治疗“后退按钮布鲁斯”的更好方法吗?

我想知道这是否会引发一些包括本文作者在内的良好对话。 我特别感兴趣的部分是控制后退按钮,以防止按下后退按钮时将表单重复条目写入数据库。 基本上,您希望在应用程序中执行脚本期间通过调用以下三个函数来控制后退按钮。 本教程中并不清楚到底以什么顺序调用函数(参见上面的问题)。

所有向前移动均由 使用我的 scriptNext 函数。 这是 在当前脚本中调用 命令激活新脚本。

函数 scriptNext($script_id) 
  // 继续执行新脚本 
  { 
     如果(空($script_id)){ 
        trigger_error("脚本 ID 未定义", E_USER_ERROR); 
     } // 如果 

     // 获取本次会话中使用的屏幕列表 
     $page_stack = $_SESSION['page_stack']; 
     if (in_array($script_id, $page_stack)) { 
        // 从堆栈数组中删除此项以及所有后续项 
        做 { 
           $last = array_pop($page_stack); 
        while ($last!= $script_id); 
     } // 如果 

     // 将下一个脚本添加到数组末尾并更新会话数据 
     $page_stack[] = $script_id; 
     $_SESSION['page_stack'] = $page_stack; 

     // 现在将控制权传递给指定的脚本 
     $location = 'http://' .$_SERVER['HTTP_HOST'] .$script_id; 
     header('位置:' .$location);  
     出口; 

  } // 脚本下一个 
  

当任何脚本完成其 处理它通过调用我的终止 scriptPrevious 函数。 这会 从末尾删除当前脚本 堆栈数组并重新激活 数组中的前一个脚本。

函数 scriptPrevious() 
  // 返回上一个脚本(如 PAGE_STACK 中定义) 
  { 
     // 获取当前脚本的id 
     $script_id = $_SERVER['PHP_SELF']; 

     // 获取本次会话中使用的屏幕列表 
     $page_stack = $_SESSION['page_stack']; 
     if (in_array($script_id, $page_stack)) { 
        // 从堆栈数组中删除此项以及所有后续项 
        做 { 
           $last = array_pop($page_stack); 
        while ($last!= $script_id); 
        // 更新会话数据 
        $_SESSION['page_stack'] = $page_stack; 
     } // 如果 

     如果(计数($page_stack)> 0){ 
        $previous = array_pop($page_stack); 
        // 重新激活之前的脚本 
        $location = 'http://' .$_SERVER['HTTP_HOST'] .$previous; 
     } 别的 { 
        // 没有以前的脚本,因此终止会话 
        session_unset(); 
        session_destroy(); 
        // 恢复默认起始页 
        $location = 'http://' .$_SERVER['HTTP_HOST'] .'/index.php'; 
     } // 如果 

     header('位置:' .$location);  
     出口; 

  } // 上一个脚本 
  

每当脚本被激活时, 可以通过脚本Next 或 scriptPrevious 函数,或 因为 BACK 按钮 浏览器,它将调用以下内容 函数来验证它是 当前脚本根据 程序的内容堆栈并取 如果不是,请采取适当的行动。

函数 initSession() 
  // 初始化会话数据 
  { 
     // 获取程序堆栈 
     if (isset($_SESSION['page_stack'])) { 
        // 使用现有的堆栈 
        $page_stack = $_SESSION['page_stack']; 
     } 别的 { 
        // 创建以当前脚本开头的新堆栈 
        $page_stack[] = $_SERVER['PHP_SELF']; 
        $_SESSION['page_stack'] = $page_stack; 
     } // 如果 

     // 检查该脚本是否位于当前堆栈的末尾 
     $实际 = $_SERVER['PHP_SELF']; 
     $expected = $page_stack[count($page_stack)-1]; 
     if ($预期!= $实际) { 
        if (in_array($actual, $page_stack)) {// 脚本位于当前堆栈中,因此删除后面的所有内容 
        while ($page_stack[count($page_stack)-1] != $actual ) { 
              $null = array_pop($page_stack); 
           } // 尽管 
           $_SESSION['page_stack'] = $page_stack; 
        } // 如果 
        // 将脚本 ID 设置为程序堆栈中的最后一个条目 
        $实际 = $page_stack[count($page_stack)-1]; 
        $location = 'http://' .$_SERVER['HTTP_HOST'] .$actual; 
        header('位置:' .$location); 
        出口; 
     } // 如果 

     ... // 继续处理 

  } // 初始化会话 
  

所采取的行动取决于是否 当前脚本存在于 程序堆栈与否。 有三种 可能性:

  • 当前脚本不在$page_stack数组中,在这种情况下它是 不允许继续。 相反,它是 替换为位于的脚本 数组末尾。
  • 当前脚本位于 $page_stack 数组,但它不是 最后一个条目。 在这种情况下所有 数组中的以下条目是 已删除。
  • 当前脚本是最后一个条目 在 $page_stack 数组中。 这是 预期的情况。 全部喝完 圆形!

Ever stumbled on a tutorial that you feel is of great value but not quite explained properly? That's my dilemma. I know THIS TUTORIAL has some value but I just can't get it.

  1. Where do you call each function?
  2. Which function should be called
    first and which next, and which
    third?
  3. Will all functions be called in all files in an application?
  4. Does anyone know of a better way cure the "Back Button Blues"?

I'm wondering if this will stir some good conversation that includes the author of the article. The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed. Basically, you want to control the back button by calling the following three functions during the execution of the scripts in your application. In what order exactly to call the functions (see questions above) is not clear from the tutorial.

All forwards movement is performed by
using my scriptNext function. This is
called within the current script in
order to activate the new script.

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

When any script has finished its
processing it terminates by calling my
scriptPrevious function. This will
drop the current script from the end
of the stack array and reactivate the
previous script in the array.

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

Whenever a script is activated, which
can be either through the scriptNext
or scriptPrevious functions, or
because of the BACK button in the
browser, it will call the following
function to verify that it is the
current script according to the
contents of the program stack and take
appropriate action if it is not.

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

The action taken depends on whether
the current script exists within the
program stack or not. There are three
possibilities:

  • The current script is not in the $page_stack array, in which case it is
    not allowed to continue. Instead it is
    replaced by the script which is at the
    end of the array.
  • The current script is in the
    $page_stack array, but it is not the
    last entry. In this case all
    following entries in the array are
    removed.
  • The current script is the last entry
    in the $page_stack array. This is
    the expected situation. Drinks all
    round!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

橘虞初梦 2024-07-18 16:08:11

这是一个很好的讨论,但更重要的是,您应该研究 Post Redirect Get (PRG),也称为“Get after Post”。

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

That is a good discussion but more to the point you should be looking into Post Redirect Get (PRG) also known as "Get after Post."

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

猫烠⑼条掵仅有一顆心 2024-07-18 16:08:11

如果您不理解我的文章,那么您应该仔细查看 图 1< /a> 描述了用户浏览一系列屏幕的典型场景 - 登录、菜单、列表、搜索、添加和更新。 当我描述向前移动时,我的意思是当前屏幕暂停,同时激活新屏幕。 当用户按下当前屏幕中的链接时会发生这种情况。 当我将移动描述为“向后”时,我的意思是用户终止当前屏幕(通过按“退出”或“提交”按钮)并返回到上一个屏幕,该屏幕从中断处恢复处理。 这可能包括合并在刚刚终止的屏幕中所做的任何更改。

这是维护独立于浏览器历史记录的页面堆栈至关重要的地方 - 页面堆栈由应用程序维护并用于验证所有请求。 这些对于浏览器而言可能是有效的,但可能被应用程序识别为无效并进行相应处理。

页面堆栈由两个函数维护:

  • scriptNext() 用于处理
    FORWARDS 运动,增加了一个新的
    堆栈末尾的条目和
    激活新条目。
  • scriptPrevious() 用于处理
    向后运动,这会消除
    堆栈中的最后一个条目和
    重新激活之前的条目。

现在以示例中的情况为例,其中用户导航到 LIST 屏幕的第 4 页,进入 ADD 屏幕,然后返回到 LIST 屏幕的第 5 页。 ADD 屏幕中的最后一个操作是按 SUBMIT 按钮,该按钮使用 POST 方法将添加到数据库的详细信息发送到服务器,之后自动终止并返回到 LIST 屏幕。

因此,如果您在 LIST 屏幕的第 5 页中按下 BACK 按钮,浏览器历史记录将生成对 ADD 屏幕上最后一个操作(即 POST)的请求。 就浏览器而言,这是一个有效的请求,但就应用程序而言,这不是一个有效的请求。 应用程序如何判定请求无效? 通过检查其页面堆栈。 当 ADD 屏幕终止时,其条目将从页面堆栈中删除,因此对不在页面堆栈中的屏幕的任何请求始终可以被视为无效。 在这种情况下,无效请求可以被重定向到堆栈中的最后一个条目。

因此,您的问题的答案应该是显而易见的:

  • 问:您在哪里调用每个函数?
  • 答:你调用 scriptNext()
    当用户选择时的功能
    向前导航到新屏幕,
    并调用 scriptPrevious()
    当用户终止时的函数
    当前屏幕。
  • 问:应该调用哪个函数
    第一个,接下来哪个,以及哪个
    第三?
  • A:每个函数都被调用
    对所选择的行动的响应
    用户,所以只使用一个功能
    一次。
  • 问:所有函数都会被调用吗
    应用程序中的所有文件?
  • 答:所有功能都应该可用
    在应用程序的所有文件中,但是
    仅在用户选择时调用。

如果您希望看到这些想法的实际应用,那么您可以下载我的示例应用程序。

If you do not understand my article then you should take a close look at figure 1 which depicts a typical scenario where a user passes through a series of screens – logon, menu, list, search, add and update. When I describe a movement of FORWARDS I mean that the current screen is suspended while a new screen is activated. This happens when the user presses a link in the current screen. When I describe a movement as BACKWARDS I mean that the user terminates the current screen (by pressing the QUIT or SUBMIT button) and returns to the previous screen, which resumes processing from where it left off. This may include incorporating any changes made in the screen which has just been terminated.

This is where maintaining a page stack which is independent of the browser history is crucial – the page stack is maintained by the application and is used to verify all requests. These may be valid as far as the browser is concerned, but may be identified by the application as invalid and dealt with accordingly.

The page stack is maintained by two functions:

  • scriptNext() is used to process a
    FORWARDS movement, which adds a new
    entry at the end of the stack and
    activates the new entry.
  • scriptPrevious() is used to process
    a BACKWARDS movement, which removes
    the last entry from the stack and
    re-activates the previous entry.

Now take the situation in the example where the user has navigated to page 4 of the LIST screen, gone into the ADD screen, then returned to page 5 of the LIST screen. The last action in the ADD screen was to press the SUBMIT button which used the POST method to send details to the server which were added to the database, after which it terminated automatically and returned to the LIST screen.

If you therefore press the BACK button while in page 5 of the LIST screen the browser history will generate a request for the last action on the ADD screen, which was a POST. This is a valid request as far as the browser is concerned, but is not as far as the application is concerned. How can the application decide that the request is invalid? By checking with its page stack. When the ADD screen was terminated its entry was deleted from the page stack, therefore any request for a screen which is not in the page stack can always be treated as invalid. In this case the invalid request can be redirected to the last entry in the stack.

The answers to your questions should therefore be obvious:

  • Q: Where do you call each function?
  • A: You call the scriptNext()
    function when the user chooses to
    navigate forwards to a new screen,
    and call the scriptPrevious()
    function when the user terminates
    the current screen.
  • Q: Which function should be called
    first and which next, and which
    third?
  • A: Each function is called in
    response to an action chosen by the
    user, so only one function is used
    at a time.
  • Q: Will all functions be called in
    all files in an application?
  • A: All functions should be available
    in all files in an application, but
    only called when chosen by the user.

It you wish to see these ideas in action then you can download my sample application.

命硬 2024-07-18 16:08:11

我特别感兴趣的部分是控制后退按钮,以防止按下后退按钮时将表单重复条目写入数据库。

你的前提是错误的。 如果您将应用程序设计为 Web 应用程序,则不存在“后退按钮蓝调”之类的东西。 如果您设计的应用程序没有任何服务器端状态,那么在第一种情况下您将永远不会遇到此问题。 这种 Web 应用程序的简约方法效果非常好,通常称为 REST。

The part I'm particularly interested in is controlling the back button in order to prevent form duplicate entries into a database when the back button is pressed.

Your premise is wrong. There is no such thing as "Back Button Blues", if you design your application as a web application. If you design your application without any server side state, you will never run into this problem in the first case. This minimalistic approach to web applications works remarkably well, and is usually known as REST.

寒江雪… 2024-07-18 16:08:11

@特罗尔斯克恩

如果您设计的应用程序没有任何服务器端状态......

不可能设计一个没有状态的有效应用程序,否则您拥有的只是一组彼此不通信的单独页面。 由于在客户端上维护状态充满了问题,因此除了在服务器上维护状态之外没有有效的替代方案。

@ troelskn

If you design your application without any server side state ....

It is not possible to design an effective application which does not have state, otherwise all you have is a collection of individual pages which do not communicate with each other. As maintaining state on the client is fraught with issues there is no effective alternative but to maintain state on the server.

鹿港小镇 2024-07-18 16:08:11

@马斯顿。

我用 post/redirect/get 解决了这个问题,但我相信该教程有一些优点,也许托尼·马斯顿可以详细说明。 以及如何使用它来解决不一定是我的特定问题,但也许可以解决类似的问题。 或者,如果这些函数实际上可以用于解决我的特定问题,那么它比 post/redirect/get 更好吗? 我认为这将是对这里社区的一个很好的补充。

@Marston.

I solved the problem with post/redirect/get but I believe the tutorial has some merit and perhaps Tony Marston can elaborate on it. And how it could be used to solve not necessarily my particular problem but perhaps something similar. Or how is it better than post/redirect/get if the functions can in fact be used in solving my particular problem. I think this will be a good addition to the community here.

小伙你站住 2024-07-18 16:08:11
if ($_POST) {
    process_input($_POST);
    header("Location: $_SERVER[HTTP_REFERER]");
    exit;
}
if ($_POST) {
    process_input($_POST);
    header("Location: $_SERVER[HTTP_REFERER]");
    exit;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文