掲示板サンプル(ファイル保存)

2003-3-8現在使っている(すでにもうない)スカトロセカンドのBBSを紹介します。
以前はデータベースに書き込み記事を保存していたのですが、今回はファイルに保存します。
今回の仕様は以下の通り

・ 入力項目は名前、メールアドレス、ホームページアドレス、メッセージの4項目。名前、メッセージは入力必須項目
・ レスはできない。
・ 1ページに表示させる記事は10まで。
・ エラーページはなし。
・ 管理者しか記事を消せない。編集はできない。
・ 表示部分と、書き込み部分を分ける。

いままでのから作り変えるのがめんどくさかったので、かなり簡単な仕様になってしまいました。

ではまず、記事を書き込むところから。
書き込みフォームのHTML 表示、ソースは一部抜粋 (完全なソースを見たい方は実際のBBSのソースを見てください)




<form name="form1" method="post" action="bbs_write.php">
<table width="750" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<table width="700" border="0" cellspacing="0" cellpadding="0" align="right">
<tr>
<td width="30%">
<div align="right">名前</div>
</td>
<td width="2%"> </td>
<td>
<input type="text" name="name" class="form_st" size="40">
</td>
</tr>
<tr>
<td width="30%"> </td>
<td width="2%"> </td>
<td> </td>
</tr>
<tr>
<td width="30%">
<div align="right">MAIL</div>
</td>
<td width="2%"> </td>
<td>
<input type="text" name="mail" class="form_st" size="50">
</td>
</tr>
<tr>
<td width="30%">
<div align="right"></div>
</td>
<td width="2%"> </td>
<td> </td>
</tr>
<tr>
<td width="30%">
<div align="right">URL</div>
</td>
<td width="2%"> </td>
<td>
<input type="text" name="url" class="form_st" size="50">
</td>
</tr>
<tr>
<td width="30%">
<div align="right"></div>
</td>
<td width="2%"> </td>
<td> </td>
</tr>
<tr>
<td width="30%">
<div align="right">メッセージ</div>
</td>
<td width="2%"> </td>
<td>
<textarea name="message" class="form_st" cols="50" rows="10"></textarea>
</td>
</tr>
<tr>
<td width="30%"> </td>
<td width="2%"> </td>
<td> </td>
</tr>
<tr>
<td colspan="3">
<div align="center">
<input type="submit" name="submit" value="カキコ" class="form_st">
 
<input type="reset" name="submit2" value="リセット" class="form_st">
</div>
</td>
</tr>
<tr>
<td colspan="3"> </td>
</tr>
<tr>
<td colspan="3"> </td>
</tr>
<tr>
<td colspan="3" bgcolor="#FFFFFF"><img src="img/spe.gif" width="1" height="1"></td>
</tr>
</table>
</td>
</tr>
</table>
</form>
 

フォームの飛び先は bbs_write.php です。

bbs_write.php


<?
$datafile = "bbs.dat"; //保存ファイル
 
//--------タグ変換
if($name == ""){
 header("Location: bbs.php");
 exit;
}else{
 $name = Notag2($name);
}
if($mail != "") $mail = Notag2($mail);
if($url != "") $url = Notag2($url);
if($message == ""){
 header("Location: bbs.php");
 exit;
}else{
 $message = Notag($message);
}
 
//-------日付取得
$hi = date("Y/m/d H:i:s");
 
//-------ファイルカキコデータ生成
$file_kakiko = $hi . "\t";
$file_kakiko .= $name . "\t";
$file_kakiko .= $mail . "\t";
$file_kakiko .= $url . "\t";
$file_kakiko .= $message . "\n";
 
//------------☆いったん読み込み☆--------------
$fpa = file($datafile);
reset($fpa);
array_unshift ($fpa, $file_kakiko);
 
//------------☆書き込み☆--------------
$fp = fopen($datafile, "w");
reset($fpa);
while ($a = each($fpa)) {
 fputs($fp,$a[1]);
}
fclose ($fp);
 
header("Location: bbs.php");
exit;
 
//-------タグ置換ルーチン
 
function Notag($mozi)
{
$strr = $mozi;

$strr = ereg_replace("&", "&amp;", $strr);
$strr = ereg_replace("<", "&lt;", $strr);
$strr = ereg_replace(">", "&gt;", $strr);
$strr = ereg_replace("\"", "&quot;", $strr);
$strr = ereg_replace("\r\n", "<br>", $strr);

return $strr;
}
 
//-------タグ置換ルーチン2
 
function Notag2($mozi)
{
$strr = $mozi;

$strr = ereg_replace("&", "", $strr);
$strr = ereg_replace("<", "", $strr);
$strr = ereg_replace(">", "", $strr);
$strr = ereg_replace("\"", "", $strr);

return $strr;
}
?>
 

