(おそらく)私が一番まともに作っているMy-ToDoの詳細
こんにちは。ねこがくれです。
今日は私が頑張って作っているウェブアプリのMy-ToDoというソフトウェアの詳細や、苦労したところ、学んだところなどを書いていこうと思います。
使用しているものたち
- php(バックグラウンド処理全般)
- json(データ保管)
- css(デザイン)
- JS(ほとんどサービスワーカー)
- html(当たり前)
見ての通りDBは未使用です。なぜか?まぁ、なんでか私でもあまりわからないです。
今から一つ言えることは絶対DBで管理したほうが良かったな、ということです。
なぜjsonで管理しているか
おそらく(記憶が定かではないのでおそらく)私の主に使っている無料レンタルサーバーのDB作成数が5個なので、もうDBを作成できないとかそんな理由だった気がします。
どちらにせよ、セキュリティの観点からもあまりよろしくないデータの管理の仕方だと思います。(.htaccessなどでアクセス不可にはしています)
あと、開発開始したのが中学1年になってすぐなのでSQLが不得手だった、というのも理由にあると思います。
→今から再度同じものを作るならちゃんとDBを使おうと思います。
phpを書くうえで
まず、下のコードを見てください。(実際にtodoとしての処理をしているところ)
<?php
ini_set('display_errors', 0);
error_reporting(0);
include('../../header.php');
?>
<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
include('check.php');
// ログインしていない場合、login.php にリダイレクト
session_start();
// ユザネがセッションにセットされていない場合、ログイン画面にリダイレクト
if (!isset($_SESSION['username'])) {
header("Location: ../../index.php");
exit();
}
// 現在アクセスしているURLを取得
$current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
// 指定された部分を取り除く
$base_url = GetPageURL() . "/";
$access_dir = str_replace($base_url, "", $current_url);
// $ACCESS_DIR に格納
$ACCESS_DIR = $access_dir;
if (str_ends_with($ACCESS_DIR, '/index.php')) {
$ACCESS_DIR = substr($ACCESS_DIR, 0, -10);
}
try {
// ユーザーディレクトリを指定してバージョン確認
version_check($ACCESS_DIR);
} catch (Exception $e) {
echo 'エラー: ' . $e->getMessage();
}
if(!($_SESSION['dir'] . '/' == $ACCESS_DIR)) {
die("アクセス権がありません");
}
// HTMLタグの入力を無効にし、文字コードをutf-8にする
function h($v) {
return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
}
include('./WEBHOOK/index.php');
// 変数の準備
$FILE = 'todo.txt'; // 保存ファイル名
$ARCHIVE_FILE = 'archive.txt'; // アーカイブ用のファイル
$id = uniqid(); // ユニークなIDを自動生成
// タイムゾーン設定
date_default_timezone_set('Japan');
$date = date('Y年m月d日H時i分'); // 日時(年/月/日/ 時:分)
$text = ''; // 入力テキスト
$tag = ''; // タグ
$comment = ''; // コメント
$commentIndex = ''; // 削除するコメントのインデックス
$DATA = []; // 一回分の投稿の情報を入れる
$BOARD = []; // 全ての投稿の情報を入れる
// $FILEというファイルが存在しているとき
if (file_exists($FILE)) {
// ファイルを読み込む
$BOARD = json_decode(file_get_contents($FILE), true); // trueで配列として取得
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 新規タスク追加
if (!empty($_POST['txt'])) {
$text = $_POST['txt'];
$tag = isset($_POST['tag']) ? $_POST['tag'] : ''; // タグを取得
// 新規データ
$DATA = [$id, $date, $text, false, [], $tag]; // タグを含める
$BOARD[] = $DATA;
file_put_contents($FILE, json_encode($BOARD));
// archive.txtにも保存
$archiveData = $DATA; // 同じデータを使う
$archiveBoard = [];
if (file_exists($ARCHIVE_FILE)) {
$archiveBoard = json_decode(file_get_contents($ARCHIVE_FILE), true);
}
$archiveBoard[] = $archiveData;
file_put_contents($ARCHIVE_FILE, json_encode($archiveBoard));
sendLine("新規タスクが追加されました。", $text); // タスクの内容も一緒に送信
echo "新規タスクが追加されました";
}
if (isset($_POST['del'])) {
$NEWBOARD = [];
foreach ($BOARD as $DATA) {
if ($DATA[0] !== $_POST['del']) {
$NEWBOARD[] = $DATA;
}
}
file_put_contents($FILE, json_encode($NEWBOARD));
sendLine("タスクが削除されました。", $DATA[2]); // 削除されたタスクの内容を送信
echo "タスクが削除されました";
}
if (isset($_POST['done'])) {
foreach ($BOARD as &$DATA) { // $DATAは参照で扱う
if ($DATA[0] === $_POST['done']) {
$DATA[3] = !$DATA[3]; // 完了状態を反転させる
// 完了または未完了のメッセージを送信
if ($DATA[3]) {
sendLine("タスクが完了しました。", $DATA[2]); // 完了メッセージ
echo "タスクが完了しました";
} else {
sendLine("タスクが未完了に戻されました。", $DATA[2]); // 未完了に戻されたメッセージ
echo "タスクが未完了に戻されました";
}
}
}
file_put_contents($FILE, json_encode($BOARD));
}
// コメントの追加処理
if (isset($_POST['comment_text']) && isset($_POST['comment_id'])) {
$comment = $_POST['comment_text'];
$comment_id = $_POST['comment_id'];
foreach ($BOARD as &$DATA) {
if ($DATA[0] === $comment_id) {
if (!isset($DATA[4])) {
$DATA[4] = []; // コメント配列が存在しない場合は空の配列を初期化
}
$DATA[4][] = $comment; // コメントを追加
}
}
file_put_contents($FILE, json_encode($BOARD));
}
// コメントの削除処理
if (isset($_POST['comment_delete_id']) && isset($_POST['comment_index'])) {
$comment_delete_id = $_POST['comment_delete_id'];
$comment_index = $_POST['comment_index'];
foreach ($BOARD as &$DATA) {
if ($DATA[0] === $comment_delete_id) {
if (isset($DATA[4][$comment_index])) {
unset($DATA[4][$comment_index]); // コメントを削除
$DATA[4] = array_values($DATA[4]); // インデックスをリセット
}
}
}
file_put_contents($FILE, json_encode($BOARD));
}
// ページをリダイレクトしてリロード
// header('Location: ' . $_SERVER['SCRIPT_NAME']);
header('Location: ./');
exit;
}
?>
このコード、だめなところ多すぎですよね。今から思うとよくこれで動いたなと思います。
このコードのだめなところ
- XSS対策をしていない
- (これ指摘しちゃうと根本を否定することになりますが)JSONでデータを管理しているところ
- CSRF対策がほとんどされていない
- Sessionの有効期限や再生成がない
- 「読みづらい。滅茶苦茶。」
-
$FILE
などで直接ファイルを埋め込んでいる。 -
if (isset(...))
見づらい! - エラーハンドリングがほとんどない
…とまぁ、自分でもこんなに欠点が見つかるような駄目コードです。
悪いコードの参考にしていただけたら嬉しいです。(ですが、少しずつ改善していっています)
CSSで頑張ったところ
次にCSSを書くうえで大変だったことを書こうと思います。
- ヘッダーに
include()
を使ってるのでinclude先のcssが適用されてしまう - そもそもとしてデザインができない
1は、!inportant
属性やidを駆使してなんとかしました。
2はまぁ、ChatGPTくんに
「My ToDoというソフトのデザインを考えて文字にしてください」
と適当に投げかけたらすぐに出してくれました。
ほんとにすごいと思います。(おかげでボックスを駆使したおしゃれ?なデザインにできた)
結構頑張ったデザイン
最後に
とても薄くとても参考にできるような内容だとは思えないです、、。すみません。ですが、結構頑張ったソフトなので一度使ってみてくださると嬉しいです!
最後まで読んでくださりありがとうございます。
Discussion
今から思うとほんとになんでjsonでやったんだろうなという思いでいっぱいです…。DBの数減らせばよかった