質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

【php】なぜかプログラムが上から順番に処理されない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,656

score -34

phpで、header関数を使って別ページに飛ぶ処理をしたいのですが、うまくいきません。

より詳しくは、
header(Location:url)を複数用意し、if文を使って飛び先のページを制御しようとすると、なぜか下にあるheader(Location:url)が先に処理されてしまう
というものです。

以下のstaff_branch.phpが問題のソースコードです。
さらに下のコードstaff_list.phpは、staff_branch.phpに飛ぶ前の(情報を渡す)ページです。
(データベースへの接続コードは、個人情報記載のため省略します)

ソース内のコメントに問題点を書いたので、どこが悪いのかご回答宜しくお願いします。

環境は、Windows10/Chrome/PHP7 です。

問題のソースコード(staff_branch.php):

<?php

if(isset($_POST['edit']) === true){//editは、buttonエレメントのname
  if(isset($_POST['staffcode']) === false){//ラジオstaffcodeが何も選択されていなければ、staff_ng.phpに飛ぶ
    header('Location:staff_ng.php');
  }
/*ラジオstaffcodeが何かしら選択されていれば、URLパラメータにstaffcodeの値を載せて、staff_edit.phpへ飛ぶ。*/

/*ラジオstaffcodeが未選択(空っぽ)なのに、なぜか、上のif文内のheaderではなく、以下のheaderが実行されてしまう*/
/*以下のheaderを削除すれば、上のheaderは実行される*/
  $staff_code=$_POST['staffcode'];
  header('Location: staff_edit.php?staffcode='.$staff_code);
}

if(isset($_POST['delete']) === true){//deleteはボタンエレメントのname
  if(isset($_POST['staffcode']) === false){//ラジオstaffcodeが何も選択されていなければ、staff_ng.phpに飛ぶ
    header('Location:staff_ng.php');
  }
/*ラジオstaffcodeが何かしら選択されていれば、URLパラメータにstaffcodeの値を載せて、staff_edit.phpへ飛ぶ。*/
/*ラジオstaffcodeが未選択(空っぽ)なのに、なぜか、上のif文内のheaderではなく、以下のheaderが実行されてしまう*/
/*以下のheaderを削除すれば、上のheaderは実行される*/
  $staff_code=$_POST['staffcode'];
  header('Location: staff_delete.php?staffcode='.$staff_code);
}
?>

staffcode選択画面(staff_list.php)

データベースへの接続(個人情報が記載されているので省略)

<body>
<?php
    print('スタッフ一覧<br><br>');

    print '<form action="staff_branch.php" method="post">';
    while(true){
      $rec = $stmt -> fetch(PDO::FETCH_ASSOC);//$stmtにはデータベースのデータが格納
      if($rec == false){
        break;
      }

      print '<input type="radio" name="staffcode" value="'.$rec['code'].'">';
      print $rec['name'];
      print '<br>';
    }
    print '<button type="submit" name="edit">修正</button>';
    print '<button type="submit" name="delete">削除</button>';
    print '</form>';
  }catch(Exception $e){
    print('ただいまサーバーに障害が発生しております。ご迷惑おかけしております。');
  }
  ?>
<\body>

試したこと

このコードは、2013年に書かれたあるphpの本のコードをそのまま写経したものですが、
「もしかして、この本が書かれた後にPHPやHTTPの仕様に変更があったのではないか?」
と思い、マニュアルを見てみました。

すると、2006年発表のPHP5.1.2の改訂内容に「header関数」がありました。内容は以下のとおりです:

header    この関数は一度に複数のヘッダを送信できないようになりました。 これは、ヘッダインジェクション攻撃への対策です。

仮にこれの意味するところが「一つのphpプログラム内で一つのheader関数しか使えない」という意味ならば、本に書かれたコードはそれに反していることになりますが、上記以上の詳細は書いておらず、こまりました 。
今回起きた「期待と異なる挙動」と照らし合わせると、おそらく、正確には以下のような内容と思われます:

「もし一つのphpプログラムに2つ以上のheader関数が書かれた場合、最後のheader関数のみが実行され、ほかのheader関数は無視される」

しかし、
・実行後になんのnoticeもエラーメッセージを出さないのは不自然。
・仕様書にちゃんとした断りが書いていない。
・7年も前の仕様変更を見落として本を書くのはさすがに著者がうかつすぎる。

といった理由から、その線は薄いと思われます。

謎です。

追記

解答者様のご指摘により解決しました。
header関数実行後にすぐにプログラムの処理を終了してページをジャンプするには、終了したい地点にexit()の記述が必要だったようです。

写経した書籍の公式サイト調べたら、正誤表があって、
「exitが抜けていた」
とおっしゃっていました。
環境によっては期待した挙動を示すこともあるようですが、私の環境の場合は駄目だったようです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

header() で値を返した後はexitをするなどして、その後のヘッダーを出力しないようにしないと、

Location: http://〜最初〜
Location: http://〜2番め〜
Location: http://〜3番め〜

がブラウザに渡されてしまいます。結果、3番目のものが処理されているのだと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/26 19:41

    あんま読んでないけど、書籍のコードをそのまま写経したわけだから、書籍を責めてるんじゃないの?

    キャンセル

  • 2019/04/26 20:11

    >書籍のコードをそのまま写経したわけだから
    そのとおりです。

    今書籍の公式サイト調べたら、正誤表があって、やはりexitが抜けていたところが訂正されていました。

    でもミスは付き物ですし、それが気にならないほど大変素晴らしい書籍なので、責めてはいません。
    http://www.ric.co.jp/book/error/error926.html

    キャンセル

  • 2019/04/26 20:49

    ちなみにheader関数は、Locationヘッダー以外を返したいときにも使うので、複数回呼び出しはありえるわけです。
    Locationヘッダーに関する知識が十分でなかったことも今回問題になってしまった要因かもですね


    実装の話で言えば、
    リダイレクトはフレームワークではたいてい標準機能であるので、いつもexitするわけではないことを理解しておくのも大事かなと

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る