最初で保存先のファイルを指定しています。
bbs.datが書き込みを記録するファイルなので、あらかじめ、0バイトのbbs.datを同じディレクトリに用意しておく必要があります。その際、書き込み権限をつけておきます。

その後、フォームから渡ってきたデータを、タグ変換ルーチンに掛けています。名前とメッセージだけは変数の中身が空だと、そのまま bbs.php(これから説明する表示部分のPHP)に飛ばしています。

そして、ファイルに書き込むデータとしてタブ区切りにして生成し、一度、既に書き込まれているデータを配列として読み込み、その配列に今生成した、データを配列の一番最後に追加しています。
array_unshift ($fpa, $file_kakiko);
これは、配列$fpaの最後に$file_kakikoを追加するというコマンドです。
reset($fpa);
は、配列のポインタを先頭にするというコマンドです。

読み込んで、配列に追加したら、改めてファイルに書き込みます。

1.$fp = fopen($datafile, "w");
2.reset($fpa);
3.while ($a = each($fpa)) {
4. fputs($fp,$a[1]);
  }
5.fclose ($fp);


1.ファイルを書き込み属性で開き、
2.既に読み込んである、もとの書き込みデータのポインタを先頭に戻し
3.2のデータを一行ずつ読み込み
4.ファイルに書き込む
5.ファイルをクローズする。

というような手順です。
書き込みが終わったら、bbs.php リダイレクトしています。

ではメインの表示する部分です。



管理者モードの画面


ソースは下記です。
見にくくなるので一部HTML部分は取っ払ってあります。

bbs.php


<?php
 
---------------------------------------------A
$datafile = "bbs.dat"; //保存ファイル
$kanri_id = "id";
$kanri_pass = "pass";
 
//------------☆管理者モード☆--------------
if($id != "" and $pass != ""){
 if($id == $kanri_id and $pass == $kanri_pass){
  $kanri_flag = "kanri";
 }
}
 
---------------------------------------------B
//------------☆管理者削除モード☆--------------
if($kanri_frag == "kanri2"){
if($del != ""){
//------------いったん読み込み
$fpa = file($datafile);
reset($fpa);
 
//------------書き込み
$fp = fopen($datafile, "w");
reset($fpa);
while ($a = each($fpa)) {
 $get = split ("\t",$a[1]);
 if($get[0] != $del){
  fputs($fp,$a[1]);
 }
}
fclose ($fp);
header("Location: bbs.php");
exit;
}
}
 
---------------------------------------------C
if($min_page == ""){
$min_page = 0;
}
 
---------------------------------------------D
$fpa = file($datafile);
reset($fpa);
 
?>
<html>
 
<!-- HTMLヘッダー部分 -->
 
<br>
<br>
---------------------------------------------E
<? if($kanri_flag == "kanri"){ ?>
<form name="form1" method="post" action="bbs.php">
<table width="750" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<table width="700" border="0" cellspacing="0" cellpadding="0" align="right">
<tr>
<td>
<div align="center">
<input type="submit" name="submit" value="デリ" class="form_st">
<input type="hidden" name="kanri_flag" value="kanri2">
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br>
<? } ?>
 
<?
---------------------------------------------F
for($i=0;$i<10;$i++){
$j=0;
while($j<$min_page){
 next($fpa);
 $j++;
}
if ($a = each($fpa)) {
 $get = split ("\t",$a[1]);
?>
 
<table width="750" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<table width="700" border="0" cellspacing="0" cellpadding="0" align="right">
<tr>
<td width="25%" valign="top">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#FFFFFF">
<table width="100%" border="0" cellspacing="1" cellpadding="0">
<tr>
<td bgcolor="#000000" height="100">
---------------------------------------------G
<? if($kanri_flag == "kanri"){ ?>
デリ<input type="radio" name="del" value="<?=$get[0]?>">
<? } ?>
---------------------------------------------H
<div align="right"><?=$get[1]?><br>
<br>
<?=$get[0]?><br>
<br>
<?
if($get[2]!=""){
print "<a href=\"mailto:". $get[2] ."\">";
}
?>
MAIL
<?
if($get[2]!=""){
print "</a>";
}
?>
<br>
<br>
<?
if($get[3]!=""){
print "<a href=\"". $get[3] ."\">";
}
?>
URL
<?
if($get[3]!=""){
print "</a>";
}
?></div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
<td width="2%"> </td>
<td valign="top">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td bgcolor="#FFFFFF">
<table width="100%" border="0" cellspacing="1" cellpadding="2">
<tr>
<td bgcolor="#000000" height="100" valign="top"><?=$get[4]?></td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<br>
<br>
---------------------------------------------I
<? }else{
$check_page = "no_next";
bleak;
} ?>
<? } ?>---------------------------------------------F’
<? if($kanri_flag == "kanri"){ ?>
</form>
<? } ?>
<table width="750" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
---------------------------------------------J
<? if($check_page != "no_next"){ ?>
<div align="right"><a href="bbs.php?min_page=<?=$min_page + 10?>"><img src="img/bbs_bo_next.gif" width="133" height="17" border="0"></a></div>
<? } ?>
</td>
</tr>
</table>
<br>
<br>
<br>
<table width="750" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<div align="right">
<table width="700" border="0" cellspacing="1" cellpadding="0" align="right">
<tr>
<td>
<div align="right">
---------------------------------------------K
<form name="form1" method="post" action="bbs.php">
<hr>
<input type="text" name="id" size="5" class="form_st">
<input type="text" name="pass" size="5" class="form_st">
<input type="submit" name="submit" value="管理者" class="form_st">
</form>
</div>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
<br>
<br>
</body>
</html>
 

