8.[PG4]PHPでTODOリスト(csv版)を作ってみよう(xampp & PHP) その3

こちら第8回「プログラマー養成講座」のパート3になります!
目次はこちらからご参照下さい!

HTML宿題提出

ひさびさの宿題、ちゃんと頑張ってきました!
見かけ具合も、できる限り似せてみました!

コードはこんな感じです!

<html>
<head>
<title>WEBページタイトル</title>
<style>

#frame
{
	display: grid;
	grid-template-columns: 140px 1fr;
	justify-content: space-around;
	text-align: center;
}

nav
{
	background-color:#F9CA02;
}

nav>ul>li
{
	text-align:left;
	padding:20px 0;
}

nav>ul>li>a
{
	color:#5C291E;
}

main
{
	background-color:#F17502;
}

main>h2
{
	color:#FFFFFF;
	margin:40px;
	padding:0 30px;
	text-align:left;
	font-size:40px;
}

main>p
{
	background-color:#FFFFFF;
	color:#0000000;
	margin:30px 60px;
	padding:30px;
	text-align:left;
}

</style>
</head>
<body>
<div id="frame">

<nav>
<ul>
<li><a href="index.php">TOP</a></li>
<li><a href="page2.php">HTML</a></li>
<li><a href="page3.php">Javascript</a></li>
<li><a href="page4.php">CSS</a></li>
<li><a href="page5.php">PHP</a></li>
</ul>
</nav>

<main>

<h2>TOP</h2>

