sql >> データベース >  >> RDS >> Mysql

ユーザー登録と電子メール検証PHPとMySQL

    PHPとMySQLを使用して完全なユーザー登録とログインシステムを作成することについてのブログ投稿をすでに書いていますが、メールによる確認は含まれていません。

    このチュートリアルは、前のチュートリアルの更新に少し似ています。アカウントの登録、ログイン、ログアウトに加えて、ユーザーには確認メールがメールアドレスに送信されます。このリンクをクリックしてメールアドレスを確認することもできます。

    構築するほとんどのアプリケーションでは、さまざまな理由で電子メール検証機能を追加することが重要です。後でユーザーに電子メールを送信し、ユーザーに確実に表示されるようにしたい場合があります。または、ユーザーがパスワードを忘れてリセットする必要がある場合があります。これを行うには、パスワードリセットリンクをメールで送信する必要があります。他にも多くの理由がありますが、要点はわかります。

    現在構築しているこのシステムでは、メールを確認していないユーザーは特定のアクションを実行できません(ボタンの表示などの簡単なデモを使用します。確認済みのユーザーのみがそのボタンを表示できます)。

    まず、verify-userという名前の新しいPHPプロジェクトを作成し、このフォルダーに、signup.phpとlogin.phpの2つのファイルを作成します。

    signup.php:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
    
      <!-- Bootstrap CSS -->
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
      <link rel="stylesheet" href="main.css">
      <title>User verification system PHP</title>
    </head>
    <body>
      <div class="container">
        <div class="row">
          <div class="col-md-4 offset-md-4 form-wrapper auth">
            <h3 class="text-center form-title">Register</h3>
            <form action="signup.php" method="post">
              <div class="form-group">
                <label>Username</label>
                <input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
              </div>
              <div class="form-group">
                <label>Email</label>
                <input type="text" name="email" class="form-control form-control-lg" value="<?php echo $email; ?>">
              </div>
              <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control form-control-lg">
              </div>
              <div class="form-group">
                <label>Password Confirm</label>
                <input type="password" name="passwordConf" class="form-control form-control-lg">
              </div>
              <div class="form-group">
                <button type="submit" name="signup-btn" class="btn btn-lg btn-block">Sign Up</button>
              </div>
            </form>
            <p>Already have an account? <a href="login.php">Login</a></p>
          </div>
        </div>
      </div>
    </body>
    </html>
    

    単純なHTML/CSSファイルです。注目に値する唯一のことは、Bootstrap4CSSフレームワークを使用してページのスタイルを設定していることです。他の任意のスタイリングフレームワークを使用することも、必要に応じて独自のCSSを作成することもできます。

    Bootstrap CSSの直後に、カスタムスタイル用のmain.cssファイルが含まれています。それでは、そのファイルを作成しましょう。アプリケーションのルートフォルダに、main.cssというファイルを作成します。

    main.css:

    @import url('https://fonts.googleapis.com/css?family=Lora');
    li { list-style-type: none; }
    .form-wrapper {
      margin: 50px auto 50px;
      font-family: 'Lora', serif;
      font-size: 1.09em;
    }
    .form-wrapper.login { margin-top: 120px; }
    .form-wrapper p { font-size: .8em; text-align: center; }
    .form-control:focus { box-shadow: none; }
    .form-wrapper {
      border: 1px solid #80CED7;
      border-radius: 5px;
      padding: 25px 15px 0px 15px;
    }
    .form-wrapper.auth .form-title { color: #007EA7; }
    .home-wrapper button,
    .form-wrapper.auth button {
      background: #007EA7;
      color: white;
    }
    .home-wrapper {
      margin-top: 150px;
      border-radius: 5px;
      padding: 10px;
      border: 1px solid #80CED7;
    }
    

    このファイルの最初の行では、フォントをより美しく見せるためにいくつかのGoogleFontsをインポートして使用しています。

    次に、login.phpファイルを参照して、同様のことを行います。

    login.php:

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <!-- Bootstrap CSS -->
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
      <link rel="stylesheet" href="main.css">
      <title>User verification system PHP - Login</title>
    </head>
    <body>
      <div class="container">
        <div class="row">
          <div class="col-md-4 offset-md-4 form-wrapper auth login">
            <h3 class="text-center form-title">Login</h3>
            <form action="login.php" method="post">
              <div class="form-group">
                <label>Username or Email</label>
                <input type="text" name="username" class="form-control form-control-lg" value="<?php echo $username; ?>">
              </div>
              <div class="form-group">
                <label>Password</label>
                <input type="password" name="password" class="form-control form-control-lg">
              </div>
              <div class="form-group">
                <button type="submit" name="login-btn" class="btn btn-lg btn-block">Login</button>
              </div>
            </form>
            <p>Don't yet have an account? <a href="signup.php">Sign up</a></p>
          </div>
        </div>
      </div>
    </body>
    </html>
    

    ブラウザでhttp://localhost/cwa/verify-user/signup.phpにアクセスすると、美しいサインアップフォームが表示されます(ログインでも同じです)。入力フィールドのエラーは無視してください。すぐに修正します。

    とりあえず、データベースを設定しましょう。 verify-userというデータベースを作成し、このデータベースに次のような属性を持つusersテーブルを作成します。

    CREATE TABLE `users` (
     `id` int(11) NOT NULL AUTO_INCREMENT,
     `username` varchar(100) NOT NULL,
     `email` varchar(100) NOT NULL,
     `verified` tinyint(1) NOT NULL DEFAULT '0',
     `token` varchar(255) DEFAULT NULL,
     `password` varchar(255) NOT NULL,
     PRIMARY KEY (`id`)
    )

    トークンと確認済みのフィールドを除いて、異常なことは何もありません。これについては後で説明します。

    次に、実際のサインアップロジックから始めます。私は通常、アプリケーションの論理部分をコントローラーと呼ぶのが好きで、それをここで行います。プロジェクトのルートフォルダーに、controllersというフォルダーを作成し、コントローラー内にauthController.phpというファイルを作成します。

    controllers / authController.php:

    <?php
    session_start();
    $username = "";
    $email = "";
    $errors = [];
    
    $conn = new mysqli('localhost', 'root', '', 'verify-user');
    
    // SIGN UP USER
    if (isset($_POST['signup-btn'])) {
        if (empty($_POST['username'])) {
            $errors['username'] = 'Username required';
        }
        if (empty($_POST['email'])) {
            $errors['email'] = 'Email required';
        }
        if (empty($_POST['password'])) {
            $errors['password'] = 'Password required';
        }
        if (isset($_POST['password']) && $_POST['password'] !== $_POST['passwordConf']) {
            $errors['passwordConf'] = 'The two passwords do not match';
        }
    
        $username = $_POST['username'];
        $email = $_POST['email'];
        $token = bin2hex(random_bytes(50)); // generate unique token
        $password = password_hash($_POST['password'], PASSWORD_DEFAULT); //encrypt password
    
        // Check if email already exists
        $sql = "SELECT * FROM users WHERE email='$email' LIMIT 1";
        $result = mysqli_query($conn, $sql);
        if (mysqli_num_rows($result) > 0) {
            $errors['email'] = "Email already exists";
        }
    
        if (count($errors) === 0) {
            $query = "INSERT INTO users SET username=?, email=?, token=?, password=?";
            $stmt = $conn->prepare($query);
            $stmt->bind_param('ssss', $username, $email, $token, $password);
            $result = $stmt->execute();
    
            if ($result) {
                $user_id = $stmt->insert_id;
                $stmt->close();
    
                // TO DO: send verification email to user
                // sendVerificationEmail($email, $token);
    
                $_SESSION['id'] = $user_id;
                $_SESSION['username'] = $username;
                $_SESSION['email'] = $email;
                $_SESSION['verified'] = false;
                $_SESSION['message'] = 'You are logged in!';
                $_SESSION['type'] = 'alert-success';
                header('location: index.php');
            } else {
                $_SESSION['error_msg'] = "Database error: Could not register user";
            }
        }
    }
    
    // LOGIN
    if (isset($_POST['login-btn'])) {
        if (empty($_POST['username'])) {
            $errors['username'] = 'Username or email required';
        }
        if (empty($_POST['password'])) {
            $errors['password'] = 'Password required';
        }
        $username = $_POST['username'];
        $password = $_POST['password'];
    
        if (count($errors) === 0) {
            $query = "SELECT * FROM users WHERE username=? OR email=? LIMIT 1";
            $stmt = $conn->prepare($query);
            $stmt->bind_param('ss', $username, $password);
    
            if ($stmt->execute()) {
                $result = $stmt->get_result();
                $user = $result->fetch_assoc();
                if (password_verify($password, $user['password'])) { // if password matches
                    $stmt->close();
    
                    $_SESSION['id'] = $user['id'];
                    $_SESSION['username'] = $user['username'];
                    $_SESSION['email'] = $user['email'];
                    $_SESSION['verified'] = $user['verified'];
                    $_SESSION['message'] = 'You are logged in!';
                    $_SESSION['type'] = 'alert-success';
                    header('location: index.php');
                    exit(0);
                } else { // if password does not match
                    $errors['login_fail'] = "Wrong username / password";
                }
            } else {
                $_SESSION['message'] = "Database error. Login failed!";
                $_SESSION['type'] = "alert-danger";
            }
        }
    }
    

    以前のチュートリアルに従った場合、このファイルの内容は新しいものではありません。ただし、初めての方のために、説明を行います。

    まず、ログインしたユーザー情報をセッションに保存する必要があるため、session_start()を使用してセッションを開始します。セッションを開始した後、フォームで使用している$username変数と$email変数、およびフォーム検証エラーを保持する$errors配列を初期化します。

    次に、データベースに接続します。次の2つのifステートメントは、それぞれ、ユーザーがサインアップボタンまたはログインボタンをクリックしたときに実行されるコードです。サインアップの場合、すべての必須フィールドが正しく入力されていることを確認してから、ユーザーをデータベースに保存します。また、トークン(一意のランダムな文字列)を生成し、それをuserとともに属性として保存しています。これは、ユーザーの電子メールを確認するために使用されます。詳細は後で説明します。

    authController.phpファイルはサインアップとログインを担当するため、フォームデータが送信される場所であるsignup.phpページとlogin.phpページの最上部に含める必要があります。そのように:

    signup.phpとlogin.php(最上部):

    <?php include 'controllers/authController.php' ?>

    $ errors配列にエラーメッセージがある場合は、フォームに表示する必要があります。これを行うには、サインアップページとログインページの両方のフォームタイトルのすぐ下にあるフォーム内にこのifステートメントを追加します。

    <!-- form title -->
    <h3 class="text-center form-title">Register</h3> <!-- or Login -->
    
    <?php if (count($errors) > 0): ?>
      <div class="alert alert-danger">
        <?php foreach ($errors as $error): ?>
        <li>
          <?php echo $error; ?>
        </li>
        <?php endforeach;?>
      </div>
    <?php endif;?>

    エラーがない場合、スクリプトはユーザーをデータベースに保存します。ユーザーをデータベースに保存した後、すぐにログインします。私たちの場合、ユーザーをログインさせるということは、セッションにユーザーのデータを保存することを意味し、それが私たちが行ったことです。

    この時点で、ユーザーを登録し、ログインすることもできます。ただし、ログインすると、存在しないindex.phpページにリダイレクトされます。すぐに作成します。

    authController.phpでは、ユーザーがログインするとすぐに表示されるように、メッセージと型変数をセッションに保存しています。メッセージはメッセージの実際のテキストであり、タイプはメッセージを適切にフォーマットするBootstrapスタイリングクラスです。タイプ値に応じた色。

    このメッセージは、ユーザーがログインした後に表示され、index.phpファイルに表示されます。プロジェクトのルートフォルダにそのファイルを作成しましょう。

    index.php:

    <?php include 'controllers/authController.php'?>
    <?php
    // redirect user to login page if they're not logged in
    if (empty($_SESSION['id'])) {
        header('location: login.php');
    }
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
    
      <!-- Bootstrap CSS -->
      <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0/css/bootstrap.min.css" />
      <link rel="stylesheet" href="main.css">
      <title>User verification system PHP</title>
    </head>
    
    <body>
      <div class="container">
        <div class="row">
          <div class="col-md-4 offset-md-4 home-wrapper">
    
            <!-- Display messages -->
            <?php if (isset($_SESSION['message'])): ?>
            <div class="alert <?php echo $_SESSION['type'] ?>">
              <?php
                echo $_SESSION['message'];
                unset($_SESSION['message']);
                unset($_SESSION['type']);
              ?>
            </div>
            <?php endif;?>
    
            <h4>Welcome, <?php echo $_SESSION['username']; ?></h4>
            <a href="logout.php" style="color: red">Logout</a>
            <?php if (!$_SESSION['verified']): ?>
              <div class="alert alert-warning alert-dismissible fade show" role="alert">
                You need to verify your email address!
                Sign into your email account and click
                on the verification link we just emailed you
                at
                <strong><?php echo $_SESSION['email']; ?></strong>
              </div>
            <?php else: ?>
              <button class="btn btn-lg btn-primary btn-block">I'm verified!!!</button>
            <?php endif;?>
          </div>
        </div>
      </div>
    </body>
    </html>

    このページは、ログインしているユーザーのみがアクセスできるようになっています。そのため、ファイルの上部に、ユーザーがログインしていない場合はログインページにリダイレクトします。ページの中央のどこかにメッセージを表示しています。メッセージを表示した後、ユーザーがページを更新した後もメッセージをページに残したくないため、メッセージとタイプ変数の設定を解除します。

    最後に、ページの中央で、ログインしているユーザーが自分のメールアドレスを確認したかどうかを確認します。ユーザーがログインしたときに、セッションに確認済みの変数を追加したことを思い出してください。ユーザーが確認済みの場合は、「確認済みです!!!」と表示されます。彼らが見るためのボタン。確認されていない場合は、メールアドレスに送信した確認リンクについて通知し、そのリンクをクリックしてメールを確認するように依頼します。

    メールの確認

    authController.phpファイルでは、コメントを使用して、sendVerificationEmail()を呼び出して確認メールをユーザーに送信する場所を示しました。 authController.phpファイルに移動し、関数呼び出しのコメントを解除します。

    // TO DO: send verification email to user
    sendVerificationEmail($email, $token);
    

    この関数を別のファイルで定義し、そのファイルをauthController.php内に含めます。コントローラーフォルダー内に、sendEmails.phpという名前のファイルを作成します。

    このファイルにコードを追加する前に、このプロジェクトでローカルホストからメールを送信するために使用するPHPでメールを送信するための人気のあるライブラリであるPHPSwiftMailerについて少し説明します。

    SwiftMailerは、PHPアプリケーションで電子メールを送信するための人気のある機能豊富なライブラリです。

    Swiftmailerを使用するには、最初にComposerをインストールする必要があります。コンポーザーをインストールしたら、ターミナルまたはコマンドラインを開き、プロジェクトのルートフォルダーに移動し、次のコマンドを実行して、すべてのファイルを含むSwiftMailerライブラリをプロジェクトに追加します。

    composer require "swiftmailer/swiftmailer:^6.0"

    これにより、メールの送信に必要なすべてのコード(クラス)を含むベンダーフォルダがアプリケーションのルートに作成されます。また、アプリケーションのルートに次のようなcomposer.jsonファイルが作成されます。

    {
        "require": {
            "swiftmailer/swiftmailer": "^6.0"
        }
    }
    

    次に、前に作成したsendEmails.phpファイルを開き、関数sendVerificationEmail()を記述します。

    <?php
    require_once './vendor/autoload.php';
    
    // Create the Transport
    $transport = (new Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl'))
        ->setUsername(SENDER_EMAIL)
        ->setPassword(SENDER_PASSWORD);
    
    // Create the Mailer using your created Transport
    $mailer = new Swift_Mailer($transport);
    
    function sendVerificationEmail($userEmail, $token)
    {
        global $mailer;
        $body = '<!DOCTYPE html>
        <html lang="en">
    
        <head>
          <meta charset="UTF-8">
          <title>Test mail</title>
          <style>
            .wrapper {
              padding: 20px;
              color: #444;
              font-size: 1.3em;
            }
            a {
              background: #592f80;
              text-decoration: none;
              padding: 8px 15px;
              border-radius: 5px;
              color: #fff;
            }
          </style>
        </head>
    
        <body>
          <div class="wrapper">
            <p>Thank you for signing up on our site. Please click on the link below to verify your account:.</p>
            <a href="http://localhost/cwa/verify-user/verify_email.php?token=' . $token . '">Verify Email!</a>
          </div>
        </body>
    
        </html>';
    
        // Create a message
        $message = (new Swift_Message('Verify your email'))
            ->setFrom(SENDER_EMAIL)
            ->setTo($userEmail)
            ->setBody($body, 'text/html');
    
        // Send the message
        $result = $mailer->send($message);
    
        if ($result > 0) {
            return true;
        } else {
            return false;
        }
    }
    

    最初のステートメントでは、autoload.phpファイルをこのファイルに入れる必要があります。このautoload.phpファイルには、このファイルで使用するベンダーフォルダー内のSwiftMailerライブラリのすべてのクラスが自動的に含まれます。

    この例ではGmailを使用しています。そのため、SENDER_EMAILとSENDER_PASSWORDを、送信者のメールアドレスとして使用するGmailアドレスとパスワードに置き換えることができます。 (受信者のメールアドレスは、フォームから送信されたものです。)

    通常、誰かにメールを送信するには、メールを作成して送信する前にGmailアカウントにサインインする必要があります。これは、SwiftMailerライブラリが行うのと同じ種類のことです。したがって、受信者($ userEmail)が電子メールを受信すると、送信電子メールとして表示されるのはGmailアドレス(SENDER_EMAIL)です。

    ここで、authController.phpファイルでsendVerificationEmail()関数を呼び出していますが、sendEmails.phpファイル内で関数を定義しました。この関数をファイルで使用できるようにするために、sendEmails.phpファイルをauthController.php内に含めましょう。 authController.phpの上部、session_start()の直前に、次の行を追加します。

    require_once 'sendEmails.php';

    必要なのはこれだけです。紳士(および女性)は、電子メール確認リンクを使用してユーザーに電子メールを送信します。ただし、ローカルホストで作業しており、Gmailはローカルホストで実行されているSwiftMailerからのサインイン試行をブロックします。

    ローカルホストからのメールの送信

    これをローカルホストで実行する場合は、安全性の低いアプリからのログインを受け入れるようにGmailアカウントを構成する必要があります。もちろん、これはGmailアカウントに脆弱性をもたらす可能性がありますが、ローカルホストでこのアプリケーションをテストする必要がある短時間しか実行できません。テスト後、Gmailアカウントの設定を元に戻すことができます。アプリケーションがインターネット上でホストされたら、作業を開始します。ローカルホストを使用しているため、これを実行しているだけです。

    さらに慎重になり、このような目的でのみ別のGmailアカウントを作成することができます。

    そのため、ブラウザでGmailにログインし、https://myaccount.google.com/security#connectedappsにアクセスして、[安全性の低いアプリを許可する]の値を[オン]に変更します。

    ローカルホストでプロジェクトのテストが完了したら、これをオフにすることができます。

    これにより、ユーザーがサインアップすると、確認リンクを含むローカルホストからの電子メールを送信できるようになります。ここで、sendVerificationEmail()メソッドをもう一度見てください。ユーザーに送信する電子メールの本文で、その特定のユーザー用に生成したトークン(トークンは一意)がリンクのパラメーターとして設定されていることがわかります。ユーザーがメール内のリンクをクリックすると、URLにそのトークンが含まれるverify_email.phpというページのアプリケーションに誘導されます。このように:

    <a href="http://localhost/cwa/verify-user/verify_email.php?token=0a150966418fa3a694bcb3ab8fcacd2063a096accc0ee33c3e8c863538ee825c0b52f2e1535d0e1377558c378ba5fc3106eb">Verify Email!</a>
    

    したがって、このトークンをverify_email.phpで次のように取得できます(落ち着いて、このverify_email.phpをすぐに作成します):

    $token = $_GET['token'];

    これで、このトークンを使用して、この特定のトークンを持つユーザーをフェッチできます(トークンは一意であることを忘れないでください)。そのユーザーを取得すると、データベースで検証済み属性をtrueに変更してレコードを更新します。そうすれば、そのユーザーのメールアドレスを確認したと誇らしげに言うことができます。

    プロジェクトのルートフォルダにこのverify_email.phpファイルを作成しましょう:

    verify_email.php:

    <?php
    session_start();
    
    $conn = new mysqli('localhost', 'root', '', 'verify-user');
    
    if (isset($_GET['token'])) {
        $token = $_GET['token'];
        $sql = "SELECT * FROM users WHERE token='$token' LIMIT 1";
        $result = mysqli_query($conn, $sql);
    
        if (mysqli_num_rows($result) > 0) {
            $user = mysqli_fetch_assoc($result);
            $query = "UPDATE users SET verified=1 WHERE token='$token'";
    
            if (mysqli_query($conn, $query)) {
                $_SESSION['id'] = $user['id'];
                $_SESSION['username'] = $user['username'];
                $_SESSION['email'] = $user['email'];
                $_SESSION['verified'] = true;
                $_SESSION['message'] = "Your email address has been verified successfully";
                $_SESSION['type'] = 'alert-success';
                header('location: index.php');
                exit(0);
            }
        } else {
            echo "User not found!";
        }
    } else {
        echo "No token provided!";
    }
    

    検証済みの値の値を1に設定することは、それをtrueに設定することと同じであることに注意してください。これは、MySQLデータベースタイプではブール値がtinyintとして解釈されるためです。

    これで、ユーザーが電子メール内のリンクをクリックしてこのページに移動すると、ユーザーの確認済みステータスがtrueに更新され、ログインしてindex.phpページにリダイレクトされます。インデックスページで、ユーザーを確認した後、ユーザーにメールアドレスを確認するように通知する警告メッセージが表示されなくなり、代わりに「確認済みです!!!」と表示されます。確認済みのユーザーにのみ表示されるボタン。

    最後に、ユーザーがログインした後のindex.phpページに、ユーザーをログアウトすることになっているlogout.phpファイルを指すログアウトリンクがあります。アプリケーションのルートにそのファイルを作成しましょう:

    logout.php:

    <?php
    session_destroy();
    unset($_SESSION['id']);
    unset($_SESSION['username']);
    unset($_SESSION['email']);
    unset($_SESSION['verify']);
    header("location: login.php");
    

    そのため、サインアップ、電子メールの確認、サインインに加えて、ユーザーはログアウトすることもできるようになりました。

    結論

    これで、ユーザー登録と電子メール検証について説明します。コメント、質問、励ましの言葉があれば、下のコメント欄に残してください。そして、この投稿を共有することを忘れないでください。または、役立つと思われる場合は、このサイトを友達に勧めてください。それは私を大いに励まします!

    良い一日を!


    1. Ubuntu14.04にMySQLをインストールします

    2. 複数の列を持つ単一の固定テーブルと柔軟な抽象テーブル

    3. Postgresを使用して複数のスキーマからすべてのレコードを選択(取得)します

    4. MySQL CASEはどのように機能しますか?