PHPとSQLiteでTwitterのようなアプリをつくります。
データベースの設計
つくるものですが、ユーザー登録しなくても投稿されたものを閲覧することはできるようにします。ユーザー登録をした人であれば、短文を投稿する、自分の投稿を削除する、自分または他人の投稿にいいねする、リツイートする、返信する、このようなことができるものにしようと考えています。
そこでデータベースは
テーブル user
id(プライマリキー)
user_id
user_name
password
prof_text(プロフィールの文章)
prof_image_path(プロフィール画像のパス)
favorites (どの投稿にいいねしたか? articleのidの配列)
テーブル article
id(プライマリキー)
user_id (投稿したユーザーのID)
text
create_at
update_at(更新時刻:投稿を変更する機能を追加する予定はないのでいまのところ必要ないが、あとになって気が変わるかもしれないので)
favo_count(いいねの数)
rt_count(リツイートの数)
rt_target(投稿がリツイートの場合、対象の投稿IDは?)
reply_target(投稿が返信の場合、対象の投稿IDは?)
とすることにします。
またurlはトップページを / とし、article_idを投稿のIDとした場合、
ユーザー登録のページ /signup.php
ログインのページ /login-form.php
ログアウトするためのページ /logout.php
各ユーザーの投稿一覧 /?user=user_id
RT投稿用のページ /?rt=article_id
投稿とそれへの返信の一覧 /?article=article_id
投稿削除確認のページ /?delete=article_id
とします。フォームに入力されたデータをどこへPOSTするかは後述します。
ユーザー登録の実装
ユーザーが新規登録をするためのページを作成します。
PHPはなにもかいていないので拡張子を.phpにする必要はないのですが、事情があって拡張子を.phpにしています。またIDがurlにも使われるのでIDに使用できる文字を半角英数に制限しています。
signup.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
<?php // あとでここに書くことがあるので・・・ ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>新規会員登録</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> h1 { font-size: 150%; } a { color: #00f; font-weight: bold; } a:hover { color: #f00; } #main { max-width : 800px; } </style> </head> <body> <div id = "main"> <h1>新規会員登録</h1> <form action="register.php" method="post"> <div> <label> 名前: <input type="text" name="user_name" required> </label> </div> <div> <label> 希望するID: <input type="text" name="user_id" pattern="^[a-zA-Z0-9]+$" placeholder="半角英数字のみ" required> </label> </div> <div> <label> パスワード: <input type="password" name="password" required> </label> </div> <input type="submit" value="新規登録"> </form> <p>パスワードは暗号化された状態でサーバー上に保存されます。たとえば "pass"であれば <?php echo password_hash("pass", PASSWORD_DEFAULT); ?> に変換されます。パスワードを忘れたので教えてくれといわれても対応できません。また他のサービスで使用しているパスワードを使い回すのは危険なのでやめましょう。</p> <p><a href="./login-form.php">すでに登録済みの方はこちら</a></p> <p><a href="./">トップページへ戻る</a></p><!-- まだindex.phpは作成していないのでページ遷移できないが・・・ --> </div> </body> </html> |
フォームに必要なことを入力して登録ボタンをクリックしたらデータベースにユーザー情報を登録します。この処理はregister.phpでおこないますが、よく使う関数はfunctions.phpで定義して他のファイルからでも呼び出せるようにします。
functions.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?php function GetDbPath(){ return "./db.sqlite3"; } function CreateUserTable($db){ $text = 'CREATE TABLE if not exists USER_TABLE ('; $text .= 'id integer primary key autoincrement,'; $text .= 'user_id text,'; $text .= 'user_name text,'; $text .= 'password text,'; $text .= 'prof_text text,'; $text .= 'prof_image_path text,'; $text .= 'favorites text)'; $sql = $text; $db->query($sql); } ?> |
register.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<?php require_once('functions.php'); if (!isset($_POST['user_id']) || !isset($_POST['user_name']) || !isset($_POST['password'])) { echo '不正なリクエスト'; exit; } //フォームからの値をそれぞれ変数に代入 $user_id = $_POST['user_id']; $user_name = $_POST['user_name']; $password = password_hash($_POST['password'], PASSWORD_DEFAULT); $db_path = GetDbPath(); $db = new PDO("sqlite:{$db_path}"); CreateUserTable($db); //フォームに入力されたmailがすでに登録されていないかチェック $sql = "SELECT * FROM USER_TABLE WHERE user_id = :user_id"; $stmt = $db->prepare($sql); $stmt->bindValue(':user_id', $user_id); $stmt->execute(); $member = $stmt->fetch(); if (is_array($member) == true && $member['user_id'] === $user_id) { $msg = 'すでに使用されているIDです。別のIDを指定してください。'; $link = '<a href="signup.php">戻る</a>'; } else { //登録されていなければinsert $sql = "INSERT INTO USER_TABLE (user_id, user_name, password) VALUES (:user_id, :user_name, :password)"; $stmt = $db->prepare($sql); $stmt->bindValue(':user_id', $user_id); $stmt->bindValue(':user_name', $user_name); $stmt->bindValue(':password', $password); $stmt->execute(); $msg = '会員登録が完了しました'; $link = '<a href="login-form.php">ログインページ</a>'; } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>新規会員登録</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> h1 { font-size: 150%; } </style> </head> <body> <h1><?php echo $msg; ?></h1> <?php echo $link; ?> </body> </html> |
ためしに登録の実験をしてみると同じユーザーIDで登録しようとしたときに’すでに使用されているIDです。別のIDを指定してください。’というエラーメッセージが表示されます。またユーザーIDに使用できない文字を入力した場合、なにも入力しないで登録ボタンをクリックしたときもその旨を伝えるメッセージが表示されます。
ログイン処理の実装
login-form.phpという名前でファイルを作成して、以下のように書きます。
login-form.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
<?php // あとでここに書くことがあるので・・・ ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ログインページ</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> h1 { font-size: 150%; } a { color: #00f; font-weight: bold; } a:hover { color: #f00; } </style> </head> <body> <h1>ログインページ</h1> <form action="login.php" method="post"> <div> <label> ID: <input type="text" name="user_id" required> </label> </div> <div> <label> パスワード: <input type="password" name="password" required> </label> </div> <input type="submit" value="ログイン"> </form> <p>アカウントを作成していない方は <a href="./signup.php">こちら</a></p> <p><a href="./">トップページへ戻る</a></p> </body> </html> |
ログインボタンをクリックしたらlogin.phpへポストされます。
$_POST[‘user_id’]や$_POST[‘password’]が渡されていない場合は不正なリクエストなので処理をおこないません。$_POST[‘user_id’]と$_POST[‘password’]が取得できたら$_POST[‘user_id’]がデータベース内に存在するか調べます。存在する場合はパスワードのハッシュが一致するかを調べます。両方ともOKならログイン成功です。そうでない場合はユーザーIDかパスワードが間違っているのでログインできない旨を表示します。
ログインに成功したら DBのユーザー情報をセッションに保存して、そのユーザーの投稿一覧が表示されるページにリダイレクトさせます。ただしいまの段階では該当するページをつくっていないのでエラーになります(続きをお待ちください)。
login.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
<?php require_once('functions.php'); if (!isset($_POST['user_id']) || !isset($_POST['password'])){ echo '不正なリクエストです'; exit; } $user_id = $_POST['user_id']; $password = $_POST['password']; session_start(); $db_path = GetDbPath(); $db = new PDO("sqlite:{$db_path}"); $sql = "SELECT * FROM USER_TABLE WHERE user_id = :user_id"; $stmt = $db->prepare($sql); $stmt->bindValue(':user_id', $user_id); $stmt->execute(); $member = $stmt->fetch(); // データベース内にuser_idが存在する場合、指定したハッシュがパスワードにマッチしているかチェック if (is_array($member) && password_verify($password, $member['password'])) { // DBのユーザー情報をセッションに保存 $_SESSION['user_id'] = $member['user_id']; header("Location: ./?user=".$member['user_id']); exit; } else { $msg = 'アカウント名もしくはパスワードが間違っています。'; $link = '<a href="login-form.php">戻る</a>'; } ?> <!-- ログイン成功したらリダイレクトするので以下の部分はログイン失敗のときだけ表示される --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ログイン失敗</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> h1 { font-size: 150%; } </style> </head> <body> <h1><?php echo $msg; ?></h1> <?php echo $link; ?> </body> </html> |
ログイン後とログアウトの処理
ログインした状態でsignup.phpやlogin-form.phpにアクセスしてしまうとユーザー登録やログインのページが表示されてしまいます。これはよくないのでログインした状態でsignup.phpやlogin-form.phpにアクセスした場合はログイン後にリダイレクトされるページにリダイレクトさせます。
signup.phpとlogin-form.phpの冒頭に以下を追加します。これでログイン状態のときにアクセスすると自動的にindex.phpにリダイレクトされます。
1 2 3 4 5 6 7 8 9 |
<?php session_start(); if (isset($_SESSION['user_id'])){ header("Location: ./?user=".$_SESSION['user_id']); exit; } ?> |
ログアウトするためのページを作ります。
logout.php
1 2 3 4 5 6 7 8 |
<?php session_start(); $_SESSION = array(); // セッションの中身をすべて削除 session_destroy(); // セッションを破壊 ?> <p>ログアウトしました。</p> <a href="login-form.php">ログインへ</a> |
次回はメインのページを作成します。