掲示板作成

PHP初心者がいきなり掲示板を作ってみた。その3-2(PHP編)

こんにちは!!ライターのTomomiです。

今回は、前回の記事で追加した掲示板で使われているPHPコードを詳しく見ていきたいと思います。

とは言うものの、私はPHPで何かを実践して作ったことがなく、構文を見ても聞いたことがある程度で実際にそれをどういう風に使うのかわかっていないレベルです^^;
なので基礎的なところから書かせていただくこともあると思いますがお許し下さい(汗)

このシリーズの、前回までの記事は以下のページです。

 

掲示板でのPHPの役割

まずは、根本的な問題
掲示板においてPHPはどんな仕事をしてくれているのか??
ということをまずは考えてみたいと思います。

 

php4

php5

PHPでは投稿ボタンが押されてから先の処理(記入された事を読み込んでそれをさらに投稿一覧に書き出す事)をしてくれているのかなと、掲示板の動作からなんとなく想像してみます。
もちろんそれ以外にも細かいことを行ってくれているのかもしれませんが、そこまで細かいことは実際にコードを見てから考えていきたいと思います。

 

掲示板を実装している全コード

以下の黄色くハイライトされている部分は今回見ていく予定のPHPコードです。
前回の記事に引き続き、こちらのページを参考にさせていただいてます。

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link href="keijiban.css" rel="stylesheet" type="text/css" media="all">
<title>掲示板</title>
</head>
<body>
<h1>掲示板</h1>
<section>
    <h2>新規投稿</h2>
    <form action="" method="post">
        <div class="name"><span class="label">お名前:</span><input type="text" name="name" value=""></div>
        <div class="honbun"><span class="label">本文:</span><textarea name="comment" cols="30" rows="3" maxlength="80" wrap="hard" placeholder="80字以内で入力してください。"></textarea></div>
        <input type="submit" value="投稿">
    </form>
</section>
<section class="toukou">
    <h2>投稿一覧</h2>
 <?php if (!empty($rows)): ?>
    <ul>
<?php foreach ($rows as $row): ?>
        <li><?=$row[1]?> (<?=$row[0]?>)</li>
<?php endforeach; ?>
    </ul>
<?php else: ?>
    <p>投稿はまだありません</p>
<?php endif; ?>
</section>
</body>
</html>

見たことあるけどなんか難しそう・・・(・・;)
でも少しずつやっていけばいずれわかっていくはず!!
と自分に言い聞かせて、コードを見ていくことにします。

 

掲示板を構成しているPHPコード前半部分を解読していく

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

一気に見ていくほどの能力はないので、まずはコードの上半分を一つずつ見ていきたいと思います。
また、使われている関数などの一つ一つの詳しい説明は別記事にて後々書いていこうと思っているので、とりあえずここではPHPコードの流れをなんとなく理解することに徹したいと思います。

 

fopen()関数でファイルを開きファイルモードを指定する

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

まずはfopen()関数により、ファイルを開く必要があるようです。

fopen()の書式は
fopen('開きたいファイル名' , 'ファイルオープンモード');です。

この掲示板の場合で行くと、「data.csvファイルをa+bモードで開きなさい」という司令を出していることになります。それを$fpと名前をつけた(名前は自由なので$のあとに自分でわかりやすい名前をつけてOKです)変数に代入しています。

※関数、変数、代入、関数fopen()、ファイルオープンモードについては別記事にて書いていきたいと思います。

 

if($SERVER[‘REQUEST_METHOD’]===’POST’)の意味

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

if($SERVER['REQUEST_METHOD']==='POST')
に関してはとりあえず今は「もしも掲示板に何か書き込みがあれば」という解釈でOKということにしておきます。

もっと深い意味があるのでしょうが、そこまで理解しようとしていたらこの掲示板の構造を解析するのにものすごく時間がかかりそうだったので・・・(汗)

※if文、$_SERVERについては別記事にて書いていきたいと思います。

 

fputcsv()関数でcsvファイルに書き込む

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

fputcsv()については、

「もしも掲示板に何か書き込みがあれば、data.csvファイルに名前と本文を(「名前,本文」の形で)書き込む」という解釈で良いのではないでしょうか。

 

csvファイル

実際csvファイルにはこのような形で書き込まれていきます。

つまり、準備しておいたdata.csvファイルはユーザーさんが投稿してくれた名前とコメントを保存しておく(書き込んでいく)ために必要だったということがわかりました。

「あれ?data.csvなんてファイル名はfputcsv($fp, [$_POST['name'], $_POST['comment']]);のコードの中には書いていないのになぜファイル指定できてるんだろ?」と、またまた初心者の私は足踏みしました。
そういえば一番はじめのコードで$fpに代入していたのをすっかり忘れていました・・・(汗)

また、$_POST['name'], $_POST['comment'][ ]の中の名前はhtmlコードの中のname部分でつけた名前と一致させておく必要があるようです。

