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

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

ただいまの
回答率

90.51%

  • PHP

    24065questions

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

  • MySQL

    7004questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

電話番号もしくはメールアドレスでユーザ認証させたい

解決済

回答 2

投稿

  • 評価
  • クリップ 2
  • VIEW 1,182

ssk

score 273

ユーザー認証を
・電話番号orメールアドレス
・パスワード

にしたいのですが、どのように書けば良いでしょうか。

$sql ='SELECT * FROM user WHERE tel=? OR mail=? AND password=?';


ここの部分を変えれば良いと思うのですが、どのように書けば良いかわかりません。
よろしくお願い致します。

全体のPHPは以下です。

<?php
try{
    $tel_mail=$_POST['tel_mail'];
    $password=$_POST['password'];
    //サニタイジング
    $tel_mail=htmlspecialchars($tel_mail);
    $password=htmlspecialchars($password);
    $password=md5($password);
    //データベース接続
    require_once('./conf/db_con.php');
    $sql ='SELECT * FROM user WHERE tel=? OR mail=? AND password=?';
    $stmt=$dbh->prepare($sql);
    $data[]=$tel_mail;
    $data[]=$password;
    $stmt->execute($data);
    //1行ずつ取り出し
    $rec = $stmt->fetch(PDO::FETCH_ASSOC);
    $dbh=null;
}catch(Exception $e){
    print 'ただいま障害により大変ご迷惑をお掛けしております。';
    exit();
}
?>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+5

ツッコミどころ満載なので、コメントで。

<?php

// 開発中は必ず記述
ini_set('display_errors', true);
error_reporting(E_ALL);

try {
//    $tel_mail = $_POST['tel_mail'];
//    $password = $_POST['password'];
    $tel_mail = filter_input(INPUT_POST, 'tel_mail');
    $password = filter_input(INPUT_POST, 'password');

    $dbh = new PDO('mysql:dbname=testdb;host=localhost;charset=utf8'
        , $username
        , $passwd
        , array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION));


    //サニタイジング
