前回、Webページが表示される仕組みを学び、HTMLにて登録ページの骨格を作成しました。
今回は読書ログのデータを登録できるようにします。
(バリデーション処理は次回行います。)
PHPの定義済み変数
PHPで定義されている変数のこと。外部から情報などが取得できる。
$_ENV
- 環境変数
- 連想配列として受け取る
$_POST
- POSTされた情報
- 連想配列として受け取る
$_GET
- URLパラメータの情報
- 連想配列として受け取る
$_SERVER
- サーバや実行時の環境情報
- 連想配列として受け取る
- REQUEST_METHOD : ページにアクセスする際に使用されたリクエストのメソッド名。'GET', 'POST'など。
マジック定数
使われる場所によって値が変化する定数のこと。
__DIR__
- そのファイルの存在するディレクトリ名
外部ファイルの読み込み方
共通の処理は別ファイルに一箇所にまとめて、そのファイルを読み込んで使用する
require
指定したファイルを読み込む
- 読み込みが失敗すると処理がそこで中断される
require '<ファイル名>';
require_once
require
とほぼ同じだが、一度しかファイルを読み込まない
- 悩んだら
require_once
を使う - 何度も外部ファイルを読み込むことは稀なため
データ登録後、リダイレクトするようにする
リダイレクトとは、ユーザを自動的に別のページへ転送する仕組みのこと。
header関数を使ってリダイレクトする。
header
生のHTTPヘッダを送信する
- $header : ヘッダ文字列
header($header)
リダイレクトするには
Location:
ヘッダを付ける
header("Location: <リダイレクト先>");
エラーログを出力するようにする
ログは、障害などが起きたときに何が起きたかを把握できるように、プログラムの実行状況・データ送受信状況などを記憶しておくもの。
ユーザの行動履歴が分かるため、サイトの不具合や不審なアクセスを見つけられる。
PHP・Apacheのログ
ログには主に、アクセスログとエラーログがある。
PHPはエラーログ、Apacheはアクセスログとエラーログを主に出力する。
アクセスログ
- ブラウザがサーバ(Apache)にリクエストし、それにApacheが応えるごとに記録される。
- アクセスの履歴を確認するために使う。
エラーログ
- リクエストの結果がエラーになったものだけが記録される。
- サーバに問題が起きたら検知するために使う。
エラーログの出力には error_log() を使う
エラーメッセージをWebサーバのエラーログに送信する
- $message : エラーログに記録されるメッセージ
error_log($message)
例えば、「データベースに接続できません」と記録するなら
error_log("データベースに接続できません");
ログの確認方法
Dockerコンテナ内のログを確認するにはdocker logs
コマンドを使う。
docker-compose
コマンドでも出力可能であるが、アクセスログとエラーログを分けて出力することができないため、今回はdockerコマンドを用いる。
- 事前準備 : コンテナ名を確認
docker ps
- ログを確認したい時(-f : follow。ログの出力を表示し続ける)
docker logs -f <コンテナ名>
- アクセスログを確認したい時(エラーログを捨てる)
docker logs <コンテナ名> -f 2>/dev/null
- エラーログを確認したい時
docker logs <コンテナ名> -f 1>/dev/null
書いたコード
ちなみに、ディレクトリの構造は以下のとおり
データベースへの接続処理は色々な場所で出てくるため、mysqli.php
というファイルを作って、その内容を他のファイルに継承するようにする。
mysqli.php
<?php // Composerのautoloadを読み込む。 // これにより各ライブラリをPHPファイル内で呼び出せるようになる // 後で理解すればOK.composerを使用するときは書いておく。 require __DIR__ . '/../vendor/autoload.php'; // データベースとの接続の関数を定義 function dbConnect() { // 以下の記述はオブジェクト指向を学んでから理解すればOK // 環境変数をPHPファイルに読み込む $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 'データベースに接続しました' . PHP_EOL; } else { echo 'Error: データベースに接続できません' . PHP_EOL; echo 'Debugging error: ' . mysqli_connect_error() . PHP_EOL; exit; } return $link; }
上記で共通化した項目をrequire_once __DIR__ . '/lib/mysqli.php';
で読み込み、該当箇所は削除。
initialize_reviews_table.php
<?php // mysqli.phpファイルを読み込む require_once __DIR__ . '/lib/mysqli.php'; // companiesテーブルが既に存在していたら、削除する関数を定義 function dropTable($link) { $dropTableSql = 'DROP TABLE IF EXISTS reviews'; $result = mysqli_query($link, $dropTableSql); if ($result) { echo 'テーブルを削除しました' . PHP_EOL; } else { echo 'Error: テーブルの削除に失敗しました' . PHP_EOL; echo 'Debugging Error: ' . mysqli_error($link) . PHP_EOL . PHP_EOL; } } // companiesテーブルを作成する関数を定義 function createTable($link) { $createTableSql = <<<EOT CREATE TABLE reviews ( id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255), author VARCHAR(30), status VARCHAR(30), score INTEGER, summary VARCHAR(500), created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) DEFAULT CHARACTER SET = utf8mb4; EOT; $result = mysqli_query($link, $createTableSql); if ($result) { echo 'テーブルを作成しました' . PHP_EOL; } else { echo 'Error: テーブルの作成に失敗しました' . PHP_EOL; echo 'Debugging Error: ' . mysqli_error($link) . PHP_EOL . PHP_EOL; } } // データベースとの接続 -> テーブルの初期化(削除・作成)-> データベースの切断 を実行 $link = dbConnect(); dropTable($link); createTable($link); mysqli_close($link);
create.php
<?php // mysqli.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); // $resultがfalseなら、エラーログを吐き出す if (!$result) { error_log('Error: fail to create review'); error_log('Debugging Error: ' . mysqli_error($link)); } } // HTTPメソッドがPOSTだったら if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 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); } // index.phpへリダイレクト header("Location: index.php");
ひとまず、リダイレクト先を簡易に作成
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>
前回作成した登録ページのファイル(再掲)。
form
タグにて、送信先にcreate.php
を指定(action="create.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> <h2>読書ログの登録</h2> <form action="create.php" method="POST"> <div> <label for="title">書籍名</label> <input type="text" id="title" name="title"> </div> <div> <label for="author">著者名</label> <input type="text" id="author" name="author"> </div> <div> <label>読書状況</label> <div> <div> <input type="radio" name="status" id="not_yet" value="未読"> <label for="not_yet">未読</label> </div> <div> <input type="radio" name="status" id="reading" value="読んでいる"> <label for="reading">読んでいる</label> </div> <div> <input type="radio" name="status" id="finish" value="読了"> <label for="finish">読了</label> </div> </div> </div> <div> <label for="score">評価(5点満点の整数)</label> <input type="number" id="score" name="score" min="1" max="5"> </div> <div> <label for="summary">感想</label> <textarea name="summary" id="summary" cols="20" rows="3"></textarea> </div> <button type="submit">登録する</button> </form> </body> </html>
備忘録(詰まった点)
パスを指定する箇所において、カレントディレクトリからのパス(相対パス)が間違っていてエラーが出た。
エラーにNo such file or directory
が記載されていたら、パスの指定誤りを疑う。
[23-Feb-2022 19:37:04 Asia/Tokyo] PHP Warning: require_once(/var/www/html/lib/mysqli.php): failed to open stream: No such file or directory in /var/www/html/create.php on line 3 Warning: require_once(/var/www/html/lib/mysqli.php): failed to open stream: No such file or directory in /var/www/html/create.php on line 3