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

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

ただいまの
回答率

90.49%

  • PHP

    20379questions

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

  • HTML

    8999questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

【PHP】ログイン機能の実装

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 2,250

shar0430

score 8

PHP初心者です。
PHPの勉強がてら、会員制のページを作成してます。

新規会員登録機能は実装できていますが、
ログイン機能の実装がうまくいきません。
やりたいことを実現するにはどのように記述すればよいか
ご教授頂けませんでしょうか。

やりたいことは以下です。

<ToBe>
・DBに登録されているメールアドレス・パスワードでのみログイン可
・メールアドレス、パスワードのいずれかが空欄のときは
エラーメッセージを表示したい。
・ログイン後はメインページに遷移。

<AsIs>
・常にエラーメッセージが表示されている。
・登録済みのユーザでログインできない

以下、ソースです。

index.html (17/3/1 追記 ver1.1)

<?php   
require('dbconnect.php');  

session_start();  

if(isset($_POST)){  
if(!empty($_POST)){ //ログインの処理   
if($_POST['mail'] != '' && $_POST['pass'] != ''){   
$sql = sprintf('SELECT * FROM users WHERE mail="%s" AND pass="%s"',   
mysqli_real_escape_string($db, $_POST['mail']),   
mysqli_real_escape_string($db, sha1($_POST['pass']))   
);   
$record = mysqli_query($db, $sql) or die(mysqli_error($db));   
$result = mysqli_fetch_assoc($record);  
if(!empty($result)){ //ログイン成功   
header('Location: main.php');   
exit();               
}else{  
$error['login'] = 'failed';   
}  
}else{   
$error['login'] = 'blank';   
}  
}  
}  
ini_set('display_errors', 1);
error_reporting(E_ALL);

?>  

<!DOCTYPE html>   
<html>   
<head>   
<title>Login</title>   
</head>   
<body bgcolor="#FAFC7B">   
<h2>Login</h2>   
<img src="nekos.jpg">   
<form action="" method="post">   
<dl>   
<dt>メールアドレス</dt>   
<dd><input type="text" name="mail" size="35" maxlength="255"> </dd>   
<dt>パスワード</dt>   
<dd><input type="password" name="pass" size="35" maxlength="255"></dd>   
</dl>   
<input type="submit" value="ログイン">   
<?php var_dump($error['login']); ?>

<?php if(!empty($error['login']) && $error['login'] == 'blank'): ?>   
<p><font color="red">* メールアドレスまたはパスワードをご記入ください</font></p>   
<?php endif; ?>   
<?php if(!empty($error['login']) && $error['login'] == 'failed'): ?>   
<p><font color="red">* ログインに失敗しました。正しくご記入ください。</font></p>   
<?php endif; ?>   
</form>   
<HR>   
<a href="join/register.php">新規登録</a>&nbsp; &nbsp;     
<a href="lookingforpass.php">パスワード照会</a>&nbsp; &nbsp;
<a href="contact.html">お問い合わせ</a>     
</body>  
</html>  

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • kei344

    2017/03/01 14:04

    質問文のコードはそれぞれコードブロックで囲んでいただけませんか? ```(バッククオート3つ)で囲み、前後に改行をいれるか、コードを選択して「<code>」ボタンを押すとコードブロックになります。

    キャンセル

  • kei344

    2017/03/04 14:46

    まだ質問が「受付中」になっていますが、いったん「解決済」にされてはいかがでしょうか。また、解決されていないなら状況を追記ください。

    キャンセル

  • shar0430

    2017/03/05 11:44

    皆さん、ご丁寧に御回答頂きありがとうございます。ベストアンサーは悩みましたが、解決のきっかけとなったKosuke_shibuyaに決めさせて頂きました。ありがとうございました。

    キャンセル

回答 3

checkベストアンサー

+3

開発時は必ず、下に示したコードのように、

ini_set('display_errors', 1);
error_reporting(E_ALL);

を記述し、 エラーメッセージを表示してください 。
質問する際には、表示されたエラーを記述するようにしましょう。
もっとも、表示されたエラーには、「なぜうまくいかないか」の理由が書かれているものですから、質問を建てる前に、自己解決できる場合がほとんどです。

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

require('dbconnect.php');

やっつけサンプル

SQL

CREATE TABLE `Users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `email` varchar(64) DEFAULT NULL,
  `password` varchar(256) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- password = 'password'
