6-2:ユーザー管理機能を作成する1

2019/05/31

概要

管理画面で会員の管理を行います。
会員一覧を表示して会員の名前でデータを検索できる機能を実装します。

フォルダ階層

完成イメージ

ダッシュボード

会員一覧

事前準備

ユーザーの登録

ダミーのユーザーデータを複数件登録しておきます。
手作業で登録するのでもいいですが、面倒な人は下記を実行して、登録してください。

dummy.sqlをデスクトップに作成

下記のコードをコピーしてdummy.sqlという名前でデスクトップに保存してください。
~/Desktop/dummy.sql

INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('大垣 和也','user1@user.com','testtest','7827139 高知県宇野市東区笹田町伊藤4-1-6 ハイツ笹田105号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('佐々木 桃子','user2@user.com','testtest','9873978 広島県坂本市中央区渡辺町井上5-2-4 ハイツ井上105号',1,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('村山 裕太','user3@user.com','testtest','7835703 青森県野村市北区村山町鈴木8-1-10 コーポ中村106号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('笹田 直子','user4@user.com','testtest','5076538 三重県西之園市西区渡辺町青田4-10-2',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('三宅 亮介','user5@user.com','testtest','9525225 佐賀県桐山市北区加納町近藤8-2-10',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('松本 七夏','user6@user.com','testtest','9533278 神奈川県野村市東区廣川町工藤4-6-1',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('田辺 翔太','user7@user.com','testtest','7823385 兵庫県坂本市中央区渚町井高3-2-7 ハイツ松本101号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('松本 あすか','user8@user.com','testtest','3043211 北海道加藤市北区桐山町田中8-4-5',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('小泉 篤司','user9@user.com','testtest','4735084 福岡県原田市西区吉田町小泉3-3-5 コーポ桐山105号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('山本 幹','user10@user.com','testtest','1137323 島根県加納市中央区藤本町山岸3-3-9',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉田 浩','user11@user.com','testtest','1066295 栃木県中津川市南区佐々木町村山3-8-6 ハイツ山口109号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('笹田 陽一','user12@user.com','testtest','7964925 宮城県小林市中央区青田町坂本9-8-1',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉田 智也','user13@user.com','testtest','8265163 静岡県山田市西区小泉町青田3-7-10',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('喜嶋 千代','user14@user.com','testtest','6345691 愛媛県佐藤市西区高橋町中島8-9-7 コーポ野村107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('中村 真綾','user15@user.com','testtest','4891842 山梨県江古田市西区三宅町渡辺7-7-3',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('青山 亮介','user16@user.com','testtest','2151781 愛知県江古田市中央区工藤町浜田9-9-9 ハイツ加納106号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('渡辺 直人','user17@user.com','testtest','7098770 大阪府小林市北区伊藤町中島6-3-1 ハイツ笹田110号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('加納 直樹','user18@user.com','testtest','4202410 島根県加納市北区山口町吉田5-6-2 ハイツ工藤110号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('高橋 加奈','user19@user.com','testtest','4491730 奈良県吉田市南区井高町近藤8-1-2',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('加納 充','user20@user.com','testtest','7751135 兵庫県渚市西区井高町津田6-8-10',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('山本 稔','user21@user.com','testtest','2645875 和歌山県佐々木市北区渡辺町坂本5-6-2 ハイツ中島107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('杉山 翔太','user22@user.com','testtest','4623820 大分県加藤市北区加藤町宇野2-3-10 ハイツ佐々木106号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('大垣 七夏','user23@user.com','testtest','1693727 宮城県青山市南区石田町原田4-4-10',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('石田 稔','user24@user.com','testtest','8387474 沖縄県江古田市中央区井高町藤本1-2-5 コーポ中島105号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('西之園 洋介','user25@user.com','testtest','1679599 岐阜県大垣市中央区笹田町田辺8-1-2',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('大垣 亮介','user26@user.com','testtest','5303497 福島県渡辺市東区井高町松本8-7-8',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉田 舞','user27@user.com','testtest','5316889 千葉県佐々木市北区山口町加納6-7-3 ハイツ宮沢103号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('近藤 英樹','user28@user.com','testtest','5106013 奈良県石田市東区笹田町杉山8-10-9 ハイツ大垣101号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉本 修平','user29@user.com','testtest','7953938 大分県西之園市東区西之園町石田10-5-9 ハイツ若松107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('山口 翔太','user30@user.com','testtest','1953150 愛媛県喜嶋市西区井高町山口5-10-10',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('山口 あすか','user31@user.com','testtest','2833057 北海道中島市南区浜田町近藤3-4-5 ハイツ山口110号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('佐藤 あすか','user32@user.com','testtest','3413782 愛媛県坂本市南区渚町三宅4-7-5 ハイツ佐々木108号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉本 涼平','user33@user.com','testtest','4074518 神奈川県廣川市西区鈴木町津田9-8-4',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('田辺 翼','user34@user.com','testtest','2604791 和歌山県中津川市北区大垣町吉田5-7-4',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('田辺 淳','user35@user.com','testtest','4444406 福井県加藤市中央区高橋町井上2-6-9',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('井上 拓真','user36@user.com','testtest','2846958 島根県山田市中央区田中町山岸8-7-1 ハイツ木村102号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('三宅 聡太郎','user37@user.com','testtest','9164215 静岡県山本市中央区山本町山岸7-3-1 コーポ渡辺110号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('藤本 篤司','user38@user.com','testtest','3422096 奈良県田辺市西区桐山町中津川6-1-9 ハイツ井上110号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('井上 翔太','user39@user.com','testtest','1234832 栃木県鈴木市北区山田町青田8-1-5',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('吉田 聡太郎','user40@user.com','testtest','6976786 茨城県坂本市東区津田町高橋8-5-3 ハイツ工藤102号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('鈴木 英樹','user41@user.com','testtest','4571939 香川県吉本市北区坂本町田中8-6-1 コーポ大垣107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('青山 加奈','user42@user.com','testtest','6198551 福井県青山市中央区田中町廣川7-7-3 ハイツ杉山107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('高橋 稔','user43@user.com','testtest','6318612 島根県松本市東区浜田町井上1-9-8 ハイツ笹田107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('斉藤 裕樹','user44@user.com','testtest','4691784 宮崎県野村市南区木村町吉田7-8-8',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('村山 修平','user45@user.com','testtest','9103653 福島県吉本市中央区田辺町宇野9-4-3 コーポ若松107号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('山岸 翼','user46@user.com','testtest','4681386 愛媛県野村市南区渚町山田4-1-8 コーポ田辺103号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('木村 真綾','user47@user.com','testtest','7568362 福岡県山本市南区田中町藤本8-7-9',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('笹田 零','user48@user.com','testtest','1999068 栃木県小林市西区木村町田中10-9-6 コーポ近藤104号',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('渡辺 くみ子','user49@user.com','testtest','4731176 宮崎県西之園市西区江古田町村山10-4-1',0,now(),now());
INSERT INTO users(name,email,password,address,dm,created_at,updated_at) values('野村 零','user50@user.com','testtest','8666541 愛知県佐藤市西区田辺町中島10-4-10',0,now(),now());

consoleでファイルを実行

コンソールを開いて実行します。
mysqlにログインするときと同様にパスワードを入力してエンターを押します。
console

$ mysql -u root -p corporate_db < ~/Desktop/dummy.sql
Enter password:
$

コンソールが返ってきたら、mysqlにログインして確認します。
console

mysql> use corporate_db
Database changed
mysql> select * from users;

件数が51件(一つ前の章で手動で登録した1件を含む)のデータが入っていることが確認できればOKです。
登録したユーザーはuser2@user.comの佐々木さんだけメール配信希望するに設定しています。

全体の手順

手順は以下の通りです。

  1. 管理画面作成
  2. 検索機能実装

管理画面作成

会員管理メニュー追加

ダッシュボードに会員管理メニューを追加します。
アイコンは記事管理と同様にfontawesomeを利用しています。
admin/dashboard.php

    <div class="container">
        <div class="wrapper-title">
            <h3>ダッシュボード</h3>
        </div>
        <div class="boxs">
            <a href="news.php" class="box">
                <i class="far fa-newspaper icon"></i>
                <p>記事管理</p>
            </a>
+           <a href="users.php" class="box">
+               <i class="fas fa-users icon"></i>
+               <p>会員管理</p>
+           </a>

        </div>
    </div>

admin/dashboard.phpにアクセスして確認します。

会員一覧作成

adminフォルダにusers.phpを作成します。

ログインチェック

管理画面では必須のログインチェックを入れます。
admin/users.php

<?php

    //sessionでログイン制限
    session_start();

    if($_SESSION['admin_login'] == false){
        header("Location:./index.html");
        exit;
    }
?>

DBからデータ取り出し

DBに接続してusersのデータを取得します。
admin/users.php

    <?php

        //sessionでログイン制限
        session_start();

        if($_SESSION['admin_login'] == false){
            header("Location:./index.html");
            exit;
        }

+       //DB接続
+       try{
+           $dbh = new PDO("mysql:host=localhost;dbname=corporate_db","root","root");
+       }catch(PDOException $e){
+           var_dump($e->getMessage());
+           exit;
+       }

+       $stmt = $dbh->prepare("SELECT * FROM users");
+       $stmt->execute();
+       $users = $stmt->fetchAll(PDO::FETCH_ASSOC);
    ?>

取得したデータの表示

phpの下にhtmlでテーブルを作成して取得したデータを表示します。
※表示上、編集ボタンと削除ボタンを付けていますが、ここでは実装していません。第4章のNews CRUD機能の実装を参考に実装してみてください。
admin/users.php

?>
<!DOCTYPE html>
<html>

<head>
    <!-- Global site tag (gtag.js) - Google Analytics -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=UA-13xxxxxxxxx"></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag() { dataLayer.push(arguments); }
        gtag('js', new Date());

        gtag('config', 'UA-13xxxxxxxxx');
    </script>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>会員管理</title>

    <link rel="icon" href="favicon.ico">
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
        integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">

    <!-- css -->
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <header>
        <div class="container">
            <div class="header-logo">
                <h1><a href="dashboard.php">管理画面</a></h1>
            </div>

            <nav class="menu-right menu">
                <a href="index.html">ログアウト</a>
            </nav>
        </div>
    </header>
    <main>
        <div class="wrapper">
            <div class="container">
                <div class="wrapper-title">
                    <h3>会員管理</h3>
                </div>
                <div class="list">
                    <table>
                        <thead>
                            <tr>
                                <th>id</th>
                                <th>名前</th>
                                <th>メールアドレス</th>
                                <th>DM配信</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php foreach($users as $user): ?>
                            <tr>
                                <td><?php echo $user['id']; ?></td>
                                <td><?php echo $user['name']; ?></td>
                                <td><?php echo $user['email']; ?></td>
                                <td><?php echo $user['dm']; ?></td>
                                <td>
                                    <button type="button" class="btn btn-green">編集</button>
                                    <button type="button" class="btn btn-red">削除</button>
                                </td>
                            </tr>
                            <?php endforeach; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </main>
    <footer>
        <div class="container">
            <p>Copyright @ 2018 SQUARE, inc</p>
        </div>
    </footer>
</body>

</html>

ブラウザで確認します。
登録されているユーザーのデータがずら~っと表示されればOKです。

DM配信希望が0/1で表示されているので、0は「-」1は「受信する」と表示するようにします。
admin/users.php

    <tbody>
        <?php foreach($users as $user): ?>
        <tr>
            <td><?php echo $user['id']; ?></td>
            <td><?php echo $user['name']; ?></td>
            <td><?php echo $user['email']; ?></td>
-           <td><?php echo $user['dm']; ?></td>
+           <td>
+               <?php if($user['dm']=='0'): ?>
+               -
+               <?php else: ?>
+               受信する
+               <?php endif; ?>
+           </td>
            <td>
                <button type="button" class="btn btn-green">編集</button>
                <button type="button" class="btn btn-red">削除</button>
            </td>
        </tr>
        <?php endforeach; ?>
    </tbody>

確認します。
1だった人が「受信する」、0だった人は「-」が表示されていればOKです。

検索機能実装

名前でデータを検索する機能を実装します。

検索窓の追加

検索フォームを作成します。
データのmethodはGET、送り先は自分自身(users.php)を設定します。
admin/users.php

    <div class="wrapper-title">
        <h3>会員管理</h3>
    </div>
+   <form class="serch" action="users.php" method="GET">
+       <input type="text" name="name" placeholder="名前検索">
+       <button type="submit" class="btn btn-blue">検索</button>
+   </form>

    <div class="list">
        <table>
            <thead>
                <tr>
                    <th>id</th>
                    <th>名前</th>
                    <th>メールアドレス</th>
                    <th>DM配信</th>
                    <th>操作</th>
                </tr>
            </thead>

CSSを編集します
admin/styles.css

/* users.php */
.serch {
    text-align: right;
    width: 100%;
}
.serch input {
    width: 30%;
    padding: 4px;
}

.serch button {
    padding: 5px 10px;
}

admin/users.phpを更新して確認します。

検索窓ができました。
※cssはブラウザがキャッシュしていることが多く、すぐにスタイルシートの変更が反映されないことが多いです。
cssが反映されていないなと思ったら、キャッシュをクリアしてから試すか、他のブラウザで確認する、またはChromeの場合、ゲストウィンドで開いて確認するといいです。

検索実行

formから自分自身に送ったデータを受け取ります。
admin/users.php

    <?php

        //sessionでログイン制限
        session_start();

        if($_SESSION['admin_login'] == false){
            header("Location:./index.html");
            exit;
        }

+       $name = isset($_GET['name'])? htmlspecialchars($_GET['name'], ENT_QUOTES, 'utf-8'):'';

        //DB接続
        try{
            $dbh = new PDO("mysql:host=localhost;dbname=coporate_db","root","root");
        }catch(PDOException $e){
            var_dump($e->getMessage());
            exit;
        }

初回アクセスや$nameが入っていない状態は、全件表示なので、今までのSQLを利用します。
$nameが送られてきた場合、SQLのSELECT文にWHERE句を入れて検索できるようにします。
if文を使って、$nameの値の有無判断をしてSELECT文を出し分けします。
admin/users.php

        $name = isset($_GET['name'])? htmlspecialchars($_GET['name'], ENT_QUOTES, 'utf-8'):'';

        //DB接続
        try{
            $dbh = new PDO("mysql:host=localhost;dbname=coporate_db","root","root");
        }catch(PDOException $e){
            var_dump($e->getMessage());
            exit;
        }

+       if($name == '')
+       {
+           $stmt = $dbh->prepare("SELECT * FROM users");

+       }else{
+           $stmt = $dbh->prepare("SELECT * FROM users WHERE name=:name");
+           $stmt->bindParam(":name",$name);     
+       }

-       $stmt = $dbh->prepare("SELECT * FROM users");
        $stmt->execute();
        $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

    ?>

確認します。
検索窓に、会員の名前を一つ入力して検索してみてください。
該当の会員が表示されればOKです。

like検索

検索条件で、名前に「田」が付く人を検索したい。という場合、今の状態だと「田」で検索してもヒットしません。
「田」が付く人を検索できるようにするためにはlike検索にします。
SELECT文とバインドに少し変更を加えます。
admin/users.php

    if($name == '')
    {
        $stmt = $dbh->prepare("SELECT * FROM users");

    }else{
-       $stmt = $dbh->prepare("SELECT * FROM users WHERE name=:name");
-       $stmt->bindParam(":name",$name);  
+       $stmt = $dbh->prepare("SELECT * FROM users WHERE name like :name");
+       $stmt->bindValue(":name",'%'.$name.'%');
    }

これで部分検索に対応しました。
検索窓に「田」を入力して検索してください。
「田」が付くユーザーが全て表示されればOKです。

これで一覧と検索が実装できました。

コード

https://github.com/bluecode-io/web-basic/tree/basic6-2