<section>
    <h2>新規投稿</h2>
    <form action="" method="post">
        <div class="name"><span class="label">お名前:</span><input type="text" name="name" value=""></div>
        <div class="honbun"><span class="label">本文:</span><textarea name="comment" cols="30" rows="3" maxlength="80" wrap="hard" placeholder="80字以内で入力してください。"></textarea></div>
        <input type="submit" value="投稿">
    </form>
</section>

※fputcsv()関数、$_POSTについては別記事にて書いていきたいと思います。

 

rewind()でファイルポインタを先頭に戻す

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

掲示板に投稿があった場合、data.csvファイルに書き込みが行われるが、書き込みが行われるとファイルポインタというものが終端に移動してしまうため(ファイルオープンモードで指定しているa+は書き込みを行うとファイルポインタを終端に置くため)、このrewind()関数により先頭に戻す必要があるようです。

これは、掲示板の投稿一覧部分に過去に投稿された名前とコメントを表示させるため、最初から読み出す必要があるためではないでしょうか。

 

ファイルポインタのイメージ(図解)

ファイルポインタ

ファイルポインタとは、現在ファイルのどの位置にいるかを示すものらしく、イメージとしては私達がネットで何か検索する時に検索窓で調べる単語などを打っている時に点滅している棒のような感じでしょうか。

「このファイルポインタを取得するためのコードとかってどこに書いてあるの??」
と、謎がまたまた増えましたが、どうやら関数fopen()を使ってファイルを開いた時に自動で取得されているもののようです。

わかるようなわからないような感じですが、とりあえずファイルポインタというのはファイルを扱う時に「次はどこから書き込みを行うか・・・ファイルを読み込むときはどこから読み込むか・・・」などを指定するために必要なものと考えておけば良いのではないでしょうか。

※ファイルポインタについては別記事にて書いていきたいと思います。

 

fgetcsv()関数でcsvファイルを読み込む作業をwhile文で繰り返す

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

fgetcsv()関数により、csvファイル(ここではdata.csv)一行を配列という形で読み込み、それを$rowに代入します。
そしてそれを更に$rowsに代入します。($rowsは2次元配列になっています)
この一連の流れを、while文により繰り返していきます。

そして取り出すものがなくなったら(data.csvファイルに書き込まれているデータを全て取り出し終わったら)繰り返しを終わります。

 

2次元配列のイメージ(図解)

二次元配列

まずは$row = fgetcsv($fp)の部分です。
data.csvに書き込まれている一行目を配列という形で取り出します。($rowという箱に格納されるイメージ)

※配列として取り出されたデータになぜ[0]や[1]という番号がついているかも配列についての別記事にて書いていきたいと思います。

 

二次元配列

そして、図①で配列として取り出されたデータをさらに$rowsというに格納します。
このような、配列の中に配列が入っている状態を二次元配列と言うようです。

図②が終わったらまた図①に戻り同じことをデータを全て取り出すまで繰り返します。

 

二次元配列

この場合だと、最終的な$rowsの箱の中身のイメージはこのような感じではないでしょうか。
なぜ2次元配列にする必要があるのか・・・わからない・・・。

今の現段階では2次元配列にする意味も、使い方も私には理解できていませんが、もう少し先に進むとわかってくるかも・・・と信じてここは先に進むことにします。

※fgetcsv()関数、配列、二次元配列、while文については別記事にて書いていきたいと思います。

 

fclose()でファイルを閉じる

<?php
$fp = fopen('data.csv', 'a+b');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    fputcsv($fp, [$_POST['name'], $_POST['comment']]);
    rewind($fp);
}
while ($row = fgetcsv($fp)) {
    $rows[] = $row;
}
fclose($fp);
?>

初心者の私は気をつけなければなりません。
fopen()で何かファイルを開いたら、最後はfclose()でファイルを閉じるのを忘れずに・・・。
このfclose()は省略もできるようなのですが、私は素人らしく慣れるまでは基本に忠実に記述しておくことにします(汗)

 

掲示板を構成しているPHPコード後半部分を解読していく

 <?php if (!empty($rows)): ?>
    <ul>
<?php foreach ($rows as $row): ?>
        <li><?=$row[1]?> (<?=$row[0]?>)</li>
<?php endforeach; ?>
    </ul>
<?php else: ?>
    <p>投稿はまだありません</p>
<?php endif; ?>

いよいよ後半戦・・・。
わかったような、わかっていないような感じでここまで来てしまいました(汗)
いよいよここから、掲示板に投稿された本文と名前を表示していく動作が入ってくるかと思います。

あと少し!!

 

empty()で変数が空かどうかを調べる

 <?php if (!empty($rows)): ?>
    <ul>
<?php foreach ($rows as $row): ?>
        <li><?=$row[1]?> (<?=$row[0]?>)</li>
<?php endforeach; ?>
    </ul>