INSERT INTO `Users` (`id`, `email`, `password`)
VALUES
    (1,'user@example.com','$2y$10$OqyHPnhhs7nFZGrB/P7wDuN1sZ7olqyc8r3bUTXIKRqg00eJRu/W2');

index.php

<?php
/**
 * index.php
 */
ini_set('display_errors', true);
error_reporting(E_ALL);

session_start();

define('DSN', 'mysql:host=localhost;dbname=sample;charset=utf8');
define('USERNAME', 'root');
define('PASSWORD', 'password');

/**
 * htmlspecialchars
 */
function h($string)
{
    return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

/**
 * SELECT
 */
function select($sql, $params = [])
{
    $options = [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ];
    $objPdo = new PDO(DSN, USERNAME, PASSWORD, $options);
    $stmt = $objPdo->prepare($sql);
    $stmt->execute($params);
    return $stmt->fetchAll();
}

/**
 * ログイン
 */
function login()
{
    if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') !== 'POST') {
        return;
    }
    $email = filter_input(INPUT_POST, 'email');
    $password = filter_input(INPUT_POST, 'password');
    if (empty($email) || empty($password)) {
        throw new Exception('メールアドレスおよびパスワードは入力必須です。');
    }

    $sql = 'SELECT * FROM `Users` WHERE `email` = :email ';
    $params = [];
    $params['email'] = $email;
    $rows = select($sql, $params);

    $user = reset($rows);
    if (count($rows) === 0 || !password_verify($password, $user['password'])) {
        throw new Exception('メールアドレスおよびパスワードが間違っています。');
    }

    session_regenerate_id(true);
    $_SESSION['login_user'] = $user;

    return true;
}

try {
    if (login()) {
        header('Location: top.php');
    }
} catch (Exception $ex) {
    $err = $ex->getMessage();
}
?>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Signin Template for Bootstrap</title>

        <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
        <style type="text/css">
            body {
                padding-top: 40px;
                padding-bottom: 40px;
                background-color: #eee;
            }

            .form-signin {
                max-width: 330px;
                padding: 15px;
                margin: 0 auto;
            }
            .form-signin .form-signin-heading,
            .form-signin .checkbox {
                margin-bottom: 10px;
            }
            .form-signin .checkbox {
                font-weight: normal;
            }
            .form-signin .form-control {
                position: relative;
                height: auto;
                -webkit-box-sizing: border-box;
                -moz-box-sizing: border-box;
                box-sizing: border-box;
                padding: 10px;
                font-size: 16px;
            }
            .form-signin .form-control:focus {
                z-index: 2;
            }
            .form-signin input[type="email"] {
                margin-bottom: -1px;
                border-bottom-right-radius: 0;
                border-bottom-left-radius: 0;
            }
            .form-signin input[type="password"] {
                margin-bottom: 10px;
                border-top-left-radius: 0;
                border-top-right-radius: 0;
            }
        </style>
    </head>

    <body>

        <div class="container">

            <?php if (isset($err)) : ?>
                <div class="alert alert-danger">
                    <p>
                        <?= h($err); ?>
                    </p>
                </div>
            <?php endif; ?>

            <form class="form-signin" method="post">
                <h2 class="form-signin-heading">Please sign in</h2>

                <label for="inputEmail" class="sr-only">
                    Email address
                </label>
                <input type="email" name="email" id="inputEmail" class="form-control" placeholder="Email address" autofocus>

                <label for="inputPassword" class="sr-only">
                    Password
                </label>
                <input type="password" name="password" id="inputPassword" class="form-control" placeholder="Password">

                <button class="btn btn-lg btn-primary btn-block" type="submit">
                    Sign in
                </button>
            </form>

        </div> <!-- /container -->
    </body>
</html>

top.php

<?php
/**
 * top.php
 */
ini_set('display_errors', true);
error_reporting(E_ALL);

session_start();

/**
 * htmlspecialchars
 */
function h($string)
{
    return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
}

/**
 * check_login
 */