//    $tel_mail = htmlspecialchars($tel_mail); // <- 完全な間違い htmlspecialchars ダメ!
//    $password = htmlspecialchars($password); // <- 完全な間違い htmlspecialchars ダメ!

    $sql = 'SELECT * FROM user WHERE (tel=:tel_mail OR mail=:tel_mail) AND password=:password';
    $stmt = $dbh->prepare($sql);

    $data[':tel_mail'] = $tel_mail;
    $data[':password'] = md5($password); // <- md5 なんて今時使うもんじゃないけど、本題ではないのでスルー

    $stmt->execute($data);

    //1行ずつ取り出し
    $rec = $stmt->fetch(PDO::FETCH_ASSOC);
} catch (Exception $e) {
    print 'ただいま障害により大変ご迷惑をお掛けしております。';
    exit();
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/05/28 08:39

    これたぶん有名な某書籍のやつですね…

    キャンセル

  • 2016/05/28 14:05

    ありがとうございます。
    はい、書籍を参考に書いていました。

    新しい本だったのでセキュリティも問題ないかと思っていたのですが
    あまり良くないようですね、、

    CertaiN様、Kosuke_Shibuya
    ご回答ありがとうございました。

    キャンセル

  • 2016/05/28 14:06

    PHPの初心者向けの書籍ではあまり良書はないですねー。

    キャンセル

+1

場当たり的な修正案に関してはKosuke_Shibuyaさんが既にコメントされているので,今後の実装の方針としてどうすればいいかについて.

PHPによる簡単なログイン認証いろいろ

こちらに認証機構の設け方についてまとめてあります.今回は「セッション認証」と称しているものに該当するかと思います.ただし, $hashes として設けているものは,データベース内に存在していると考えます.

 コーディングに関するポイント

(セキュリティ上絶対に無視できないレベルで必須)

  • パスワードは直接記録したり脆弱なmd5は使わず,より強力なpassword_hashで作成したハッシュを取り扱う.
  • パスワードの照合はデータベース上では行わず,まずメールアドレス (UNIQUE制約のある前提) のみの指定で1件取り出してきておいて, 後からパスワードをpassword_verifyで検証して判定する.

(セキュリティ上多くの場合において必須)

  • セッションIDのハッシュ値を使ってCSRF対策を行う.
  • htmlspecialcharsは下処理の段階で適用してはいけない.逆に,HTMLとして表示する最終段階には絶対に適用を忘れないようにする.

(推奨)

  • PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTIONを指定し,あらゆる処理でPDOExceptionがハンドルできるようにする.
  • 例外発生でexitするときはheader("Content-Type: text/plain; charset=UTF-8", true, 500);を先に実行する.

 運用に関するポイント

こちらは実運用する場合にのみ考えてください.練習用のサイトをローカルに立ち上げるだけでは気にしなくていいです.

(セキュリティ上絶対に無視できないレベルで必須)

  • パスワードを送信するページはTLSで暗号化する

(推奨)

  • 全てのコンテンツをTLSで暗号化する

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/05/28 15:00

    CertaiN様

    http://qiita.com/mpyw/items/bb8305ba196f5105be15
    こちらのサイトを見て勉強しています。
    以下の部分が理解できないのですが、

    ただし, $hashes として設けているものは,データベース内に存在していると考えます。
    ↑password_hashを利用して登録したユーザテーブルの事を指していますか?

    // 事前に生成したユーザごとのパスワードハッシュの配列
    $hashes = [
    'ユーザ名' => '$2y$10$TThG3fsMJegLJHzVQbz8IeHhvpgBg7P5j6gjQWEUOrKKCtsA9L87G',
    ];

    キャンセル

  • 2016/05/28 15:36

    そうですね,ユーザ名と紐つけてパスワードハッシュをデータベースに格納してください.(この例は簡略化のために連想配列でハードコーディングしているだけです)

    キャンセル

  • 2016/06/12 10:32

    mpyw様
    お世話になっております。

    上記の件、試しているのですが
    うまくいかず、困っています><

    <?php include('header.php'); ?>
    <?php
    require_once __DIR__ . '/functions.php';
    require_unlogined_session();
    ini_set('display_errors', true);
    error_reporting(E_ALL);
    //ユーザから受け取ったユーザ名とパスワード
    $tel_mail = filter_input(INPUT_POST, 'tel_mail');
    $password = filter_input(INPUT_POST, 'password');
    try{
    //データベース接続
    include('./conf/db_con.php');
    $sql ='SELECT * FROM user WHERE (tel=":tel_mail" OR mail=":tel_mail")';
    $stmt=$dbh->prepare($sql);
    $data[':tel_mail'] = $tel_mail;
    $stmt->execute($data);
    $dbh = null;
    //1行ずつ取り出し
    $rec = $stmt->fetch(PDO::FETCH_ASSOC);
    // 事前に生成したユーザごとのパスワードハッシュの配列
    $hashes = [
    'tel_mail' => $rec['password'],
    ];
    }catch(Exception $e){
    print 'ただいま障害により大変ご迷惑をお掛けしております。';
    exit();
    }

    // POSTメソッドのときのみ実行
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (
    validate_token(filter_input(INPUT_POST, 'token')) &&
    password_verify(
    $password,
    isset($hashes[$tel_mail])
    ? $hashes[$tel_mail]
    : '$2y$10$abcdefghijklmnopqrstuv' // ユーザ名が存在しないときだけ極端に速くなるのを防ぐ
    )
    ) {
    // 認証が成功したとき
    // セッションIDの追跡を防ぐ
    session_regenerate_id(true);
    // ユーザ名をセット
    session_start();//合言葉を決める
    $_SESSION['login']=1;//ログインOKの証拠を残す
    $_SESSION['user_id']=$rec['user_id'];
    // ログイン完了後に / に遷移
    header('Location: /');
    exit;
    }
    // 認証が失敗したとき
    // 「403 Forbidden」
    http_response_code(403);
    }

    header('Content-Type: text/html; charset=UTF-8');

    ?>
    <main id="regist"><?php var_dump($hashes); ?>
    <div class="container">
    <section class="container">
    <form class="form-horizontal" action="" method="post">
    <fieldset>
    <div class="clearfix"></div><br>
    <div class="input-group input-group-lg">
    <span class="input-group-addon"><i class="glyphicon glyphicon-user red"></i></span>
    <input type="text" class="form-control" placeholder="電話番号またはメールアドレス" name="tel_mail">
    </div>
    <div class="clearfix"></div><br>
    <div class="input-group input-group-lg">
    <span class="input-group-addon"><i class="glyphicon glyphicon-lock red"></i></span>
    <input type="password" class="form-control" placeholder="パスワード" name="password">
    </div>
    <div class="clearfix"></div>
    <div class="col-sm-12">
    <button type="submit" class="btn btn-default center-block">ログイン</button>
    </div>
    </fieldset>
    <input type="hidden" name="token" value="<?=h(generate_token())?>">
    </form>
    <?php if (http_response_code() === 403): ?>
    <p style="color: red;">ユーザ名またはパスワードが違います</p>
    <?php endif; ?>
    </section>
    </div>
    </main>
    <?php include('footer.php'); ?>

    キャンセル

  • 2016/06/12 10:33

    まず、

    <?php var_dump($hashes); ?>
    とすると

    array(1) { ["tel_mail"]=> NULL }
    と表示されてしまいます。
    何が間違っているのでしょうか。

    キャンセル

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

  • PHP

    24065questions

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

  • MySQL

    7004questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。