---------------------------------------------A
ここでは管理者ID、パスワードを設定しています。
管理者フォームから送られてきた、IDとパスワードを照らし合わせて、OKなら$kanri_flagにkanriという値をセットしています。
この $kanri_flag に kanri がセットされていれば、管理者モードなんだなということになります。

---------------------------------------------B
管理者ID、パスワードを入力して管理者ボタンを押すと、上の図の管理者モードの画面という画面に入ります。
ここで、削除したい記事にチェックしてデリボタンを押した先がこのBになります。
管理フラグが立っていて、なおかつ、変数 $del に値が入っている場合にここの処理がされます。

$del には、日付がセットされます。今回記事を削除する際に、記事を特定するためのキーは日付を使います。

記事の削除の仕方は、登録とほぼ同じです。
一度記事を全て読み込み、書き込む際に、もし$del の値と同じ値だったら書き込まないという処理をします。

1.while ($a = each($fpa)) {
2. $get = split ("\t",$a[1]);
3. if($get[0] != $del){
4.  fputs($fp,$a[1]);
   }
  }

1.まとめて読み込んだ記事($fpa)を一行ずつ繰り返し、
2.一行をさらに、タブで分割して、項目ごとに分け、
3.$get[0] (日付) と $del (削除で選択した日付)が同じでなければ
4.ファイルに書き込む

---------------------------------------------C
ページ数を設定しています。
$min_page には現在の最小の記事ナンバーが入ります。

例えば、今回は10記事ずつ表示するので、
1ページ $min_page = 0
2ページ $min_page = 10
3ページ $min_page = 20
となります。

最初にこの bbs.php にアクセスしてきた場合は当然、$min_page には何も入っていないので、何もは一定なければ 0 を入れるというふうにしています。

---------------------------------------------D
記事を表示するために、ファイルから読み込んでいます。

---------------------------------------------E
管理者モードの時の表示です。
デリボタンを表示しています。

---------------------------------------------F
---------------------------------------------F’

1ページに表示する記事数を、調整しています。F〜F’の間をFor文でループして記事を表示しています。

1.for($i=0;$i<10;$i++){
2.$j=0;
3.while($j<$min_page){
4. next($fpa);
5. $j++;
  }


1.10回繰り返し
2.変数を初期化
3.$j が $min_page より小さい間くりかえす。
4.ポインタをひとつ進める

具体的にどういうことかというと、1ページ目では$min_pageは0なので、3.のwhile文は実行されません。
2ページ目から$min_pageが0以上になるので、実行されるのです。これは、2ページ目は11番目の記事から10つ表示してたいので、そのぶん$fpaのポインタを11番目に合わせてあげないといけないためです。

if ($a = each($fpa)) {
 $get = split ("\t",$a[1]);


ポインタの部分から一行ずつ読み込んで、タブで分割して$getの配列に入れています。

---------------------------------------------G
管理者フラグが立っていれば、ラジオボタンをつけています。ラジオボタンdelの値はその記事の日付をセットしています。

---------------------------------------------H
実際記事を表示する部分です。
Fで $get の配列に記事を入れました。$get 配列には以下のように記事がセットされています。

$get[0] = 日付
$get[1] = 名前
$get[2] = メールアドレス
$get[3] = URL
$get[4] = メッセージ


---------------------------------------------I
Fの if ($a = each($fpa)) { に対応する else文です。
For文で繰り返しているとき、ポインタが次に進めなくなったら、elseの中の処理になります。
if ($a = each($fpa)) { の意味が、変数に代入して、ポインタが次に進めたら、なのでelseはその逆となります。

$check_page に no_next をセットして、For文を break で抜けています。

---------------------------------------------J
$check_page に no_next がセットされていなければ、次へボタンを表示します。
つまり、1ページに収まりきらない(10記事以上)なら、I の処理がなされないので、ボタンが表示されるというわけです。

そのNEXTボタンには、
<a href="bbs.php?min_page=<?=$min_page + 10?>">

のように、現在の最小記事ナンバーに10を足されて、リンクを張られます。

---------------------------------------------K
管理者ID,パスワード入力フォームです。