function check_login()
{
    $res = (isset($_SESSION['login_user']) && $_SESSION['login_user'] != NULL);
    if (!$res) {
        header('Location: index.php');
    }
}

check_login();
?>
<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>
    <body>
        <?= h($_SESSION['login_user']['email']); ?>
    </body>
</html>

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+2

まずはテンプレですが…質問文のコードはそれぞれコードブロックで囲んでいただけませんか? ```(バッククオート3つ)で囲み、前後に改行をいれるか、コードを選択して「<code>」ボタンを押すとコードブロックになります。 次にカッコが抜けていたりする箇所が多かったです。それが動作が想定と異なる原因になります。個人的にはIDEの利用をお勧めします。私がつかっているのはNetbeansですが、それ以外にも無料のIDEがあるので使ってみてください。少なくとも、文法エラーは一目瞭然でわかりますので…

で、実際に拝見したコードを軽く直してみました。とりあえず、ログインの為のDB読込はできると思いますよ。

<?php   
require('dbconnect.php');  

session_start();  

if(isset($_POST)){  
if(!empty($_POST)){ //ログインの処理   
if($_POST['mail'] != '' && $_POST['pass'] != ''){   
$sql = sprintf('SELECT * FROM users WHERE mail="%s" AND pass="%s"',   
mysqli_real_escape_string($db, $_POST['mail']),   
mysqli_real_escape_string($db, sha1($_POST['pass']))   
);   
$record = mysqli_query($db, $sql) or die(mysqli_error($db));   
$result = mysqli_fetch_assoc($record);  
if(!empty($result)){ //ログイン成功   
header('Location: main.php');   
exit();               
}else{  
$error['login'] = 'failed';   
}  
}else{   
$error['login'] = 'blank';   
}  
}else{  
echo '<p>NOSET!!!!</p>';  
}  
}  

?>  

<!DOCTYPE html>   
<html>   
<head>   
<title>ログインページ</title>   
</head>   
<body bgcolor="#FAFC7B">   
<h2>ログインページ</h2>   
<img src="nekos.jpg">   
<form action="" method="post">   
<dl>   
<dt>メールアドレス</dt>   
<dd><input type="text" name="mail" size="35" maxlength="255"> </dd>   
<dt>パスワード</dt>   
<dd><input type="password" name="pass" size="35" maxlength="255"></dd>   
</dl>   
<input type="submit" value="ログイン">   
<?php if(!empty($error['login']) && $error['login'] == 'blank'): ?>   
<p><font color="red">* メールアドレスまたはパスワードをご記入ください</font></p>   
<?php endif; ?>   
<?php if(!empty($error['login']) && $error['login'] == 'failed'): ?>   
<p><font color="red">* ログインに失敗しました。正しくご記入ください。</font></p>   
<?php endif; ?>   
</form>   
<HR>   
<a href="join/register.php">新規登録</a>     
<a href="lookingforpass.php">パスワード照会</a>     
<a href="contact.html">お問い合わせ</a>     
</body>  

</html>  

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/03/01 15:31

    ご回答ありがとうございます。修正頂いたコードでも変化なしです。
    常に
    $error['login'] = 'failed';
    $error['login'] = 'blank';

    なっている?ようで、
    * メールアドレスまたはパスワードをご記入ください
    * ログインに失敗しました。正しくご記入ください。

    が常に表示されています。
    それとも
    <?php if分がうまく認識されていないんでしょうか、、

    キャンセル

  • 2017/03/01 15:40

    そうですか…私の環境では正常に動いているので、何かしらの齟齬があるのでしょう。

    まずは、$error['login']にどのような値が入っているか、確認頂けますか?
    * メールアドレスまたはパスワードをご記入ください
    * ログインに失敗しました。正しくご記入ください。
    常に上記の2行が「同時に」出ている訳では無いですよね?もし、同時に出ているのであれば、コピペミスが考えられます。もう一度、私が提示したソースとご自分のソースを確認してください。

    ログインボタンの下に、<?php var_dump($error['login']);?>を仕込むと、その時の値がブラウザで確認できるはずです。

    キャンセル

  • 2017/03/01 16:59

    <input type="submit" value="ログイン">
    <?php var_dump($error['login']); ?>

    上記の位置に仕込んでみましたが、ブラウザには何も出ません。
    ちなみにレンタルウェブサーバを借りて本番環境で直接開発してます。

    キャンセル

  • 2017/03/01 17:04

    では、改めてKosuke_Shibuyaさんの回答通り、
    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    を追加してみましょう。これで何かエラーが出てきませんか?

    また、上記対応後にも上手くいかないようでしたら、現時点のソースを質問に追記して頂けますか?

    キャンセル

  • 2017/03/01 17:16

    デバッグがブラウザに表示されない件についてですが
    php.iniも問題ないようです。
    display_startup_errors=Off 
    display_errors=On 
    error_reporting=E_ALL & ~E_NOTICE 

    キャンセル

  • 2017/03/01 17:20 編集

    質問文のソース、//require('dbconnect.php'); を外して
    $db = mysqli_connect("127.0.0.1", "test", "test", "test");
    としても正常に動きますね。。。
    もしかしたら、dbconnect.phpで例外が発生しているのかもしれませんね。

    初期画面表示の画像と、ログインボタン押下後のハードコピーを見ると何か浮かぶかもしれませんが…
    環境となると、もはやお手上げかもしれません。

    キャンセル

  • 2017/03/01 17:31

    $db = mysqli_connect("127.0.0.1", "test", "test", "test");
    に変えても表示結果変わりませんね。
    謎です。
    ありがとうございました。。。。

    キャンセル

  • 2017/03/01 17:34

    一応、、、言葉足らずだったかもしれませんが、
    mysqli_connect("ホスト名", "ユーザ", "パスワード", "DB名");
    ですよ。大丈夫ですよね?ご自身の環境の文字に変えてあげてくださいね。

    それでもダメなら、いよいよちょっと分からないです。。。

    キャンセル

  • 2017/03/01 18:02

    PHPの実行環境で動作させていないように思えます。つまり、アドレスバーが「file:///」の状態。

    キャンセル

  • 2017/03/02 04:24 編集

    ini_set('display_errors', 1);
    error_reporting(E_ALL);
    はファイルの先頭に入れないと意味がありません。

    あと、ファイル名は index.html ではなく、 index.php でなければなりません。

    キャンセル

  • 2017/03/02 11:32

    ファイル名をindex.phpに変更したところ、エラーメッセージ出力等、PHPが正常に動作しました。
    ありがとうございます。初歩的なミスで恐縮です。エラーメッセージを元に修正かけたいと思います。
    どうにもエラーが解消しない場合に、再度質問させて頂ければと思います。

    キャンセル

  • 2017/03/02 12:06

    >Kosuke_Shibuyaさん
    そもそもの問題でしたね…気付ければ良かった…フォローして頂き、ありがとうございました。

    キャンセル

+2

質問とは全く関係ない部分ですが、

pass=sha1($_POST['pass'])

暗号強度はほぼゼロなので使ってはいけません。
例:passが'5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8'ならパスワードは'password'と判る

× 固定値SALTを使う
http://qiita.com/shunsuke_takahashi/items/fcbe1e08aa94b208c14a

△ 個別SALTを使う
http://qiita.com/ms2sato/items/6005eea50def287090d0

○ password_hashを使う

    // パスワード登録時
    $sql = 'INSERT INTO users (mail, pass) VALUES (?, ?)';
    $stmt = mysqli_prepare($db, $sql);
    mysqli_stmt_bind_param($stmt, 'ss', $_REQUEST['mail'], password_hash($_REQUEST['pass'], PASSWORD_DEFAULT));
    mysqli_stmt_execute($stmt);

    // パスワード照合時
    $sql = 'SELECT * FROM users WHERE mail = ?';
    $stmt = mysqli_prepare($db, $sql);
    mysqli_stmt_bind_param($stmt, 's', $_REQUEST['mail']);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_bind_result($stmt, $user);
    mysqli_stmt_fetch($stmt);
    if(password_verify($_REQUEST['pass'], $user['pass'])){
        // ログイン成功
    }

あと手続き型mysqliはわかりにくいので、mysqliクラスにするかPDOをお勧めします。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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

  • PHP

    20379questions

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

  • HTML

    8999questions

    HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。