暇人の寝室
技術系の記事や読書・アニメの感想などを投稿します。
プログラミング
前回ブログを作成するにあたって環境構築を行った。今回はルーティングと見た目部分であるビューを作成する。
ルーティングを行うためにpublic/index.phpを作成する。public/index.phpは下記の通り。
<?php
$PATH = $_SERVER['PATH_INFO'];
if(empty($PATH)){
$PATH = $_SERVER['REQUEST_URI'];
$PATH = preg_replace('/^\//','',$PATH);
}
if(empty($PATH)){
include("../views/index.php");
}else{
include("../views/${PATH}.php");
}
PATH_INFOの値に応じてビューを読み込む簡単仕様。PATH_INFOが空のときにはREQUEST_URIをパースする。
ブログ一覧を表示するindex.phpは下記の通り。
<?php
include("../lib/login.php");
session_start();
header('Content-Type: text/html; charset=UTF-8');
?>
<header>
<link href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" rel="stylesheet"/>
</header>
<body>
<div class="container">
<h2 class="subtitle">ブログ一覧画面</h2>
<?php
if(isset($_SESSION['username'])){
?>
<nav class="level">
<div class="level-left">
<div class="level-item">
<a class="button is-small" href="/create">新規投稿</a>
</div>
</div>
<div class="level-right">
<div class="level-item">
<form action="logout" method="post">
<input type="hidden" name="token" value="<?= h(generate_token())?>"/>
<button class="button is-small" type="submit">ログアウト</button>
</form>
</div>
</div>
</nav>
<?php
}else{
?>
<a class="button is-small" href="/login">ログイン</a>
<?php
}
?>
<?php
include('../models/Blog.php');
$blog = new Blog;
$posts = $blog->read();
foreach($posts as $post){
if(!isset($_SESSION['username']) && boolval($post['private'])){
continue;
}
?>
<form action="delete" method="post">
<input type="hidden" name="id" value="<?php echo($post['id'])?>"/>
<input type="hidden" name="title" value="<?php echo($post['title'])?>"/>
<input type="hidden" name="content" value="<?php echo($post['content'])?>"/>
<div class="box">
<h2><?php echo($post['title']) ?></h2>
<div><?= boolval($post['private']) ? "非公開" : "公開" ?></div>
<article>
<?php echo($post['content']) ?>
</article>
<?php
if(isset($_SESSION['username'])){
?>
<button class="button is-danger is-small" type='submit'>投稿を削除する</button>
<?php
}
?>
</div>
</form>
<?php } ?>
</div>
</body>
上段は後ほど作成する認証処理のための記述である。
データを読み込む部分について。
<?php
include('../models/Blog.php');
$blog = new Blog;
$posts = $blog->read();
foreach($posts as $post){
if(!isset($_SESSION['username']) && boolval($post['private'])){
continue;
}
?>
DBからデータを読み込む部分は後ほど作成するモデルに任せるので、ビューはモデルをインスタンス化してメソッドを読み出して、foreachで表示するのみ。ただし、認証済みユーザに対してのみ非公開の記事を表示するので、セッションが無効かつprivateフラグが有効な記事は表示しないように記述する。
続いてブログ投稿に関するcreate.phpは下記の通り。
<?php
include("../lib/login.php");
required_logined_session();
if(!empty($_POST["title"]) && !empty($_POST["content"])){
$value = [
"title" => $_POST["title"],
"content" => $_POST["content"],
"private" => isset($_POST["private"]) ? $_POST['private'] : "0",
];
include("../models/Blog.php");
$blog = new Blog;
$blog->create($value);
header('Location: /',true,301);
exit;
}
?>
<header>
<link href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" rel="stylesheet"/>
</header>
<body>
<div class="container">
<h2 class="subtitle">新規投稿画面</h2>
<form action="" method="post">
<div class="field">
<div class="control">
<label class="label">タイトル</label>
<input class="input" name="title" type="text"/>
</div>
</div>
<div class="field">
<div class="control">
<label class="label">本文</label>
<textarea class="textarea" name="content"></textarea>
</div>
</div>
<div>
<label class="checkbox">
<input type="checkbox" name="private" value="1"/>
非公開にする
</label>
</div>
<button class="button" type="submit">投稿する</button>
</form>
</div>
</body>
ブログ投稿部分は下記の通り。
if(!empty($_POST["title"]) && !empty($_POST["content"])){
$value = [
"title" => $_POST["title"],
"content" => $_POST["content"],
"private" => isset($_POST["private"]) ? $_POST['private'] : "0",
];
include("../models/Blog.php");
$blog = new Blog;
$blog->create($value);
header('Location: /',true,301);
exit;
}
$_POSTに入っている値をBlogモデルに渡して、/にリダイレクトする。
delete.phpは下記の通り。
<?php
include('../models/Blog.php');
$blog = new Blog;
$blog->delete($_POST['id']);
header('Location: /',true,301);
register.phpは下記の通り。
<?php
if(!empty($_POST["username"]) && !empty($_POST["password"])){
$value = [
"username" => $_POST["username"],
"password" => $_POST["password"],
];
include("../models/User.php");
$blog = new User;
$blog->create($value);
header('Location: /',true,301);
exit;
}
?>
<header>
<link href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" rel="stylesheet"/>
</header>
<body>
<div class="container">
<h2 class="subtitle">ユーザー登録画面</h2>
<form action="" method="post">
<div class="field">
<div class="control">
<label class="label">ユーザ名</label>
<input class="input" name="username" type="text"/>
</div>
</div>
<div class="field">
<div class="control">
<label class="label">パスワード</label>
<input class="input" name="password" type="password"/>
</div>
</div>
<div class="field">
<div class="control">
<label class="label">パスワード(確認用)</label>
<input class="input" type="password"/>
</div>
</div>
<button class="button" type="submit">作成</button>
</form>
</div>
</body>
入力をユーザモデルに渡してリダイレクトする。
login.phpは下記の通り。
<?php
include("../lib/login.php");
include("../models/User.php");
required_unlogined_session();
$user = new User;
$username = filter_input(INPUT_POST,'username');
$password = filter_input(INPUT_POST,'password');
if($_SERVER['REQUEST_METHOD']==='POST'){
if(
$user->validate_password($username,$password)
){
session_regenerate_id(true);
$_SESSION['username'] = $username;
header('Location: /');
exit;
}
http_response_code(403);
}
header('Content-Type: text/html; charset=UTF-8');
?>
<header>
<link href="https://cdn.jsdelivr.net/npm/bulma@0.8.0/css/bulma.min.css" rel="stylesheet"/>
</header>
<body>
<div class="container">
<h2 class="subtitle">ログイン画面</h2>
<form action="" method="post">
<div class="field">
<div class="control">
<label class="label">ユーザ名</label>
<input class="input" name="username" type="text"/>
</div>
</div>
<div class="field">
<div class="control">
<label class="label">パスワード</label>
<input class="input" name="password" type="password"/>
</div>
</div>
<input type="hidden" name="token" value="<?= h(generate_token())?>"/>
<button class="button" type="submit">ログイン</button>
</form>
</div>
</body>
ユーザモデルのvaidate_password()でパスワードチェックをし、通ったらセッションIDをregenerateする。
logout.phpは下記の通り。
<?php
include('../lib/login.php');
required_logined_session();
if(!validate_token(filter_input(INPUT_POST,'token'))){
header('Content-Type: text/plain; charset=UTF-8', true, 400);
exit('トークンが無効です。');
}
setcookie(session_name(),'',1);
session_destroy();
header('Location: /');
validate_token()でトークンをチェックし、無効なトークンの場合は400を返す。
有効なトークンの場合はcookieを削除し、セッションをdestroyしてルートを返す。
今回はルーティングとビューを作成した。この辺りからゴリゴリソースを書いていくことになるので楽しい。次回はモデルやDB周りを実装して行こうと思う。