<p>
ひさき、計画名SPRINT-A(英語:Small (省略)
</p>

<p>
当初は、2013822日に打上げを予定(省略)
</p>

</main>

</div>
</body>
</html>

なるほど、なるほど。いいですね。
前回はじめてHTMLさわりはじめたのに、きちんとHTML書けていますね。すばらしいです。ここらへんを調べながら書けるようであれば、この先もHTMLについては(調べて)→(書いて)を自走できそうですね。自分で調べて解決する、自走力はプログラミングするのには必要な才能ですよ!

そんな中で、少しだけ修正点を出していきますね。
<title>WEBページタイトル</title>
これは、WEBブラウザのウィンドウ名と、お気に入りに入れたりするときに表示されるテキストになります。基本的にはトップページは「サイト名+サイト説明」で、それ以外のページは「ページ内容|サイト名」みたいな感じで記述します。
まだサイト名を決めていなかったので、できるわけではないところではありますが、それ以外はツッコミ所がないくらい良いということです!

師匠

なるほど、わかりました!
例えば、
<title>ひさきHP</title>
とか
<title>HTML|ひさきHP</title>
って感じですかね?

そうです、その通りですね。
出は今回の宿題は、90点ですね!
初めて触ったHTMLでここまできっちり書けるのは、想定以上でした。

というわけで、本日の本題に入っていきましょう。

師匠

TODOリストとは

まず、TODOリストについて、簡単に説明をしておきます。仕事や家事などで今日やること、明日やるべきことなどを忘れないように「タスク」として登録し、そのタスクが行ったら「チェック」することで仕事の「抜け」や「漏らし」を防止するものがTODOリストです。

本来はTODOリストは、「名前」「備考」「やる人」「期限」などいろいろ付随する情報を登録しますが、今回は「名前」だけ登録し、登録したものに「チェック」する、くらいの機能にしておきます。

師匠

HTMLとPHPの関係性

HTML言語は、WEBページの表示を行うことがメイン処理になります。
PHP言語は、中身の処理をメインに行います。TODOリストで言えばHTMLとPHPの役割は以下のように分けられます。

HTML
・入力フォーム表示①
・TODOリストのフォーム作成④

PHP
・TODOリスト-登録処理②(入力フォームの値を受け取り)
・TODOリスト-チェック処理⑤
・TODOリスト-読込処理③(表示用のHTML作成)

データ内容(list.csv)
・名前/text、チェック/boolean、登録日時/date

WEBページ(WEBサービス)は、このようにプログラム言語でHTMLを作ったり、データ登録処理、データ読取処理をします。上記の①~⑤の順番でプログラミングをしていきます。

師匠

入力フォームの作成①

WEBページでは、データの送信処理は、Formタグを使って行います。Formタグで囲ってある情報のみが送信されます。

<form></form>・・・フォームタグ内のデータを送信します
<input type="text" value="" />・・・テキストボックスです
<input type="submit" value="TODO登録" />・・・登録ボタンです

最初のファイル名は「todo.php」として作成して下さい。
HTMLの例文はこんな感じです。

師匠
<form method="POST" action="./todo-entry.php">
<div>登録名<input type="text" name="todo-name" value="" /></div>
<input type="submit" name="cmd" value="登録する" />
</form>

TODOリスト-登録処理②(入力フォームの値を受け取り)

これからPHPのプログラミングをしていきます。
まず、前項のformタグ内にある
「action="./todo-entry.php"」は、
submitボタンを押し際に表示されるWEBページです。
「todo-entry.php」というファイルを作成してください。
まずは「todo-name」のテキストボックスの値を画面に表示してみましょう。

師匠
<?php
//todo-nameの内容を表示
print $_POST['todo-name'];
?>

表示されましたか? 問題なければ「登録処理」を行います。

llist.csvというファイルにtodo-nameの値を追加書き込みします。
file_put_contents 関数を使います。関数に値を3個渡しますが、

1個目はファイル名になります。list.csv です。
2個目は書き込むデータになります。
 データは「TODO名」「チェックあり/なし」「登録日時」
 「登録日時」は「date('Y/m/d H:i:s')」になります。
 CSVファイルの区切りはカンマ文字とし、改行を「\n」で処理します。
3個目は「FILE_APPEND」になります。
 「FILE_APPEND」を指定することでファイルの操作が「追加」書込みとなります。指定しない場合は「すべて上書き」処理となります。

データはわかりやすいように2,3個入れておきましょう。

師匠
<?PHP
//todo-nameの内容を表示
//print $_POST['todo-name'];

file_put_contents('./list.csv' , $_POST['todo-name'].',no,'.date('Y/m/d H:i:s')."\n" , FILE_APPEND);
?>
登録しました<br />
<a href="todo.php">戻る</a>

TODOリスト-読込処理③(表示用のHTML作成)

todo.php には登録フォームがありますが、
その下にCSVファイルの中身を出力するプログラムを書きます。
書込処理は「file_put_contents」関数を使いましたが、
読込処理は「file_get_contents」関数を使います。
引数は1個でファイル名を入れます。

師匠
<?php
$csv = file_get_contents('list.csv');
print $csv;
?>

TODOリストのフォーム作成④

とりあえず中身の表示はできたでしょうか?
HTMLとして整形していませんので、改行もされずにベタッと1行で出力されています。

これから見やすいように処理をしますが、
CSVファイル内の仕様の理解が大事になってきます。
改行は「\n」で、項目の区切りは「,」ですので、
それをプログラミングで処理をしていきます。

explode関数を使うことで文字を分割できます。
1個目の引数では、分割する区切文字を指定し、
2個目の引数で、操作対象の文字を指定します。

得られる結果は、配列という複数の変数の塊で受け取れます。
データ1個の時は   $lines[0] のみですが、
データ3個の時は、$lines[0]、$lines[1]、$lines[2]のように
同じ変数で連番で割り振られて、変数に格納されます。
この変数は「添字配列」といいます。

師匠
<?php
$csv = file_get_contents('list.csv');
//print $csv;

$lines = explode("\n" , $csv);
foreach($lines as $num => $line)
{
	echo "<div>".$line."</div>\n";
}
?>

これでまずは、行レベルで「\n」で区切ることができ、表示できました。
続いて、項目レベルで「,」で区切っていきます。

師匠
<?php
$csv = file_get_contents('list.csv');
//print $csv;

$lines = explode("\n" , $csv);
foreach($lines as $num => $line)
{
	//echo "<div>".$line."</div>\n";
	if($line)
	{
		$values = explode("," , $line);
		echo "<div>チェック状態".$values[1].' 項目名:'.$values[0].' 登録日時:'.$values[2]."</div>\n";
	}
}
?>

これで見やすくはなってきましたね。ここに登録時と同じようにフォームの機能を追加していきます。

ここらへんから、少しややこしくなってくるかもしれませんが、
落ち着いて1個ずつ、理解して、自分で書きだせばそこまで難しくないと思います。どこかで詰まったり、よくわからなかったら説明しますので手を挙げてください。

まず、フォームとしては以下のような出力を想定しています。
チェック済みのTODOには「☑」だけ表示し、
チェックしていないTODOには「☑」のボタンを表示します。

前のデータ登録ボタンが、チェックボタンになるだけですね。
なお、登録時は「no」で2番目の項目を作っていますが、この位置が該当します。「no」だとチェックボタンを表示し、「yes」だとチェックを表示するだけということです。

<サンプル>
<form method="POST" action="./todo-check.php">
<div><input type="submit" name="chk1" value="no" />TODO名1</div>
<div>yes TODO名2</div>
<div><input type="submit" name="chk3" value="no" />TODO名3</div>
</form>

では、転写だけしていてもつまらないと思いますので、
自分で考えてプログラミングしてみましょうか。
まだ、list.csvファイル内には、yesのデータはないですけど、csvファイルを自分で開いて、2行目のデータのnoをyesに変えて保存して作業してみましょう。

師匠

わかりました、頑張ってみます!
あれ、エラーになるようになっちゃった。
なんだろう・・・

まだ教えていないことが原因でエラーになってるかもしれませんので、
ちょっとトライしてみて、駄目そうなら教えてください。

師匠

わかりました!
(・・・15分経過・・・)
こんな感じでしょうか。

<form method="POST" action="./todo-entry.php">
<div>登録名<input type="text" name="todo-name" value="" /></div>
<input type="submit" name="cmd" value="登録する" />
</form>

<form method="POST" action="./todo-check.php">
<?php
$csv = file_get_contents('list.csv');
//print $csv;

$lines = explode("\n" , $csv);

foreach($lines as $num => $line)
{
	//echo "<div>".$line."</div>\n";
	if($line)
	{
		$values = explode("," , $line);

		if ( $values[1] == 'no' )
		{
			print '<div><input type="submit" name="chk['.$num.']" value="no" />'.$values[0].'</div>';
		}
		else
		{
			print '<div>yes'.$values[0].'</div>';
		}
	}
}
?>
</form>

お、手助けしなくてもどうにかなりましたか。
ちなみにどこでエラーになってました?

師匠

printのところで、ダブルコーテーションとかシングルコーテーションがうまくいってなかったみたいです。

あぁ、なるほど。あそこはHTMLの出力しているコーテーションと、PHPの文字列処理をする際のコーテーションがまざるとわかりにくく難るんですよね。そういうときは行を分割するとかで、解消しやすくなるかもですね。

print '<div><input type="submit" name="chk['.$num.']" value="no" />'.$values[0].'</div>';

print '<div>';
print '<input type="submit" name="chk['.$num.']" value="no" />';
print $values[0];
print '</div>';

こんな感じでしょうか。

師匠

なるほど、確かに。書き方が違っても、結果が同じになるところは、自分がわかりやすいほうが良いということですね。

TODOリスト-チェック処理⑤

では最後に、
さきほどのフォームの処理を実行するプログラミングします。
選択したTODOリストを「no」から「yes」に変更して、
その結果をCSVファイルに上書きするプログラムですね。
実は、新規追って簡単なんです。
既にあるデータの更新ロジックは比べると結構難易度が高いんですよ。

師匠
<?PHP

//更新する行数を変数に格納
$upd_num = '';
foreach($_POST['chk'] as $num => $value)
{
	if ( $value == 'no' )
	{
		$upd_num = $num;
	}
}

//更新する行数が記録されていたら更新処理を開始する
if ( $upd_num !== '' )
{
	//更新用のCSV情報を初期化
	$upd_csv = '';

	//csvファイルを読み込み
	$csv = file_get_contents('list.csv');

	//レコード分割
	$lines = explode("\n" , $csv);
	foreach($lines as $num => $line)
	{
		if($line)
		{
			if ( $num == $upd_num )
			{
				//更新対象の処理
				$values = explode("," , $line);
				$upd_csv .= $values[0].',yes,'.$values[2]."\n";
			}
			else
			{
				//更新対象以外の処理
				$upd_csv .= $line."\n";
			}
		}
	}

	file_put_contents('./list.csv' , $upd_csv);
}
?>
更新しました<br />
<a href="todo.php">戻る</a>

こんなもんでしょうか。これで今回のサンプルプログラム、TODOリストは完成になります。ただ、これはわかりやすぅく書くことを目的にしており、プログラムとしてはいくつかの欠陥があります。

例えば、TODOの項目名にカンマが入らないようにしないといけません。なぜならばレコードの項目をカンマ区切りにしているのですから、項目名に「こうも,くめい」もカンマが入ると
「こうも,くめい,no,日時」として保存してしまうと、
本来「no」か「yes」が入る項目が「くめい」になってしまいます。そうなるとプログラムが想定外の動作をするようになります。いわゆるバグですね。

同様に、ダブルコーテーションやシングルコーテーションも同じく処理をする必要があります。これは表示処理でもXFF(クロスサイトスクリプティング)というWEBの脆弱性をついた攻撃から守るために必要となります。

また、file_put_contentsの処理に、エラー処理をいません。多人数でこのプログラムを使ったときにファイルが壊れる可能性がでてきます。

プログラム研修を終えて一つレベルアップをしたことは確実ですが、まだまだ機能的にもセキュリティ的にも十分なプログラムではないので、これからもレベルアップが必要ということです。

師匠

では、次回はデータベース回となります!!

この記事が気に入ったらサポートをしてみませんか?