🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

3回答

4276閲覧

php ログイン後○秒後に自動ログアウトしたいがint_setを使用しているのに即ログアウトとなってしまう。

Ms.yy

総合スコア83

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2019/11/07 14:07

編集2019/11/07 23:41

問題点
sessionを用いて自動ログアウトを設定しているのですが、コード内のlist.phpに入るとすぐにログアウトしindex.htmlに飛ばされてしまいます。

ini_setは使用しているのになぜでしょうか?
もし、使い方が違うのであればどのように書けばいいでしょうか?

宜しくお願いいたします。

list.php

<?php session_start();?> <?php ini_set( 'session.gc_maxlifetime', 60 );?> <?php require"header_login.html"; ?> <link href="mystyle.php" rel="stylesheet" type="text/css" /> <?php //自動ログアウト if (isset($_SESSION['customer'])) { unset($_SESSION['customer']); echo 'ログアウトしました。'; header('Location: index.html'); exit(); } else { echo 'すでにログアウトしています。'; header('Location: index.html'); exit(); } ?>

###login.php

<!-- ヘッダー 読み込み --> <?php require"header.html"; ?> <!------ ログインフォーム 2----------> <div class="form-wrapper"> <h1>Sign In</h1> <form action="login_output.php" method="post"> <div class="form-item"> <label for="email"></label> <input type="text" name="login" required="required" placeholder="user name"></input> </div> <div class="form-item"> <label for="password"></label> <input type="password" name="password" required="required" placeholder="password"></input> </div> <div class="button-panel"> <input type="submit" class="button" title="Sign In" value="Sign In"></input> </div> </form> <div class="form-footer"> <p><a href="#">Create an account</a></p> <p><a href="#">Forgot password?</a></p> </div> </div>

###login_output.php(ログイン成功後list.phpへ飛ぶ)

<?php session_start();?> <?php unset($_SESSION["customer"]); $pdo=new PDO("mysql:host=localhost;dbname=shop7;charset=utf8","staff","password"); $sql=$pdo->prepare("select*from customer where login=? and password=?"); foreach($sql->fetchAll() as $row){ $_SESSION["customer"]=[ "id"=>$row["id"],"name"=>$row["name"], "address"=>$row["address"],"login"=>$row["login"], "password"=>$row["password"] ]; } if (isset($_SESSION["customer"])){ echo "いらっしゃいませ",$_SESSION["customer"] ["name"],"さん"; header('Location: list.php'); exit(); } else{ echo "ログイン名またはパスワードが違います"; } ?>

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hentaiman

2019/11/07 21:04

ログインの処理はどうなっているのか ログイン処理自体が無いのか
Ms.yy

2019/11/07 21:12

失礼しました。 login.php追加させて頂きましたので、ご確認お願いいたします。
Ms.yy

2019/11/07 21:26

ログイン処理はあります。^^;
hentaiman

2019/11/07 21:44

追記を見てもサッパリ分からない 載せるならログイン処理が書いてあるだろうと思われるlogin_output.phpも載せないと分からない login.php自体がログイン処理をしているつもりで作っているのなら一度頭を整理して各処理を見直しを推奨します
Ms.yy

2019/11/07 21:48

お手数お掛けしまして申し訳ございません。抜けておりました、 追記させて頂きましたのでよろしくお願いします。
hentaiman

2019/11/07 22:02

なるほど、list.phpはうっかりミスでもなく素で書いてたのか ini_setは関係ありません セッションの有効期限に関係無くセッションがあれば問答無用で削除してリダイレクトさせる処理だから飛んでいるだけ ini_setは設定か変えるだけのものであって時間差でプログラムを動作させるようなものではない
Ms.yy

2019/11/07 22:09 編集

そういうことでしたか^^; では、自動ログアウトしたい場合何を記述はしたらいいでしょうか? よろしくお願いします。
Y.H.

2019/11/07 23:31

>○秒後 何(どこ)を起点に?ログイン時点?ログイン後の最後のリクエスト時点?
Ms.yy

2019/11/07 23:36

失礼しました。 修正させて頂きます。 ログイン後の最後のリクエスト時点から○秒後に自動ログアウトとなるようにしたいです。
hentaiman

2019/11/08 00:07

丸投げ質問に感じるので低評価したけど、具体的にどこかどう分からないの?
Ms.yy

2019/11/08 02:51 編集

具体的に申しますと、 ログイン後から○秒後に自動ログアウトにするにが、どんなコードを記述すればよいかわかりません。
m.ts10806

2019/11/08 11:33

インデントが全く整理されてないところからロジックの整理ができてない感じが伺えます。 コードフォーマット機能および構文チェック機能のついたエディタの利用を強く推奨します。 Eclipseならデフォルトで色々入ってるので導入はすぐでしょう。 (インデントについてはコードブロックの次に読む気が起きないコード提示です)
Ms.yy

2019/11/09 01:05

Eclipseインストールしました! ただ、使い方に結構手こずりそうです。
guest

