一部の画像や動画に異なるUIがありますが、CSS修正の有無によるものでプログラム部分には影響はありません。
前回に引き続き、家計簿システム開発していきます。
今回は家計簿データを記録するデータベースを構築し、実際にデータを画面から登録できるようにしていきます。
前回の記事はこちら↓
データベース構築
今回はMAMPのphpMyAdminを使って開発していきます。まず以下の名前の6つのテーブルを作成していきます。
・records(入力データ記録用)
・spending_category(支出カテゴリー記録用)
・income_category(収入カテゴリー記録用)
・payment_method(支払い方法記録用)
・creditcard(クレジットカード記録用)
・qr(スマホ決済記録用)
recordsテーブル
このテーブルは、入力したデータを記録するためのテーブルです。
カラム数がかなり多くなりますが、以上のように設定しました。
・id → 記録データの番号(オートインクリメント設定)
・date → 日付項目の保存カラム
・title → タイトル項目の保存カラム
・amount → 金額項目の保存カラム
・spending_category → 支出カテゴリー項目の保存カラム
・income_category → 収入カテゴリー項目の保存カラム
・type → 支出か収入かの保存カラム
・payment_method → 支払い方法項目の保存カラム
・credit → クレジットカード選択項目の保存カラム
・qr → QR決済選択項目の保存カラム
・memo → 登録フォーム最下のメモ欄の保存カラム
ほとんどがINT(数値)で入れるように構築しました。
これは項目を他のテーブルで管理し、出力の際はそこから情報を引き出すためです。
ここから先のテーブルは、テーブルのカラム構造は全く同じものをテーブル名だけ変えて作っていきます。
その他のテーブル
その他のテーブルは以下の構造で構築しました。
支出カテゴリーと収入カテゴリーは統合してもよいのですが、カテゴリーが増えると入力するときに大変なので今回は分けています。
以上でデータベース構築は完了です。
入力データをDBに登録
データベースが構築できたので、実際に収支データを「登録」を押してデータベースに記録できるように実装していきます。
登録処理までのステップは以下の通りです。
データベースに接続する
記録するために、まずはデータベースに接続するプログラムを書いていきます。
ファイルの冒頭に都度接続プログラムを書いてもよいのですが、データベース名が変わった際に変更するのが手間になるので、①「dbconnect.php」という接続のためだけのファイルを作成し、②それを読み込むという方法で進めていきます。
dbconnect.phpファイルを作成したら、接続の雛形である以下を記載します。
<?php
$変数名 = new mysqli('host_name', 'user_name', 'password', 'database_name');
?>
$変数名には好きな変数を入れてOKです。今回は$dbで進めていきます。
続いて(カッコ)内の値ですが、以下の手順で確認できます。
①MAMPの右上「WebStart」をクリック→ブラウザが開きます。
②MySQL項目をクリック
↑をクリックすると以下のような情報が見ることができます。
先程の接続の雛形をもう1度確認しておきます。
<?php
$変数名 = new mysqli('host_name', 'user_name', 'password', 'database_name');
?>
‘host_name’ → ‘localchost:8889’
‘user_name’ → ‘root’
‘password’ → ‘root’
‘database_name’ → ‘kakeibo’(筆者の場合)
上記情報を当てはめると以下のようになります。
<?php
$db = new mysqli('localhost:8889', 'root', 'root', 'kakeibo');
?>
以上でデータベース接続のためのファイルは完成です。
続いてこのファイルをindex.phpに読み込んで接続されるか確認します。
以下をindex.phpの冒頭に記述しました。
<?php
//DB接続ファイルの読み込み
require_once('./dbconnect.php');
echo "接続完了";
?>
PHPのファイル読み込み関数は「include()」「require()」「include_once()」「require_once()」など複数用意されています。どう違うのかや使い分けは「PHP include require 違い」で検索するとわかりやすい記事が出てくるので参考にしてみてください。
接続が成功している場合は「接続完了」の文字が画面の上部に表示されます。
以上でデータベースの接続は完了です。
送信データを変数化する
次に登録ボタンを押したあとのプログラムを書いていきます。
このプログラムは同じ階層に「record-create.php」という新規ファイルを作成して書いていきます。
まずは新規ファイルにデータベース接続ファイルを読み込み、送られてきたデータを変数に入れて扱いやすくします。
①index.phpのデータ入力フォーム<form>のaction属性に「./record-create.php」を追加(52行目付近)
<form name="recordInput" action="./record-create.php" method="POST">
②record-create.phpの冒頭にdbconnect.phpを読み込む
<?php
//DB接続
require_once('./dbconnect.php');
③送信されてきたデータを変数に入れる用意を記述
//送信データ受け取り
$date = filter_input(INPUT_POST, 'date', FILTER_SANITIZE_SPECIAL_CHARS);
$title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_SPECIAL_CHARS);
$amount = filter_input(INPUT_POST, 'amount', FILTER_SANITIZE_NUMBER_INT);
$spending_category = filter_input(INPUT_POST, 'spending_category', FILTER_SANITIZE_NUMBER_INT);
$income_category = filter_input(INPUT_POST, 'income_category', FILTER_SANITIZE_NUMBER_INT);
$type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_NUMBER_INT);
$payment_method = filter_input(INPUT_POST, 'payment_method', FILTER_SANITIZE_NUMBER_INT);
$credit = filter_input(INPUT_POST, 'credit', FILTER_SANITIZE_NUMBER_INT);
$qr = filter_input(INPUT_POST, 'qr', FILTER_SANITIZE_NUMBER_INT);
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_SPECIAL_CHARS);
$input_time = filter_input(INPUT_POST, 'input_time', FILTER_SANITIZE_SPECIAL_CHARS);
1行1行とても長くなっていますが、送られてきたデータにHTMLタグやscriptプログラムなどが入り込み、バグが起こることを防ぐためにfilter_input関数でフィルタリングをします。
今回の雛形は以下の通りです。
$変数 = filter_input(送信タイプ, '取得したい変数名', フィルターの型);
変数名はわかりやすいものでOKです。ここではname属性と同じにしています。
まず第1パラメータは、送信タイプをPOSTにしているので、INPUT_POSTを記述します。
そして取得したい変数名は、予め設定していたname属性を入れていきます。
※index.phpの入力項目部分のinputやoptionなどに設定しているname属性です。
最後のフィルターの型は、タイトルやメモなどデータベースに文字列で登録する項目は「FILTER_SANITIZE_SPECIAL_CHARS」を、その他の数値で登録する項目は「FILTER_SANITIZE_NUMBER_INT」を設定します。
次は上記で作った変数を使いながらSQL発行のプログラムを書いていきます。
SQLを発行する
送信されてきたデータをrecordsテーブルの該当カラムに正しく入るようにSQLを発行します。
今回は前回の静的コーディングで、支出←→収入ボタンの切り替えで、初期化処理をするorしないのどちらを入れたかによってプログラムを変える必要があります。
※今後のプログラムは初期化処理ありの前提で進めていきますので、前回ダウンロードした静的コーディングのまま進めることを推奨します。
【初期化処理ありの場合】SQLの発行
まずは初期化処理を組み込んでいるときのプログラムです。以下を先程記述したデータ受け取り変数の下に記述します。
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,?,?,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiiiss', $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo, $input_time);
選択していない項目(支出を選択したときの収入カテゴリー、クレジットを選択したときのスマホ決済種類など)や初期化が行われた項目には「0」が入るため通常操作では問題なくデータベースに登録されます。
$sqlでSQL文を作成し格納しています。VALUESはじめの「0」はidカラムに入れる値です。
こちらはデータベースでオートインクリメントを指定しているので、「0」をいれると勝手に連番を入れてくれます。その他のカラムにはこのあと値を変数で指定するので「?」にしておきます。
※SQL文内をダブルクオーテーション「” “」で囲い、{$変数}で値を書くことも可能ですが、セキュリティ的に推奨されていないようなので、bind_param()で指定します。
1番下のbind_param()で「?」に入れるデータを指定します。まずはじめに「s」や「i」が羅列されていますが、これは?に入れるデータ型を指定するものです。「s」は文字列(strings)で「i」は数値(int)を表しています。
また順序は$sqlで記述した「?」の左からの順番(=データベースのカラム左から)になります。
しかし初期化処理を組み込んでいない場合には、すでに入力したあと支出←→収入を切り替えても値が残ってしまうため、収入データとして登録したのにクレジットの種類も記録されるという不具合が起きてしまいます。
これを解消するためにはif文で支出データor収入データの判断をしSQLを発行するプログラムを記述する必要があります。
初期化処理ありの方の次のステップはこちら
【初期化処理なしの場合】支出データの場合のSQL発行
①条件式
支出データであるというのを式にします。
if($type === "0"):
$type === “0” は支出を選択し送信されたときのvalueです。
②「送信データ」or「固定値」を入れるカラム
カラムに対してどんな値を入れるのかは以下の通りです。収入カテゴリー(income_category)やデータタイプ(type)は固定にしてしまうことで、初期化処理を行っていない場合でも正常なデータを登録することができます。
以上からSQL発行プログラムは以下のようになります。
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,0,0,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiss', $date, $title, $amount, $spending_category, $payment_method, $credit, $qr, $memo, $input_time);
以上でまず支出データの場合のSQL発行が完成です。
【初期化処理なしの場合】収入データの場合のSQL
①条件式
収入データであることを条件にします。
elseif ($type === "1") :
②「送信データ」or「固定値」を入れるカラム
上記よりSQL発行プログラムは以下の通りです。
$sql = 'INSERT INTO records VALUES(0,?,?,?,0,?,1,0,0,0,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiss', $date, $title, $amount, $income_category, $memo, $input_time);
これですべてのパターンのSQL発行プログラムができました。
まとめると以下のようになります。
/*===============
初期化処理なしの場合
===============*/
if ($type === "0") :
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,0,0,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiss', $date, $title, $amount, $spending_category, $payment_method, $credit, $qr, $memo, $input_time);
//収入選択時のSQL
elseif ($type === "1") :
$sql = 'INSERT INTO records VALUES(0,?,?,?,0,?,1,0,0,0,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiss', $date, $title, $amount, $income_category, $memo, $input_time);
endif;
SQLを実行して登録する
SQL発行部分が長くなりましたが、最後に上記までで作ったSQLを実行して登録します。
今回はいきなり実行するのではなく、「発行されたSQLが正しいか」「SQL実行は成功したか」の条件分岐を作って、正しくない場合にはエラーを出すようにします。
//この後別ファイルで関数として登録します。
//SQLが正しくない場合はエラーを表示
if (!$stmt) :
die($db->error);
endif;
//正しければSQL実行
$success = $stmt->execute();
//実行されなかったらエラー表示
if (!$success) :
die($db->error);
endif;
以上のプログラムは今後も多用するので、関数にして呼び出す形にします。
まずは「functions.php」ファイルを新規作成し以下を記述します。
<?php
//SQL実行チェック関数
function sql_check($stmt, $db){
//SQLが正しくない場合はエラーを表示
if (!$stmt) :
die($db->error);
endif;
//正しければSQL実行
$success = $stmt->execute();
//実行されなかったらエラー表示
if (!$success) :
die($db->error);
endif;
}
関数を作成したら、record-create.phpで関数を呼び出すのですが、まずはfunctions.phpファイルを読み込む必要があります。
DB接続ファイル読み込みの下に以下を追記します。
include_once('./functions.php');
そしてSQL実行プログラムの下で関数を呼び出し、実行したSQLが正しいかを判断します。
//SQLチェック関数
sql_check($stmt, $db);
SQL実行後はindex.phpに戻る指示を記述します。
header('Location: ./index.php');
exit();
<?php
//DB接続
require_once('./dbconnect.php');
include_once('./functions.php');
//送信データ受け取り
$date = filter_input(INPUT_POST, 'date', FILTER_SANITIZE_SPECIAL_CHARS);
$title = filter_input(INPUT_POST, 'title', FILTER_SANITIZE_SPECIAL_CHARS);
$amount = filter_input(INPUT_POST, 'amount', FILTER_SANITIZE_NUMBER_INT);
$spending_category = filter_input(INPUT_POST, 'spending_category', FILTER_SANITIZE_NUMBER_INT);
$income_category = filter_input(INPUT_POST, 'income_category', FILTER_SANITIZE_NUMBER_INT);
$type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_NUMBER_INT);
$payment_method = filter_input(INPUT_POST, 'payment_method', FILTER_SANITIZE_NUMBER_INT);
$credit = filter_input(INPUT_POST, 'credit', FILTER_SANITIZE_NUMBER_INT);
$qr = filter_input(INPUT_POST, 'qr', FILTER_SANITIZE_NUMBER_INT);
$memo = filter_input(INPUT_POST, 'memo', FILTER_SANITIZE_SPECIAL_CHARS);
$input_time = filter_input(INPUT_POST, 'input_time', FILTER_SANITIZE_SPECIAL_CHARS);
//SQL実行
$sql = 'INSERT INTO records VALUES(0,?,?,?,?,?,?,?,?,?,?,?)';
$stmt = $db->prepare($sql);
$stmt->bind_param('ssiiiiiiiss', $date, $title, $amount, $spending_category, $income_category, $type, $payment_method, $credit, $qr, $memo, $input_time);
//SQLチェック関数
sql_check($stmt, $db);
header('Location: ./index.php');
exit();
それでは実際に入力したデータがデータベースに登録されたか確認しましょう。
カテゴリーやカードなどが数値になっているので少しわかりにくいですが、しっかり登録されました!
最後に
今回はデータベースに接続して、データを登録するところまで実装しました。
次回は現在コードに直接記述しているカテゴリーや選択項目が、DBに登録しているデータと連携するように実装していきます。
最後までお読みいただきありがとうございました。
コメント