目標
今回やること
- CUIアプリケーションをデータベースに対応させる
タスクばらし
- 読書ログを保存するテーブルを作成する
- PHPからデータベースに接続する
- 読書ログをデータベースに登録する
- 読書ログをデータベースから表示する
補足
MySQLの操作の流れ
接続→命令→切断
- MySQLに接続する
- MySQLに命令する
データベースを作成する
テーブルを作成する
テーブルにデータを登録する
テーブルからデータを取得する - MySQLとの接続を切断する
接続はMySQLに電話をかけて、相手が「今いいよ」といってから命令を出すイメージ
MySQLとの間に確立された接続のことを「コネクション」という
読書ログを保存するテーブルを作成する
目的
DockerでMySQLに接続し、読書ログを保存するテーブルを作成する
必要な知識
- MySQLと接続するにはmysqlコマンドを使う
クライアントからmysqlサーバーに接続する
// -pで値を指定しないとターミナルが入力を求め、入力時に表示されないため、セキュア
mysql -h ホスト名 -u ユーザー名 -D データベース名 -p
appコンテナからdbコンテナのmysqlに接続する
docker-compose exec app mysql -h db -u book_log -D book_log -p
-
MySQLに命令する
dev.mysql.comを参考にして、SQL文を作成する -
ファイルからSQL文を実行することで、毎回手入力せずに済む
テキストファイルにSQL文を保存し、下記コマンドを実行する
mysql < text_file
Docker上のMySQLに対して実行するなら以下のコマンド
docker-compose exec app /bin/bash
mysql -h db -u book_log -D book_log -p < text_file
実践
- Dockerの機能でコンテナを立ち上げた際に、データベースは作成される
そのため、以下のコマンドを入力すれば、データベースは自動で作成される
docker-compose exec app mysql -h db -u book_log -D book_log -p
- MySQLでテーブルを作成する
CREATE TABLES 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;
次の作業でSQLをファイルから実行するため、一旦作成したテーブルは削除する
DROP TABLE reviews;
- ファイルにテーブル作成のSQL文を保存し、そのファイルからSQL文を実行する
保存するテーブルの中身
// reviewsテーブルを初期化
DROP TABLE IF EXISTS reviews;
CREATE TABLES 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;
ファイルを実行
docker-compose exec app /bin/bash
mysql -h db -u book_log -D book_log -p < itinitialize_reviews_table.sql
PHPからデータベースに接続する
目的
- PHPからMySQLに接続する
必要な知識
- PHPからMySQLを利用する時はMySQLiを使おう
MySQLに接続するにはmysqli_connect関数使おう
mysqli_connect('my_host', 'my_user', 'my_password', 'my_db')
読書ログでMySQLに接続するなら
mysqli_connect('db', 'book_log', 'pass', 'book_log')
- MySQLの使用が完了したらMySQLとの接続を切る
接続を切るにはmysqli_close関数を使う
// $link:mysqli_connect()が返すリンクID
mysqli_close($link)
実践
・読書ログでMySQLに接続、切断する
以下をbook_log.phpに追記
function dbConnect()
{
$link = mysqli_connect('db', 'book_log', 'pass', 'book_log');
// データベースに接続できなかったときのエラー処理
if (!$link) {
echo 'Error: データベースに接続できません' . PHP_EOL;
echo 'Debugging error: ' . mysqli_connect_error() . PHP_EOL;
exit;
}
// $linkに格納された値は関数の外でも使用するため、戻り値に指定
return $link;
}
読書ログをデータベースに登録する
目的
- PHPからMySQLにデータを追加する
必要な知識
- SQLのINSERT文でテーブルにデータを登録する
INSERT文を使うと、テーブルに一行のデータを挿入する
$link : mysql_connect()が返すリンクID
$query : SQL文の文字列
companiesテーブルにデータを登録するなら
$link = mysqli_connect('db', 'book_log', 'pass', 'book_log');
$sql = "INSERT INTO compaies (name) VALUES ('SmartHR inc')";
mysqli_query($link, $sql);
- mysqli_query()は実行時に失敗した場合にFALSEを返すことを利用してエラーメッセージを表示する
$link = mysqli_connect('db', 'book_log', 'pass', 'book_log');
$sql = "INSERT INTO compaies (name) VALUES ('SmartHR inc')";
$result = mysqli_query($link, $sql);
if ($result) {
echo 'データを追加しました' . PHP_EOL;
} else {
echo 'Error: データの追加に失敗しました' . PHP_EOL;
echo 'Debugging Error: ' . mysqli_error($link) . PHP_EOL;
}
- ヒアドキュメントを使うと、複数行の文字列をそのままコード中に記載できるので、SQL文を書くときなどに見やすくなり便利
// ヒアドキュメント書く際は必ず左詰め
$sql = <<<EOT
INSERT INTO companies (
name
) VALUES (
'SmartHR inc'
)
EOT;
- バリデーション処理をする
バリデーション処理をしないと、、
予期せぬ値が入力されるかも
セキュリティ上問題があったり、変なデータがデータベースに保存され、プログラムが不具合を起こしたりしかねない
- よくあるバリデーション処理
値が入力されているか?
文字列の長さは適当な範囲か?
数値が入力されているか?
数値は適切な範囲内の値か?
選択肢から選ばれた値か?
書式が正しいか?(メールアドレス、電話番号など)
- バリデーションの基本形
strlen関数は全角文字(日本語)をカウントすると、1文字を3文字としてカウントする。
これはstrlenが文字数ではなくバイト数を返しており、日本語は一文字で複数バイトを使うため。
mb_strlen関数だと複数バイトを考慮し、日本語の1文字を1文字としてカウントする。
// バリデーションメソッドを用意
function validate($name)
{
$erros = [];
if (!strlen($name)) {
$errors['name'] = '社名を入力してください';
} elseif (strlen($name) > 100) {
$errors['name'] = '社名は100文字以内で入力してください';
}
// エラー変数を返す
return $errors;
}
$name = trim(fgets(STDIN));
$validated = validate($name);
if (count($validated) > 0) {
foreach ($validated as $error) {
echo $error . PHP_EOL;
}
// 処理を中断する
return;
}
- 整数のバリデーション
文字列を整数に変換することができる
ユーザーの入力値を適切な型に変換してプログラムで扱う時などに使用する
型キャスト
(int)
(bool)
(string)
文字列を整数へ変換するなら
$a = '2';
var_dump( (int) $a ) // int(2)
ex)型キャストの挙動
php > var_dump((int)5.8);
int(5)
php > var_dump((int) 'hoge');
int(0)
php >
※php -a
インタラクティブにphpを実行できる
※変数の型を意識する
実践
- 読書ログをPHPからデータベースに登録する
book_log.phpの関数createReviewsに追記
function createReviews($link)
{
..
..
..
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) {
echo 'データを追加しました' . PHP_EOL;
} else {
echo 'Error: データの追加に失敗しました' . PHP_EOL;
echo 'Debugging error: ' . mysqli_error($link) . PHP_EOL;
}
}
- 上記の「読書ログをPHPからデータベースに登録する処理」にバリデーション処理を加える
book_log.phpの関数validateを作成し、中に処理を記載
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']) > 100) {
$errors['author'] = '著者名は100文字以内で入力してください';
}
// 読書状況が正しく入力されているかチェック
$book_status = [
'未読',
'読んでる',
'読了'
];
if (!in_array($review['status'], $book_status, true)) {
$errors['status'] = '未読,読んでる,読了のいずれかを入力してください';
}
// 評価が正しく入力されているかチェック
if ($review['score'] < 1 || $review['score'] > 5) {
$errors['score'] = '評価は1以上5点以下で入力してください';
}
// 感想が正しく入力されているかチェック
if (!strlen($review['summary'])) {
$errors['summary'] = '感想を入力してください';
} elseif (strlen($review['summary']) > 1000) {
$errors['summary'] = '感想は1000文字以内で入力してください';
}
return $errors;
}
読書ログをデータベースから表示する
目的
- PHPからMySQLのデータを取得し、表示する
必要な知識
- mysqli_*関数
mysqli_query:データベース上でクエリを実行する
成功したらmysqli_resultオブジェクトを返す
mysqli_query($link, $query)
mysqli_fetch_assoc:結果の行を連想配列で取得する
$result:mysqli_resultオブジェクト
mysqli_fetch_assoc($result)
mysqli_free_result:結果に関連付けられたメモリを開放する
$result:mysqli_resultオブジェクト
mysqli_free_result($result)
- PHPからSQLでデータを取得する
$link = mysqli_connect('db', 'book_log', 'pass', 'book_log');
$sql = "SELECT * FROM compaies";
$result = mysqli_query($link, $sql);
// 連想配列で結果を取得
while ($company = mysqli_fetch_assoc($results)) {
echo '会社名: ' . $company['name'] . PHP_EOL;
echo '代表者: ' . $company['founder'] . PHP_EOL;
}
// メモリを開放する
mysqli_free_result($result);
実践
book_log.phpの関数viewReviewsに処理を追記
function viewReviews($link)
{
var_dump($link) . PHP_EOL;
$sql = 'SELECT id, title, author, status, score, summary FROM reviews';
$results = mysqli_query($link, $sql);
echo '登録されている読書ログを表示します' . PHP_EOL;
while ($review = mysqli_fetch_assoc($results)) {
echo '書籍名:' . $review['title'] . PHP_EOL;
echo '著者名:' . $review['author'] . PHP_EOL;
echo '読書状況(未読,読んでる,読了):' . $review['status'] . PHP_EOL;
echo '評価(5点満点の整数):' . $review['score'] . PHP_EOL;
echo '感想:' . $review['summary'] . PHP_EOL;
echo '---------------------' . PHP_EOL;
}
mysqli_free_result($results);
}