回答3

0

もしかしたら以前指摘したかもしれないですが、細かい指摘。

1.下記のような<?phpタグの書き方は悪手。読みづらい

php

1<?php session_start();?> 2<?php ini_set( 'session.gc_maxlifetime', 60 );?> 3 4 5<?php require"header_login.html"; ?> 6

し、<?phpタグ以外は全て画面に出力するので、意味のない空白行が大量に出力されることになる。

だから下記で良い。

php

1<?php 2session_start(); 3ini_set( 'session.gc_maxlifetime', 60 ); 4 5require"header_login.html"; 6

2.同じく「意味のない空白行」という理由で ファイルの最後の?>もその後に出力ないなら不要

3.ini_set()するくらいならphp.iniの設定をいじった方が良い。

4.でないとしても、ini_set()をあとにしてちゃその設定でsession_start()しないんじゃないかな。先にstartしてしまっている。設定が先でしょう。
あと一応「gc_maxlifetime」の「gc」が何かきちんと知っておいた方が良いです。

5.header()の前に出力書いてはダメ。

header()

覚えておいて頂きたいのは、header() 関数は、 通常の HTML タグまたは PHP からの出力にかかわらず、すべての実際の 出力の前にコールする必要があることです。 頻出するエラーとして、include または require 関数、他のファイルをアクセスする関数に 空白または空行があり、header() の前に出力が 行われてしまうというものがあります。同じ問題は、単一の PHP/HTML ファイルを使用している場合でも存在します。

5.下記、必ず1件になる組み合わせならfetchAll()でループする必要なし。ログインなら1件より大きくなり得ないしfetch()でいい。

$sql=$pdo->prepare("select*from customer where login=? and password=?");

細かいこと言うとprepare()の返りはPDOStatementなのでsqlという命名の変数で受けるのはおかしい。

と言うか実行してないのにfetchAll()してますけど?

6.きちんとコードフォーマット、インデントをしよう。
login_output.phpをEclipseでフォーマットかけた上で、整理してみました。
提示のコードとどっちが読みやすいか見比べてみると良いです。

※ロジックは直してません。

php

1<?php 2session_start(); 3unset($_SESSION["customer"]); 4 5$pdo = new PDO("mysql:host=localhost;dbname=shop7;charset=utf8", "staff", "password"); 6$sql = $pdo->prepare("select*from customer where login=? and password=?"); 7 8foreach ($sql->fetchAll() as $row) { 9 10 $_SESSION["customer"] = [ 11 "id" => $row["id"], 12 "name" => $row["name"], 13 "address" => $row["address"], 14 "login" => $row["login"], 15 "password" => $row["password"] 16 ]; 17} 18 19if (isset($_SESSION["customer"])) { 20 echo "いらっしゃいませ", $_SESSION["customer"]["name"], "さん"; 21 22 header('Location: list.php'); 23 exit(); 24} 25else { 26 echo "ログイン名またはパスワードが違います"; 27} 28

細かいこと言うとログイン後はsession_regenerate_id()を流した方が良いし、$_SESSION["customer"]のunset()はログイン時ではなくログアウト時(自動ログアウト含めて)であるべき。

ここから本題

7.そりゃ、速攻でログアウトしますわ

php

1//list.phpに入った時には$_SESSION['customer'])は絶対存在する仕組みになってるから 2if (isset($_SESSION['customer'])) { 3//ここは常にtrue

この作りでisset($_SESSION['customer'])がfalseになるのって、ログインせずに直接list.phpにアクセスしたときくらいです。つまり、絶対にindex.htmlにリダイレクトされる運命しかありません。
ログイン状態を保持するには「一定時間以内だったらログイン継続中」と判断がもう1つ必要です(別途回答がある通り)。

いずれにしてもheader()の前に出力があるのでPHPの構文的にNGですし、そのNGな出力をなくしたら何も表示なく勝手に戻される。

どうするか

よく既存サイトのログイン機能を見返してみてください。
ログイン画面に「セッションタイムアウトしました」って出てませんか?

ログイン後の画面に出しているところはありません。
ログイン画面か、セッションタイムアウト用の別画面を401とか403とかで作って表示させているだけです。

仕様上は「認証されている人だけ見せる画面」であるはずですね。
なので、「認証されている人だけに見せる画面」を「認証されていない、または一定時間操作がないタイムアウト状態の人」のために利用してはいけません。

何らかの方法を用いてタイムアウトしたことが分かる区分やフラグなどを渡してメッセージを表示させるのがベターなやり方です。(そこは考えてください。画面間情報の受け渡しなので手法はそこまで種類はありません)


細かいことを言い続けるとキリがないので、他にも気になる点はたくさんありますが、この辺で。

投稿2019/11/08 12:03

編集2019/11/09 01:50
m.ts10806

総合スコア80875

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ms.yy

2019/11/09 02:54