<?php else: ?>
    <p>投稿はまだありません</p>
<?php endif; ?>

empty()は、指定した変数が空かどうかを調べてくれます。
つまりこの場合だと、$rowsの中にユーザーから投稿された本文や名前があるかどうかを調べます。
さらに、emptyの文字の先頭に!がついています。
これは「否定」を表すので解釈としては、「もしも$rowsの中身が空ではない場合は以下の動作を行う」という感じで良いのではないでしょうか。

 

foreach文で配列の値を取り出し本文と名前を表示する

 <?php if (!empty($rows)): ?>
    <ul>
<?php foreach ($rows as $row): ?>
        <li><?=$row[1]?> (<?=$row[0]?>)</li>
<?php endforeach; ?>
    </ul>
<?php else: ?>
    <p>投稿はまだありません</p>
<?php endif; ?>

foreach文は配列の値を先頭から自動で取り出します。
配列の要素の数だけ繰り返します。
ちなみにこの要素というのは、先ほど「2次元配列のイメージ」でお話した「」一つ一つのことを指しているようです。

書式は
foreach(配列 as 要素の値を格納する変数){
実行する処理;
}
となります。

 

foreach文

配列の要素の値(ここでは$rowsの値)を変数(ここでは$row)にコピーして代入するようです。

※配列の要素を取り出すわけではなく、変数にコピーするだけなのでそこは注意です!!
繰り返しが一回行われると、また次の値を変数$rowに代入して・・・というように、配列の要素の数の分だけ繰り返されます。(図の①コピー→②表示を要素の数だけ繰り返します。

 

echoを省略するコードの書き方

・本文(名前)の形で表示するという命令を出しているコードは
<li><?=$row[1]?>(<?=$row[0]?>)</li>にあたります。「あれ?echoという文字がないのにどうやって表示しているんだろう?」と疑問でした…。

確かphpでは、画面に文字などを出力したいときはechoもしくはprintと記入しなければいけなかったはず…。
実はこのechoを省略して書くことが出来るようです。

実際私が教科書などで覚えた書き方だと以下のコードになります。
<?php echo $row[1]; ?>
そしてechoを省略する書き方は以下のようになります。
<?=$row[1]?>

 

endforeachでforeach文の波括弧「{}」を省略する

endforeachなんて初めて見ました・・・。

endforeach

調べてみたところ、このendforeachを使うことでforeach文の書式で記載した波括弧{}を省略し、その代わりに開波括弧{:に、閉波括弧}endforeach;に置き換えて書くことが出来るようです。

※要素・foreach文に関しては別記事にて書いていきたいと思います。

 

ユーザーからの書き込みがなかった場合の処理をelse以降に書く

 <?php if (!empty($rows)): ?>
    <ul>
<?php foreach ($rows as $row): ?>
        <li><?=$row[1]?> (<?=$row[0]?>)</li>
<?php endforeach; ?>
    </ul>
<?php else: ?>
    <p>投稿はまだありません</p>
<?php endif; ?>

先ほどまでは、ユーザーさんからの掲示板への書き込みがあった場合の処理をしてきました。

ここからは、書き込みが一切ない場合の処理になっていきます。
掲示板への書き込みが全くない場合は、掲示板の投稿一覧の下に「投稿はまだありません」と表示されるようにしています。
その処理をelse以降に記載しています。

 

endifでif文の波括弧「{}」を省略する

私が参考にした本のif文の書式では
if(条件){
条件が当てはまれば(真であれば)実行
}else{
条件が当てはまらなければ(偽であれば)実行
}
となっていました。
これを以下のように書くことも出来るようです。
if(条件):
条件が当てはまれば(真であれば)実行
else:
条件が当てはまらなければ(偽であれば)実行
endif;

 

セキュリティについて

やっと終わった~!!
なんて、そんな甘くはないですよね・・・。

 

掲示板のある程度の形はこれで完成かと思います。
ただこれではまだセキュリティに関しての問題がいろいろあるようで・・・。
今の私にはかなり難しそうな内容です(泣)

 

今回掲示板の構造について勉強しましたが、痛感したことがあります。
それは、phpにおける基礎知識があまりにも乏しかったということ・・・。
ですので、セキュリティのコードを追加していく前に一旦掲示板作成を中断して、phpの基礎知識を最低限勉強してから「掲示板作成(セキュリティ編)」に入りたいと思います。

 

ということで少しの間は基礎知識の記事を書いていこうと思っています。
下手くそな図解と説明にお付き合い頂きありがとうございました。
これからも頑張っていきたいと思います!!

 



The following two tabs change content below.
Tomomi
Tomomi
今までWebの世界には全く無縁だった超アナログ人間。 無謀にもWebの世界で生きていくことを決意。 ハムスターと柴犬好きの文系女子です。 最終的にはプログラミングが一人で出来るレベルになることが目標です。 がんばりま~す!!