目標
今回やること
- Webアプリケーションを作成する
タスクばらし
- 必須知識
- 設計・テーブル作成
- [登録ページ] HTMLで表示する
- [登録ページ] 読書ログを登録する
- [登録ページ] CSSでスタイルを整える
- [トップページ] HTMLで表示する
- [トップページ] 読書ログの一覧を表示する
- [トップページ] CSSでスタイルを整える
必須知識
目的
- PHPで開発するにあたって必須な知識を学ぶ
開発の基本順序
- 設計→テーブル作成→HTML→ロジック処理→CSS
Composer
-
現状の課題
機密データがソースコードにベタ書き
ソースコードを誰かに見られたら機密データが漏洩し、データが流出する -
解決策
ライブラリを使用して、機密データを別途管理できる仕組みを入れよう -
ライブラリ
使いたい部品が入っている道具箱
特定の機能を提供するコードをひとまとめにしたもの
ex)機密データ管理ライブラリ、ログ管理ライブラリ
- PHPでライブラリを導入したい時はComposerを使うと便利。
ComposerはPHPの依存管理ツール
何も使わないと、
1, 一つのライブラリを使うのに他のライブラリをいちいちインストールしてこないといけない
2, チーム開発時に人によって使用しているライブラリのバージョンがバラバラ。それが起因でエラーになる。
Composerを使うと、
1, プロジェクトが使用しているライブラリとそのバージョンを統一できる
2, ライブラリが依存しているライブラリもセットでインストールできる
3, プロジェクトごとにライブラリを管理できる
composer.jsonとcomposer.lockファイルで依存するライブラリを定義する
-
composer.json
プロジェクトで使用するライブラリを一覧にしたもの -
composer.lock
実際にどのライブラリのどのバージョンをダウンロードしたかをひとまとめにしたもの
1, coposer installを実行すると、インストールしたライブラリとバージョン情報が書き出される
2, composer.lockがある状態でcomposer installすると、composer.lockに記されたバージョンのライブラリがインストールされる
よって、チーム内で同じバージョンのライブラリを使える
コマンド流れ
- init
対話形式でcomposer.jsonを作成する(プロジェクトの初期に一度実行)
composer init
- require
新しいライブラリを追加する
composer.jsonにライブラリが、 composer.lockに実際にインストールしたものが記載される
composer require <ライブラリ名>
- install
composer.jsonもしくはcomposer.lockに従ってライブラリをインストールする
チーム開発時に使用。共通のバージョンのライブラリを使うことができる
composer install
- remove
ライブラリを取り除く
composer remove <ライブラリ名>
環境変数
機密データをソースコードから分離するのに環境変数を使う
-
通常の変数
PHPのコードの中で定義し、実行したプロセス内でのみ使用できる -
環境変数
PHPが動いてるOSに依存し、PHPアプリケーションに渡す仕組み(OSに格納される変数)
PHPコードに直接記述しないので、コードを見ても変数の中身がバレず、また環境によって切り替えられる
環境変数を使うのに、.envファイルを使うと簡単に設定できて便利(phpdotenv)
現状
- ソースコードにベタ書き
$link = mysqli_connect('db', 'book_log', 'pass', 'book_log');
env使うと
- ソースコードから分離できる。環境によっても使い分けられる
envファイル:重要な設定データを定義する→環境変数として定義される
DB_HOST=db - プログラムのファイル:.envファイルに定義された値を取得できる
$dbHost = getenv('DB_HOST'); //$_ENV['DB_'HOST]でも取得できる
$link = mysqli_connect($dbHost, ..., ..., ,,,);
Webページが表示される仕組み
Webページが表示される流れを銀行に例えると、
- お客さん
ブラウザ - 窓口
apache - 手続きなど作業する人
PHP - 作業する人があつかうデータ
データベース
設計・テーブル作成
目的
- テーブルの初期化をPHPから実施する(毎回SQL文を入力するのは面倒なため)
必要な知識
- 特になし
実践
- テーブルを初期化する処理をinitialize_reviews_table.phpに記載
<?php
require_once __DIR__ . '/lib/mysqli.php';
function dropTable($link)
{
$dropTable = 'DROP TABLE IF EXISTS reviews;';
$result = mysqli_query($link, $dropTable);
if ($result) {
echo 'テーブルの削除に成功しました' . PHP_EOL;
} else {
echo 'Error: テーブルの削除に失敗しました' . PHP_EOL;
echo 'Debugging error: ' . mysqli_error($link) . PHP_EOL;
}
}
function createTable($link)
{
$createTable = <<<EOT
CREATE TABLE reviews (
id INTEGER AUTO_INCREMENT NOT NULL PRIMARY KEY,
title VARCHAR(255),
author VARCHAR(100),
status VARCHAR(10),
score INTEGER,
summary VARCHAR(1000),
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARACTER SET=UTF8MB4;
EOT;
$result = mysqli_query($link, $createTable);
if ($result) {
echo 'テーブルの作成に成功しました' . PHP_EOL;
} else {
echo 'Error: テーブルの作成に失敗しました' . PHP_EOL;
echo 'Debugging error: ' . mysqli_error($link) . PHP_EOL;
}
}
$link = dbConnect();
dropTable($link);
createTable($link);
mysqli_close($link);
- 該当のディレクトリで以下コマンドを実施するとテーブルの初期化が実施できる
docker-compose exec app php reviews/initialize_reviews_table.php
[登録ページ] HTMLで表示する
目的
PHPでHTMLを表示する
必要な知識
-
HTML、CSS、PHPの作成手順
HTML→PHP→CSS -
HTMLを書くときの順序
1, WFを書く
2, HTMLで基本構成とheadを作成する
3, 大枠のレイアウトをメモする
4, HTMLで大枠のレイアウトを作成する
5, 個別パーツのレイアウトをメモする
6, HTMLで個別パーツを作成する
※HTMLを書くときのコツは入れ子構造を意識すること
実践
-
表示したい内容のHTMLをファイルに記載
-
ブラウザのURL欄に以下を記載する
localhost:アプリケーションのポート番号/表示したいファイルのルートからのフルパス
- src/reviews/new.phpに記載
<body>
<h1>読書ログ</h1>
<form action="" method="post">
<div>
<label for="title">書籍名</label>
<input type="text" name="title" id="title">
</div>
<div>
<label for="author">著者名</label>
<input type="text" name="author" id="author">
</div>
<div>
<label>読書状況</label>
<div>
<div>
<input type="radio" name="status" id="status1" value="未読">
<label for="status1">未読</label>
</div>
<div>
<input type="radio" name="status" id="status2" value="読んでる">
<label for="status2">読んでる</label>
</div>
<div>
<input class="form-check-input" type="radio" name="status" id="status3" value="読了">
<label for="status3">読了</label>
</div>
</div>
</div>
<div>
<label for="score">評価(5点満点の整数)</label>
<input type="number" name="score" id="score">
</div>
<div>
<label for="summary">感想</label>
<textarea type="text" name="summary" id="summary" rows="10"></textarea>
</div>
<button type="submit">登録する</button>
</form>
</body>
[登録ページ] 読書ログを登録する
目的
PHPでデータを登録する
必要な知識
PHPで定義されている変数。外部から情報などが取得できる
-
$_ENV
環境変数
連想配列として受け取る -
$_POST
POSTされた情報
連想配列として受け取る -
$_GET
URLパラメータの情報
連想配列として受け取る -
$_SERVER
連想配列として受け取る
REQUEST_METHOD:ページにアクセスする際に使用されたリクエストのメソッド名。''GET', 'POST'など
マジック定数
-
DIR
そのファイルの存在するディレクトリ名 -
FILE
ファイルのフルパスとファイル名 -
LINE
そのファイル上の現在の行番号
共通の処理は別ファイルに一箇所にまとめて、そのファイルを読み込んで使おう
-
require
指定したファイルを読み込む
読み込みが失敗すると処理がそこで中断される -
require_once
requireとほぼ同じだが、一度しかファイルを読み込まない
悩んだらrequire_onceを使うことを推奨
リダイレクト
ユーザを自動的に別のページヘ転送する仕組み
1つのページに1つの処理
- header
生のHTTPヘッダを送信する
$header:ヘッダ文字列
header($header)
- リダイレクトするには"Location:"ヘッダを付ける
リダイレクト処理するとこれ以降のコードは実行されないので注意
header("Location: http://www.example.com/");
エラーハンドリング
-
エラーメッセージをログに書き出す
ログは、障害などが起きた時に何が起きたかを把握できるように、プログラムの実行状況・データ送受信状況などを記録しておくもの -
PHP・Apacheのログ
ログには主にアクセスログとエラーログがある(自分で設定できる)。
PHPはエラーログ、Apacheはアクセスログとエラーログを主に出力 -
アクセスログ
1, ブラウザがサーバー(Apache)にリクエストし、それにApacheが応えるごとに記録される(アクセスのたびに記録)
2, アクセスの履歴を確認するために使う -
エラーログ
1, リクエストの結果がエラーになったものだけが記録される
2, サーバに問題が起きたら検知するために使う -
error_log
エラーメッセージをWebサーバーのエラーログに送信する
error_log($message)
「データベースに接続できません」と記録するなら
error_log("データベースに接続できません");
- Dockerコンテナ内のログを確認するにはdocker logsコマンドを使う
事前準備:コンテナ名を確認
docker ps
ログを確認したい時(-f:follow。ログの出力を表示し続ける)
docker logs -f <コンテナ名>
アクセスログを確認したい時(エラーログを捨てる)
docker logs <コンテナ名> -f 2>/dev/null
エラーログを確認したい時
docker logs <コンテナ名> -f 1>/dev/null
PHPとHTMLファイルを分割する
- include
指定したファイルを読み込む
読み込みが失敗しても処理が中断されない
※require_onceと似ているが、処理が中断されない点が異なる。HTMLやテキストなどを読み込む時に使う
※ロジックとHTMLはファイル分割する
※DRY
Don' t repeat yourself
バリデーションエラーしても入力値を残す
- value属性
input要素の値を指定する属性
テキスト入力欄などにおいて初期入力値を表す
<input type="text" id="name" name="name" value="<?php echo $company['name'] ?>">
-
バリデーションエラー時に入力した値が消える理由は、新しくHTMLを読み込んでいるから。これを改善するにフォームの初期値を設定しておく方法をパーツごとに抑えとくとよい。
-
checked属性を付けると初期値で選択された状態になる
<div>
// 「男性」が最初から選択された状態になる
<input type="radio" name="sex" id="sex1" value="男性" checked>
<label for="sex1">男性</label>
</div>
<div>
<input type="radio" name="sex" id="sex2" value="女性">
<label for="sex2">女性</label>
</div>
<div>
<input type="radio" name="sex" id="sex1" value="男性"
<?php echo ($user['sex'] === '男性') ? 'checked' : ''; ?>>
<label for="sex1">男性</label>
</div>
実践
src/reviews/lib/mysqli.php に共通処理をまとめる。
<?php
require __DIR__ . '/../vendor/autoload.php';
function dbConnect()
{
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->load();
$dbHost = $_ENV['DB_HOST'];
$dbUsername = $_ENV['DB_USERNAME'];
$dbPassword = $_ENV['DB_PASSWORD'];
$dbDatabase = $_ENV['DB_DATABASE'];
$link = mysqli_connect($dbHost, $dbUsername, $dbPassword, $dbDatabase);
if (!$link) {
echo 'Error: データベースに接続できません' . PHP_EOL;
echo 'Debugging error: ' . mysqli_connect_error() . PHP_EOL;
exit;
}
return $link;
}
src/reviews/new.php のformのactionを指定する
<form action="create.php" method="post">
src/reviews/create.php で登録処理を行う。
<?php
require_once __DIR__ . '/lib/mysqli.php';
function createReview($link, $review)
{
$sql = <<<EOT
INSERT INTO reviews (
title,
author,
status,
score,
summary
) VALUES (
"{$review['title']}",
"{$review['author']}",
"{$review['status']}",
"{$review['score']}",
"{$review['summary']}"
)
EOT;
$result = mysqli_query($link, $sql);
if (!$result) {
error_log('Error: fail to create review');
error_log('Debugging Error: ' . mysqli_error($link));
}
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$review = [
'title' => $_POST['title'],
'author' => $_POST['author'],
'status' => $_POST['status'],
'score' => $_POST['score'],
'summary' => $_POST['summary']
];
// バリデーションする
$link = dbConnect();
createReview($link, $review);
mysqli_close($link);
}
header("Location: index.php");
src/reviews/index.php を一覧ページとして用意する
<?php
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>読書ログ一覧</title>
</head>
<body>
<h1>読書ログの一覧</h1>
</body>
</html>
src/reviews/views/new.php を作成し、HTMLをまとめる
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>読書ログ登録</title>
</head>
<body>
<h1>読書ログ</h1>
<form action="create.php" method="post">
<?php if (count($errors)) : ?>
<ul>
<?php foreach ($errors as $error) : ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<div>
<label for="title">書籍名</label>
<input type="text" name="title" id="title">
</div>
<div>
<label for="author">著者名</label>
<input type="text" name="author" id="author">
</div>
<div>
<label>読書状況</label>
<div>
<div>
<input type="radio" name="status" id="status1" value="未読">
<label for="status1">未読</label>
</div>
<div>
<input type="radio" name="status" id="status2" value="読んでる">
<label for="status2">読んでる</label>
</div>
<div>
<input class="form-check-input" type="radio" name="status" id="status3" value="読了">
<label for="status3">読了</label>
</div>
</div>
</div>
<div>
<label for="score">評価(5点満点の整数)</label>
<input type="number" name="score" id="score">
</div>
<div>
<label for="summary">感想</label>
<textarea type="text" name="summary" id="summary" rows="10"></textarea>
</div>
<button type="submit">登録する</button>
</form>
</body>
</html>
src/reviews/new.php にて、src/reviews/views/new.php を読み込む。また $errors を初期化し、エラーが起こらないようにする
<?php
$errors = [];
include 'views/new.php';
src/reviews/create.php の末尾にて、src/reviews/views/new.php を読み込む
<?php
require_once __DIR__ . '/lib/mysqli.php';
function createReview($link, $review)
{
$sql = <<<EOT
INSERT INTO reviews (
title,
author,
status,
score,
summary
) VALUES (
"{$review['title']}",
"{$review['author']}",
"{$review['status']}",
"{$review['score']}",
"{$review['summary']}"
)
EOT;
$result = mysqli_query($link, $sql);
if (!$result) {
error_log('Error: fail to create review');
error_log('Debugging Error: ' . mysqli_error($link));
}
}
function validate($review)
{
$errors = [];
// 書籍名が正しく入力されているかチェック
if (!strlen($review['title'])) {
$errors['title'] = '書籍名を入力してください';
} elseif (strlen($review['title']) > 255) {
$errors['title'] = '書籍名は255文字以内で入力してください';
}
// 著者名が正しく入力されているかチェック
if (!strlen($review['author'])) {
$errors['author'] = '著者名を入力してください';
} elseif (strlen($review['author']) > 255) {
$errors['author'] = '著者名は255文字以内で入力してください';
}
// 読書状況が正しく入力されているかチェック
if (!in_array($review['status'], ['未読', '読んでる', '読了'])) {
$errors['status'] = '読書状況は「未読」「読んでる」「読了」のいずれかを入力してください';
}
// 評価が正しく入力されているかチェック
if ($review['score'] < 1 || $review['score'] > 5) {
$errors['score'] = '評価は1〜5の整数を入力してください';
}
// 感想が正しく入力されているかチェック
if (!strlen($review['summary'])) {
$errors['summary'] = '感想を入力してください';
} elseif (strlen($review['summary']) > 10000) {
$errors['summary'] = '感想は10,000文字以内で入力してください';
}
return $errors;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$status = '';
if (array_key_exists('status', $_POST)) {
$status = $_POST['status'];
}
$review = [
'title' => $_POST['title'],
'author' => $_POST['author'],
'status' => $status,
'score' => $_POST['score'],
'summary' => $_POST['summary']
];
$errors = validate($review);
if (!count($errors)) {
$link = dbConnect();
createReview($link, $review);
mysqli_close($link);
header("Location: index.php");
}
}
// ここを追記。以下のHTMLは削除
include 'views/new.php';
src/new.php
// ここを追記
$review = [
'title' => '',
'author' => '',
'status' => '未読',
'score' => '',
'summary' => ''
];
$errors = [];
src/views/new.php
// 下記をそれぞれ修正
<input type="text" name="title" id="title" value="<?php echo $review['title'] ?>">
<input type="text" name="author" id="author" value="<?php echo $review['author'] ?>">
<input type="radio" name="status" id="status1" value="未読" <?php echo ($review['status'] === '未読') ? 'checked' : ''; ?>>
<input type="radio" name="status" id="status2" value="読んでる" <?php echo ($review['status'] === '読んでる') ? 'checked' : ''; ?>>
<input class="form-check-input" type="radio" name="status" id="status3" value="読了" <?php echo ($review['status'] === '読了') ? 'checked' : ''; ?>>
<input type="number" name="score" id="score" value="<?php echo $review['score'] ?>">
<textarea type="text" name="summary" id="summary" rows="10"><?php echo $review['summary'] ?></textarea>
[登録ページ] CSSでスタイルを整える
目的
Bootstrapを用いて画面のスタイルを整える
必要な知識
-
CSSを書くときの順序
1, 大枠のレイアウトをスタイリングする
2, 大枠のレイアウトをレスポンシブ対応する
3, 個別パーツをスタイリングする
4, 個別パーツをレスポンシブ対応する -
処理を書くコツは先にコメントで実装したい処理を書く
-
エラー処理をしっかり書いておくと、エラーが起きた際の発見が早くなるため返って実装の速度が上がる。サボらずに書こう
-
bootstrapの使い方は以下公式ドキュメント参照
bootstrap
実践
stylesheets/css ディレクトリを作成した上で、下記コマンドを実行し、SassをCSSにコンパイルする。
vendor/scssphp/scssphp/bin/pscss < stylesheets/scss/app.scss > stylesheets/css/app.css
src/reviews/views/new.php で app.css を読み込む
<head>
...
<link rel="stylesheet" href="stylesheets/css/app.css">
<title>会社情報の登録</title>
</head>
src/reviews/views/new.php
<body>
<header class="navbar shadow-sm p-3 mb-5 bg-white">
<h1 class="h2">
<a class="text-body text-decoration-none" href="index.php">読書ログ</a>
</h1>
</header>
<div class="container">
<h2 class="h3 text-dark mb-4">読書ログの登録</h2>
<form action="create.php" method="post">
<?php if (count($errors)) : ?>
<ul class="text-danger">
<?php foreach ($errors as $error) : ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<div class="form-group">
<label for="title">書籍名</label>
<input type="text" name="title" id="title" class="form-control" value="<?php echo $review['title'] ?>">
</div>
<div class="form-group">
<label for="author">著者名</label>
<input type="text" name="author" id="author" class="form-control" value="<?php echo $review['author'] ?>">
</div>
<div class="form-group">
<label>読書状況</label>
<div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status1" value="未読" <?php echo ($review['status'] === '未読') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status1">未読</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status2" value="読んでる" <?php echo ($review['status'] === '読んでる') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status2">読んでる</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status3" value="読了" <?php echo ($review['status'] === '読了') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status3">読了</label>
</div>
</div>
</div>
<div class="form-group">
<label for="score">評価(5点満点の整数)</label>
<input type="number" name="score" id="score" class="form-control" value="<?php echo $review['score'] ?>">
</div>
<div class="form-group">
<label for="summary">感想</label>
<textarea type="text" name="summary" id="summary" class="form-control" rows="10"><?php echo $review['summary'] ?></textarea>
</div>
<button type="submit" class="btn btn-primary">登録する</button>
</form>
</div>
</body>
[トップページ] HTMLで表示する
目的
読書ログの一覧画面のHTMLを作成する
必要な知識
実践
- 一覧画面のHTMLを作成する
- 登録画面と一覧画面のHTMLのレイアウト部分を共通化します
- バリデーションエラーになった画面(src/create.php)にもスタイルを当ててください。こちらは現状Bootstrapが当たってない状態になっているので、Bootstrapを当てればOKです(講義の会社情報ではこちらの対応やってなく、クイズ独自の対応です)
src/reviews/new.php
<?php
$review = [
'title' => '',
'author' => '',
'status' => '未読',
'score' => '',
'summary' => ''
];
$errors = [];
$title = '読書ログ登録';
$content = __DIR__ . "/views/new.php";
include __DIR__ . '/views/layout.php';
src/review/index.php
<?php
$title = '読書ログ一覧';
$content = __DIR__ . "/views/index.php";
include __DIR__ . '/views/layout.php';
src/reviews/views/layout.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="stylesheets/css/app.css">
<title><?php echo $title; ?></title>
</head>
<body>
<header class="navbar shadow-sm p-3 mb-5 bg-white">
<h1 class="h2">
<a class="text-body text-decoration-none" href="index.php">読書ログ</a>
</h1>
</header>
<div class="container">
<?php include $content; ?>
</div>
</body>
src/rviews/views/new.php
<h2 class="h3 text-dark mb-4">読書ログの登録</h2>
<form action="create.php" method="post">
<?php if (count($errors)) : ?>
<ul class="text-danger">
<?php foreach ($errors as $error) : ?>
<li><?php echo $error; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
<div class="form-group">
<label for="title">書籍名</label>
<input type="text" name="title" id="title" class="form-control" value="<?php echo $review['title'] ?>">
</div>
<div class="form-group">
<label for="author">著者名</label>
<input type="text" name="author" id="author" class="form-control" value="<?php echo $review['author'] ?>">
</div>
<div class="form-group">
<label>読書状況</label>
<div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status1" value="未読" <?php echo ($review['status'] === '未読') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status1">未読</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status2" value="読んでる" <?php echo ($review['status'] === '読んでる') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status2">読んでる</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" name="status" id="status3" value="読了" <?php echo ($review['status'] === '読了') ? 'checked' : ''; ?>>
<label class="form-check-label" for="status3">読了</label>
</div>
</div>
</div>
<div class="form-group">
<label for="score">評価(5点満点の整数)</label>
<input type="number" name="score" id="score" class="form-control" value="<?php echo $review['score'] ?>">
</div>
<div class="form-group">
<label for="summary">感想</label>
<textarea type="text" name="summary" id="summary" class="form-control" rows="10"><?php echo $review['summary'] ?></textarea>
</div>
<button type="submit" class="btn btn-primary">登録する</button>
</form>/layout.php';
src/reivews/views/index.php
※sectionタグの中身の文字は何でもOK
※「 」は特殊文字で、スペースを入れるために使用している。本来は「挿入した箇所の前後の改行を禁止する」役割だが、現場ではスペースを入れる目的でもよく使用される
<?php
$review = [
'title' => '',
'author' => '',
'status' => '未読',
'score' => '',
'summary' => ''
];
$errors = [];
$title = '読書ログ登録';
$content = __DIR__ . "/views/new.php";
include __DIR__ . '/views/layout.php';
<?php
$review = [
'title' => '',
'author' => '',
'status' => '未読',
'score' => '',
'summary' => ''
];
$errors = [];
$title = '読書ログ登録';
$content = __DIR__ . "/views/new.php";
include __DIR__ . '/views/layout.php';
src/reviews/create.php
※ここだけファイルの一部を掲載
$title = '読書ログ登録';
// ここを修正
$content = __DIR__ . "/views/new.php";
include __DIR__ . '/views/layout.php';
[トップページ] 読書ログの一覧を表示する
目的
データベースからデータを取得し、HTMLで画面に表示する
必要な知識
-
データベースからデータを取得
配列で取得 -
HTMLでデータを表示
ループで一つずつ表示 -
データがないときの処理
データがないときなど、イレギュラーパターンを想定して処理を書けることがプロダクションコードへ第一歩 -
TRUNCATE TABLE
指定したテーブルの全データを削除する
tbl_name:テーブル名
TRUNCATE TABLE [TABLE] tbl_name
- 会社情報テーブルの全データを削除する
TRUNCATE TABLE companies;
PHPでXSS対策するには
htmlspecialchars()を使ってHTML特殊記号をエスケープする
- HTMLの特殊記号を文字参照に置き換える
$string :変換する文字列
$flags:処理の仕方を指定するフラグ
$encoding:文字を変換する時に使用するエンコーディング
htmlspecialchars($string, $flags, $encoding)
- ユーザーが入力してDBに保存された以下の値をエスケープするなら
「<script>...</script>」
htmlspecialchars('<script>...</script>', ENT_QUOTES, 'UTF-8')
実行結果
$lt;script>...</script>
実践
src/revies/lib/escape.php
<?php
function escape($string)
{
return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}
src/reviews/index.php
<?php
require_once __DIR__ . '/lib/escape.php';
require_once __DIR__ . '/lib/mysqli.php';
function listReviews($link)
{
$reviews = [];
$sql = "SELECT id, title, author, status, score, summary FROM reviews";
$results = mysqli_query($link, $sql);
while ($review = mysqli_fetch_assoc($results)) {
$reviews[] = $review;
}
mysqli_free_result($results);
return $reviews;
}
$link = dbConnect();
$reviews = listReviews($link);
$title = '読書ログ一覧';
$content = __DIR__ . "/views/index.php";
include __DIR__ . '/views/layout.php';
src/reviews/views/index.php
<a href="new.php">読書ログを登録する</a>
<main>
<?php if (count($reviews) > 0) : ?>
<?php foreach ($reviews as $review) : ?>
<section>
<h2><?php echo escape($review['title']) ?></h2>
<div>
<?php echo escape($review['author']) ?> /
<?php echo escape($review['status']) ?> /
<?php echo escape($review['score']) ?>点
</div>
<p>
<?php echo nl2br(escape($review['summary']), false) ?>
</p>
</section>
<?php endforeach; ?>
<?php else : ?>
<p>まだ読書ログが登録されていません。</p>
<?php endif; ?>
</main>
[トップページ] CSSでスタイルを整える
目的
一覧画面をデザインする
必要な知識
[登録ページ] CSSでスタイルを整えると同様
実践
src/revies/views/index.php
<a href="new.php" class="btn btn-primary mb-4">読書ログを登録する</a>
<main>
<?php if (count($reviews) > 0) : ?>
<?php foreach ($reviews as $review) : ?>
<section class="card shadow-sm mb-4">
<div class="card-body">
<h2 class="card-title h4 text-dark mb-3"><?php echo escape($review['title']) ?></h2>
<div class="small mb-3">
<?php echo escape($review['author']) ?> /
<?php echo escape($review['status']) ?> /
<?php echo escape($review['score']) ?>点
</div>
<p>
<?php echo nl2br(escape($review['summary']), false) ?>
</p>
</div>
</section>
<?php endforeach; ?>
<?php else : ?>
<p>まだ読書ログが登録されていません。</p>
<?php endif; ?>
</main>