2

非常に価値があると思われるチュートリアルに出くわしたことがありますが、適切に説明されていませんか? それが私のジレンマです。このチュートリアルには何らかの価値があることは知っていますが、それを得ることができません。

  1. 各関数をどこで呼び出しますか?
  2. どの関数を最初に呼び出し、次にどの関数を呼び出し、どの関数を 3 番目に呼び出す必要がありますか?
  3. アプリケーション内のすべてのファイルですべての関数が呼び出されますか?
  4. 「Back Button Blues」を治すより良い方法を知っている人はいますか?

これが記事の著者を含めて良い会話を巻き起こすかどうか疑問に思っています. 私が特に興味を持っている部分は、戻るボタンが押されたときにデータベースへのフォームの重複エントリを防ぐために、戻るボタンを制御することです。基本的には、アプリケーションでスクリプトの実行中に次の 3 つの関数を呼び出して、戻るボタンを制御します。関数を呼び出す正確な順序 (上記の質問を参照) は、チュートリアルからは明らかではありません。

すべての前方移動は、私の 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 関数を介して、またはブラウザの [戻る] ボタンによってスクリプトがアクティブ化されるたびに、次の関数が呼び出され、プログラム スタックの内容に従って現在のスクリプトであることを確認します。そうでない場合は、適切なアクションを実行します。

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

実行されるアクションは、現在のスクリプトがプログラム スタック内に存在するかどうかによって異なります。次の 3 つの可能性があります。

  • 現在のスクリプトは $page_stack 配列にありません。この場合、続行できません。代わりに、配列の最後にあるスクリプトに置き換えられます。
  • 現在のスクリプトは $page_stack 配列にありますが、最後のエントリではありません。この場合、配列内の後続のすべてのエントリが削除されます。
  • 現在のスクリプトは、$page_stack 配列の最後のエントリです。これは予想される状況です。オールラウンドドリンク!
4

6 に答える 6

9

これは良い議論ですが、「Get after Post」としても知られる Post Redirect Get (PRG) について検討する必要があります。

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

于 2009-01-09T00:41:08.903 に答える
3

私の記事を理解できない場合は、ユーザーが一連の画面 (ログオン、メニュー、リスト、検索、追加、更新) を通過する典型的なシナリオを示す図 1をよく見てください。FORWARDS の動きを説明するとき、現在の画面が中断され、新しい画面がアクティブになることを意味します。これは、ユーザーが現在の画面でリンクを押したときに発生します。移動を BACKWARDS と説明する場合、ユーザーが現在の画面を終了し (QUIT または SUBMIT ボタンを押して)、前の画面に戻り、中断したところから処理を再開することを意味します。これには、終了したばかりの画面で行われた変更を組み込むことが含まれる場合があります。

これは、ブラウザーの履歴から独立したページ スタックを維持することが重要な場所です。ページ スタックはアプリケーションによって維持され、すべての要求を検証するために使用されます。これらはブラウザに関する限り有効かもしれませんが、アプリケーションによって無効であると識別され、それに応じて処理される場合があります。

ページ スタックは、次の 2 つの関数によって維持されます。

  • scriptNext() は、スタックの最後に新しいエントリを追加し、新しいエントリをアクティブにする FORWARDS 移動を処理するために使用されます。
  • scriptPrevious() は、BACKWARDS 移動を処理するために使用されます。これにより、スタックから最後のエントリが削除され、前のエントリが再度アクティブになります。

ここで、ユーザーが LIST 画面のページ 4 にナビゲートし、ADD 画面に入り、次に LIST 画面のページ 5 に戻った例を考えてみましょう。ADD 画面の最後のアクションは、データベースに追加された詳細を POST メソッドを使用してサーバーに送信する SUBMIT ボタンを押すことでした。その後、自動的に終了して LIST 画面に戻りました。

したがって、LIST 画面の 5 ページ目で [戻る] ボタンを押すと、ブラウザーの履歴によって、ADD 画面の最後のアクション (POST であった) の要求が生成されます。これは、ブラウザーに関する限り有効な要求ですが、アプリケーションに関する限りではありません。アプリケーションはどのようにしてリクエストが無効であると判断できますか? ページスタックをチェックすることによって。ADD 画面が終了すると、そのエントリはページ スタックから削除されるため、ページ スタックにない画面に対する要求は常に無効として扱われます。この場合、無効な要求はスタック内の最後のエントリにリダイレクトできます。

したがって、あなたの質問に対する答えは明らかです。

  • Q: 各関数はどこで呼び出しますか?
  • A: ユーザーが新しい画面に進むことを選択したときに scriptNext() 関数を呼び出し、ユーザーが現在の画面を終了したときに scriptPrevious() 関数を呼び出します。
  • Q: どの関数を最初に呼び出し、次にどの関数を呼び出し、どの関数を 3 番目に呼び出す必要がありますか?
  • A: 各関数は、ユーザーが選択したアクションに応答して呼び出されるため、一度に 1 つの関数のみが使用されます。
  • Q: アプリケーション内のすべてのファイルですべての関数が呼び出されますか?
  • A: アプリケーション内のすべてのファイルですべての関数を使用できるようにする必要がありますが、ユーザーが選択した場合にのみ呼び出されます。

これらのアイデアの動作を確認したい場合は、私のサンプル アプリケーションをダウンロードしてください。

于 2009-01-10T09:02:00.133 に答える
0

@ troelskn

サーバー側の状態なしでアプリケーションを設計する場合...。

状態のない効果的なアプリケーションを設計することはできません。そうしないと、相互に通信しない個々のページのコレクションしかありません。クライアントの状態を維持することには問題が伴うため、サーバーの状態を維持する以外に効果的な代替手段はありません。

于 2009-01-10T07:47:55.883 に答える
0

@マーストン。

post / redirect / getで問題を解決しましたが、チュートリアルにはいくつかのメリットがあり、おそらくTonyMarstonがそれについて詳しく説明できると思います。そして、それをどのように使用して、必ずしも私の特定の問題を解決するのではなく、おそらく同様の問題を解決することができるでしょうか。または、関数を実際に私の特定の問題の解決に使用できる場合は、post / redirect/getよりも優れています。これはここのコミュニティへの良い追加になると思います。

于 2009-01-10T08:06:56.750 に答える
0

私が特に興味を持っているのは、戻るボタンが押されたときにデータベースへのフォームの重複エントリを防ぐために、戻るボタンを制御することです。

あなたの前提は間違っています。アプリケーションをWebアプリケーションとして設計する場合、「戻るボタンブルー」のようなものはありません。サーバー側の状態なしでアプリケーションを設計する場合、最初のケースでこの問題が発生することはありません。Webアプリケーションへのこの最小限のアプローチは非常にうまく機能し、通常はRESTとして知られています。

于 2009-01-09T21:34:18.477 に答える
0
if ($_POST) {
    process_input($_POST);
    header("Location: $_SERVER[HTTP_REFERER]");
    exit;
}
于 2009-01-10T09:04:59.877 に答える