前提・実現したいこと
最近独学でプログラミングを始めたPHP初心者です。
現在、サーバーサイド言語としてPHPを使用してログイン機能のついた掲示板を作成しております。
password_hashとpassword_verifyを使うとパスワードを暗号化して扱えると知り、それらを用いてログイン機能を実装しようと試みましたが、うまくいきません。
周りにプログラミング(PHP)のことを相談できる人がおらず、またウェブで調べても解決法を見つけることができなかったため、質問しました。
※開発環境はXAMPP、掲示板利用時のユーザーアカウント管理用テーブル・投稿管理用テーブルはDB(MySQL)で行っております。
発生している問題・エラーメッセージ
エラーメッセージは出ていませんが、ユーザーログイン時にpassword_verifyを用いてユーザーが入力したパスワードと暗号化したパスワードの一致を確認するところがうまくいかず、困っております。
password_verifyを用いてパスワードの一致を確認する際、引数(ハッシュ値)の書き方に問題があるのではなうか?というところまでは突き止めたのですが、ではどのように記述したらよいのか、が分からない状況です。
※なお、password_hashを用いたパスワードの暗号化は出来ており、暗号化されたパスワードはDB内ユーザーアカウント管理のテーブルに問題なく登録されております。
該当のソースコード
password_verifyを使用しているソースコードはこちら↓です。
既存のアカウントに対してログインできるかチェックを行う(Logincheck.php)
PHP
<?php // session開始 session_start(); // DBと繋ぐ(別ファイルに記述) include "DBconnect.php"; // 入力パスワードとDBパスワードが一致した時にログイン処理を進める // ログインページでユーザーが入力した情報を取得 $user_name = $_POST["user_name"]; $user_password = $_POST["user_password"]; // DB内でユーザー名が一致するレコードを$sqlに代入 $sql = "SELECT * FROM stockuser WHERE user_name = '$user_name'"; // SQLを発行し、SQL文がDBに通ったかを判別 if($result = mysqli_query($conn , $sql)) { // ユーザー名が一致したレコードを取り出す $row = mysqli_fetch_assoc($result); // implodeを用いて該当レコードが取り出せているかを確認 echo implode($row); // 該当レコードからパスワードが取り出せているかを確認 echo $row["user_password"]; // 入力したパスワードと暗号化されたパスワードの一致が確認されれば、ログイン許可 // ここが間違っているのではないかと思います。 if(password_verify($user_password, $row["user_password"])) { // 一致していれば"ログインOK"と画面に表示させる echo "ログインOK"; // $flagを使ってログインOK/NGでの動作を定義 $flag = true; } else { // 一致していなければ"ログインNG"と画面に表示させる echo "ログインNG"; // ログインNGのときはfalseとする $flag = false; } } else { echo mysqli_error($conn)."<BR>"; } // MySQLの切断 mysqli_close($conn); // 以降、画面遷移に関するパート // password_verifyの部分を動作確認する際は以降の部分をコメントアウトしております // サーバー情報の記述 $host = $_SERVER['HTTP_HOST']; $uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\'); // $flagがtrueなら、ログイン成功(main.phpにページ遷移) if($flag){ // user_idとuser_nameで連想配列を作り、sessionに載せる $user = array("user_id" => $row["user_id"] , "user_name" => $row["user_name"]); $_SESSION["user"] = $user; $extra = "main.php"; header("Location: http://$host$uri/$extra"); exit(); } // $flagがfalseなら、login2.html(ログインできませんでした のページ)に遷移 else{ // sessionを破壊 session_destroy(); // session破壊後に遷移先ページへの移動を行う $extra = "login2.php"; header("Location: http://$host$uri/$extra"); exit(); } ?>
関連ファイルの情報
DBと繋ぐためのファイル(DBconnect.php)
PHP
<?php // DBに繋ぐためのファイル // サーバへの接続情報を登録 $DBSERVER = "localhost:3307"; $DBUSER = "root"; $DBPASSWORD = ""; $DBNAME = "hellowordsdb"; //MySQLへの接続 $conn = mysqli_connect($DBSERVER , $DBUSER , $DBPASSWORD , $DBNAME); //接続時にエラーが発生していれば、エラーメッセージを表示 if(mysqli_connect_error()) { echo mysqli_connect_error(); exit(); } else { // 下のechoは後ほど削除(表示があるとページ遷移ができないのでコメントアウト) // echo "Connect OK"; } ?>
新規ユーザー登録時、パスワードは暗号化してDBに登録する(registAccount.php)
PHP
<?php // DBにユーザを新規登録するためのファイル // セッション開始 session_start(); // 新規登録ボタンが押された時の確認項目 if(isset($_POST["register"])){ // DB接続のためのファイルを読み込み include "DBconnect.php"; // ユーザー名、ユーザーアドレスの情報を新規登録ページから取得 $user_name = $_POST["user_name"]; $user_address = $_POST["user_address"]; // パスワードは暗号化して登録する $hash = password_hash($_SESSION["user_password"], PASSWORD_DEFAULT); // insert文の組み立て・sql文の発行 $sql = "INSERT INTO stockUser (user_name , user_address , user_password , enable) "; $sql .= " VALUES ('$user_name' , '$user_address' , '$hash' , 1)"; // 必要な情報が揃っていれば、ユーザ情報を登録 if($result = mysqli_query($conn , $sql) ){ // sessionに情報を積む $user = array("user_id" => mysqli_insert_id($conn) , "user_name" => $user_name); $_SESSION["user"] = $user; $host = $_SERVER['HTTP_HOST']; $uri = rtrim(dirname($_SERVER['PHP_SELF']), '/\'); $extra = "main.php"; // 一覧画面に転送 header("Location: http://$host$uri/$extra"); exit(); } // 情報入力が不足していた場合 else { // 入力画面に戻す $err_msg = mysqli_error($conn); $user_name = $_POST["user_name"]; $user_address = $_POST["user_address"]; include "newAccount.php"; } } // 戻るボタンが押された時は、ひとつ前の入力画面へ戻す else { $err_msg = ""; $user_name = $_POST["user_name"]; $user_address = $_POST["user_address"]; include "newAccount.php"; } ?>
ログインフォーム(login.php)
PHP
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" type="text/css" href="login.css?v=5"> <link rel="icon" href="images/wordcard.png"> <title>Hello!Words ログイン</title> </head> <body> <div id="container"> <h2>Hello! Words ログイン画面</h2> <p>ログイン情報を入力してください</p> <!-- action属性で情報の送り先となるページ(Logincheck.php)を指定 --> <form action="Logincheck.php" method="post"> <table> <tr> <th>ユーザー名</th> <td><input type="text" name="user_name"></td> </tr> <tr> <th>パスワード</th> <td><input type="password" name="user_password"></td> </tr> </table> <input class="buttons" type="submit" href="main.php" value="ログイン"> </form> <a href="top.php">トップへ戻る</a> </div> </body> </html>
ユーザー名またはパスワードが一致せずログインできなかった場合に表示するページ(login2.php)
PHP
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" type="text/css" href="login.css?v=4"> <link rel="icon" href="images/wordcard.png"> <title>Hello!Words ログイン</title> </head> <body> <div id="container"> <h2>Hello! Words ログイン画面</h2> <p>ログイン情報を入力してください</p> <!-- action属性で情報の送り先となるページ(Logincheck.php)を指定 --> <!-- エラー表示 --> <div class="err">ユーザー名またはパスワードが違います</div> <form action="Logincheck.php" method="post"> <table> <tr> <th>ユーザー名</th> <td><input type="text" name="user_name"></td> </tr> <tr> <th>パスワード</th> <td><input type="password" name="user_password"></td> </tr> <tr> <!-- <th><input type="submit" href="top.php" value="トップページに戻る"></th> --> <th><input class="buttons" type="submit" href="main.php" value="ログイン"></th> </tr> </table> </form> <a href="top.php">トップへ戻る</a> </div> </body> </html>
試したこと
Logincheck.php内に記載をしておりますが、レコードが問題なく取得できているかどうか、echoで画面に出力させて確認しました。
PHP
// implodeを用いて該当レコードが取り出せているかを確認 echo implode($row); // 該当レコードからパスワードが取り出せているかを確認 echo $row["user_password"];
画面には以下↓のように取得したレコードの値が出力されます。
ユーザーID ユーザー名 ユーザーアドレス ユーザーパスワード(暗号化したもの)
ユーザーパスワード(暗号化したもの)
ログインNG
...この結果から、抽出したいレコード及びパスワードは取り出せているものの、"ログインNG"との表示が出るため、password_verifyがきちんと機能できていないのではないかと考えております。
補足情報(FW/ツールのバージョンなど)
データベースの情報
DB名: hellowordsdb
DBでユーザー管理を行うテーブルの情報は以下の通りです。
テーブル名: stockuser
カラム名: user_id, user_name, user_address, user_password, enable(有効なアカウントかを入力)
使用ツールについて
OS: Windows10
開発環境: XAMPP Control Panel v3.2.4
コーディングツール: Visual Studio Code
追記:
hoshi-takanori様からご指摘いただいた内容を試してみました(ご指摘の内容はコメント欄をご覧ください)。
- まず、既存のアカウントでログインを行う際にパスワードを空文字でログインを試みたところ、以下↓の画面表示となりました。
ユーザーID ユーザー名 ユーザーアドレス ユーザーパスワード(暗号化したもの)
ユーザーパスワード(暗号化したもの)
ログインOK
...上記 "ログインOK"との表示から、ログイン出来ており、その際のパスワードは空文字で登録されていた。ということが判明しました。
- そこで、registAccount.phpファイル内にてパスワードハッシュ化を行う箇所のスーパーグローバル変数を以下のように変更
($_SESSION → $_POST)
PHP
// パスワードは暗号化して登録する $hash = password_hash($_POST["user_password"], PASSWORD_DEFAULT);
上記コードに変更後、テストを行った(新規ユーザー登録を行い、一旦ログアウトした後にログインを試みた)ところ、問題なくログインすることができました。
質問した内容について解決することができ、本当に助かりました。ご回答いただいた皆様、本当にありがとうございました。
まだ回答がついていません
会員登録して回答してみよう