ご丁寧にありがとうざいます。 すごく参考になります。 コードの書き方は意識するように心がけてみます! phpのロジックの部分はヒントを頂けたので時間はかかると思いますが、改め見直して調べて行くしかありません。^^;
Ms.yy

2019/11/09 02:57

session.gc_maxlifetime session.gc_probability session.gc_divisor この辺りはどうやらsession_startの前に書く感じですね。 今回のタイムアウトは必要なさそうでした。^^;
m.ts10806

2019/11/09 02:58

余裕出てきたらセキュリティ面も加味して実装してくださいね。一切考慮されていない脆弱性に溢れた作りなので。
Ms.yy

2019/11/09 03:06 編集

ちなみにこの自動ログアウトの設定に必要だとされるセッションの時間変更を行うにはphp.ini内の数字を変える場合と、.phpファイルにプログラムを書いて変更する場合と2種類やり方があるということでしょうか?
m.ts10806

2019/11/09 03:22

どの観点で考えるかですが、実務観点から言うと、回答にあるようにプログラム内でPHP設定を変えることってほとんどありません。 バッチプログラムなどWebとは別で動く機能がある場合は使わないこともないですが、iniファイルできちんと設定しますし、あまり長くするのもそれはそれでセキュリティリスクがあります。 あと今回の問題点としては既に別回答にあるように「前回のアクセス日時を保持して今回のアクセス日時と比較」部分が抜けているのもあります。 大抵は、「自動ログアウト」はini設定の時間より短い時間にします。つまり、ini設定で見るのではなく、プログラム側でログアウト「させる」ように組むのが一般的です。
Ms.yy

2019/11/09 03:35

なるほどです。 普通はiniで書き換えるということですね。 ありがとうございます。 ちょっと整理されました。^^ とりあえず現在日時の取得方法とセッションで比較調べてみます!
m.ts10806

2019/11/09 03:38

もちろんiniを書き換えるということは利用しているWebサーバー全てに同じ設定になるので注意は必要です。
m.ts10806

2019/11/09 03:39

>現在日時の取得方法 えっと。まさかそこが分かってないとは思ってなかった。 「日時」とはいっても「計算(引き算)」ができればいいので、time()で充分ですよ。 もしYYYMMDD HHMMSS みたいな形式で保存していたら変換したりなんだり面倒ですし。
Ms.yy

2019/11/09 03:40

なるほどです、 個別に設定したい時には.phpファイルへ書き込む感じということですね。
guest

0

①login_output.phpの以下で$_SESSION["customer"]に最終アクセス日時も保存

$_SESSION["customer"]=[ "id"=>$row["id"],"name"=>$row["name"], "address"=>$row["address"],"login"=>$row["login"], "password"=>$row["password"] ]; }

②list.phpの以下で、ini_setを削除し、以下を追加

<?php ini_set( 'session.gc_maxlifetime', 60 );?>
  • $_SESSION["customer"]が未設定の場合、index.htmlへリダイレクト
  • $_SESSION["customer"]に保存されている最終アクセス日時と現在日時を比較し規定時間経過している場合は、$_SESSION["customer"]をunsetし、index.htmlへリダイレクト
  • 規定時間を経過していない場合は、$_SESSION["customer"]の最終アクセス日時に現在日時をセット。(もし、ログイン時点から規定時間経過で判断するならこれは不要)

③ 以下は削除

<?php //自動ログアウト if (isset($_SESSION['customer'])) { unset($_SESSION['customer']); echo 'ログアウトしました。'; header('Location: index.html'); exit(); } else { echo 'すでにログアウトしています。'; header('Location: index.html'); exit(); } ?>

投稿2019/11/08 00:24

Y.H.

総合スコア7918

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ms.yy

2019/11/08 03:13

ありがとうございます。 さっそく調べながら試してみたいと思います!
m.ts10806

2019/11/08 12:04 編集

Y.H.さん header()の前の出力については何も指摘なしでは質問者がそのままにしてしまいます。 (他にも色々細かい指摘が必要そうなので自身の回答に記してみました)
guest

0

session.gc_maxlifetime を設定したら、指定時間後に、unset が実行されてセッションが消去実行されると想定しているのでしょうか?

session.gc_maxlifetime にあるように、この設定は使われなくなったセッションを削除するまでの時間を設定するものです。

自動ログアウトさせたいということですが、ログアウトを確実に判断するのは難しいので、通常は、操作するたびに最終操作時間をセッション等に記録しておいて、次回操作時に最終操作時間から、一定時間が経過していたらログイン無効と判断して、再ログインをさせるという風にすることが多いと思います。

投稿2019/11/07 22:54

CHERRY

総合スコア25216

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ms.yy

2019/11/07 23:11

はい、session.gc_maxlifetimeを使用するとそのように思っていましたが、違うようですね^^; ご返答頂きました内容の「操作するたびに最終操作時間を」というのは、この場合でいうとlist,phpが更新される度にセッションも更新されて設定した時間が過ぎたらunsetという認識であってますでしょうか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問