治愈“后退按钮蓝调”

时间:2009-01-09 00:22:53

标签: php forms button back

你偶然发现了一个你觉得很有价值的教程,但却没有得到很好的解释?那是我的困境。我知道THIS TUTORIAL有一些价值,但我无法得到它。

  1. 你在哪里称呼每个功能?
  2. 应该调用哪个函数 第一个和下一个,哪个 第三λ
  3. 是否会在应用程序的所有文件中调用所有函数?
  4. 有没有人知道治疗“Back Button Blues”的更好方法?
  5. 我想知道这是否会激起包括文章作者在内的一些好的对话。我特别感兴趣的部分是控制后退按钮,以防止在按下后退按钮时将重复条目复制到数据库中。基本上,您希望在应用程序中执行脚本期间通过调用以下三个函数来控制后退按钮。从教程中可以清楚地知道调用函数的顺序(参见上面的问题)。

      

    所有前进动作均由。执行   使用我的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   或scriptPrevious函数,或   因为中的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数组中。这是   预期的情况。喝完了   圆<!/ LI>   

6 个答案:

答案 0 :(得分:9)

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

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

答案 1 :(得分:3)

如果您不理解我的文章,那么您应该仔细查看figure 1,其中描述了用户通过一系列屏幕的典型场景 - 登录,菜单,列表,搜索,添加和更新。当我描述FORWARDS的移动时,我的意思是在激活新屏幕时暂停当前屏幕。当用户按下当前屏幕中的链接时会发生这种情况。当我将运动描述为BACKWARDS时,我的意思是用户终止当前屏幕(通过按下QUIT或SUBMIT按钮)并返回到上一个屏幕,该屏幕从中断处继续处理。这可能包括合并屏幕中刚刚终止的任何更改。

这是维护与浏览器历史无关的页面堆栈的关键所在 - 页面堆栈由应用程序维护,用于验证所有请求。就浏览器而言,这些可能是有效的,但可能被应用程序识别为无效并相应处理。

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

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

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

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

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

  • 问:你在哪里打电话给每个职能部门?
  • 答:你调用scriptNext() 用户选择时的功能 向前导航到新屏幕, 并调用scriptPrevious() 用户终止时的功能 当前的屏幕。
  • 问:应该调用哪个函数 第一个和下一个,哪个 第三λ
  • A:调用每个函数 对...选择的行动的回应 user,因此只使用一个函数 一次。
  • 问:是否会调用所有功能 应用程序中的所有文件?
  • 答:所有功能都应该可用 在应用程序的所有文件中,但是 仅在用户选择时调用。

您希望在行动中看到这些想法,然后您可以下载我的sample application

答案 2 :(得分:0)

  

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

你的前提是错的。如果您将应用程序设计为Web应用程序,则不会出现“Back Button Blues”。如果您设计的应用程序没有任何服务器端状态,则在第一种情况下您将永远不会遇到此问题。这种简单的Web应用程序方法非常有效,通常称为REST。

答案 3 :(得分:0)

@ troelskn

  

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

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

答案 4 :(得分:0)

@Marston。

我用post / redirect / get解决了这个问题,但我相信这个教程有一些优点,也许Tony Marston可以详细说明。它如何用于解决不一定是我特定的问题,但也许类似的东西。或者如果函数实际上可以用于解决我的特定问题,它如何比post / redirect / get更好。我认为这对社区来说是一个很好的补充。

答案 5 :(得分:0)

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