質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

20071閲覧

PHP・簡易掲示板の削除機能について

saki_program

総合スコア31

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

1クリップ

投稿2015/03/03 08:35

PHPを使って簡易掲示板を作成しております。
下記コードにて1行投稿は行えるのですが、
削除番号を指定して、投稿を削除できる機能がうまく書けません。
どのように書き直したらよいか、ご回答をお願いします。

lang

1コード 2<?php 3 4$dataFile = 'bbs.dat'; 5 6function h ($s) { 7 return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); 8} 9 10 11if(isset($_POST['toukou'])){ 12 13 $lines = file('bbs.dat'); 14 $cnt = count($lines); 15 $cnt += 1; 16 17 $message = $_POST['message']; 18 $user = $_POST['user']; 19 $time = date("Y/m/d H:i:s"); 20 21 22 $newData = "{番号}"."<".$cnt.">"."\t"."{名前}"."<".$user.">"."\t"."{コメント}"."\n"; 23 24 $fp = fopen($dataFile, 'a'); 25 fwrite($fp, $newData); 26 fclose($fp); 27 28 } 29 30$posts = file($dataFile, FILE_IGNORE_NEW_LINES); 31$posts = array_reverse($posts); 32 33if (isset($_POST['delete'])) { 34 for ($i = 0; $i < count($lines); $i++) { 35 $items = explode("\t", $lines[$i]); 36 if ($items[0] == $_POST['delno']) { 37 array_splice($lines, $i, 1); 38 } 39 } 40} 41 42 43?> 44 45<!DOCTYPE html> 46 <html lang="ja"> 47 <head> 48 <meta charset="UTF-8"> 49 <title>簡易掲示板</title> 50 </head> 51 <body> 52 <h1>簡易掲示板</h1> 53 <form action="" method="post"> 54 名前:<input type="text" name="user"> 55 コメント:<input type="text" name="message"> 56 <input type="submit" name="toukou" value="投稿"> 57 </form> 58 <form method="post" action=""> 59 削除指定番号:<input type="text" name="delno"> <input type="submit" name="delete" value="削除"> 60 </form> 61 <h2>投稿一覧 (<?php echo count($posts); ?>件)</h2> 62 <ul> 63 <?php if (count($posts)): ?> 64 <?php foreach ($posts as $post): ?> 65 <?php list($cnt, $user, $message, $time) = explode("\t", $post); ?> 66 <li><?php echo h($cnt); ?> <?php echo h($user); ?></li> 67 <?php endforeach ?> 68 <?php else: ?> 69 <li>まだ投稿はありません。</li> 70 <?php endif; ?> 71 </ul> 72 </body> 73 </html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

あなたのコードをできるだけ尊重して実装してみました。
全投稿件数の取得と、投稿番号の連番を両立するため、
削除があったレコードは空行にしてあります。

<?php $dataFile = 'bbs.dat'; function h($s) { return htmlspecialchars($s, ENT_QUOTES, 'UTF-8'); } if (isset($_POST['toukou'])){ $lines = file('bbs.dat'); $cnt = count($lines); $cnt += 1; $message = $_POST['message']; $user = $_POST['user']; $time = date("Y/m/d H:i:s"); $newData = "{番号}" . "<" . $cnt . ">" . "\t" . "{名前}" . "<" . $user . ">" . "\t" . "{コメント}" . "<" . $message . ">" . "\t" . $time . "\n"; write($dataFile, $newData, "a"); } $posts = file($dataFile, FILE_IGNORE_NEW_LINES); $posts = array_reverse($posts); if (isset($_POST['delete'])) { for ($i = 0; $i < count($posts); $i++) { $items = explode("\t", $posts[$i]); if($items[0] == "{番号}<{$_POST['delno']}>") { $posts[$i] = ""; } } $newData = array_reverse($posts); $newData = implode("\n", $newData) . "\n"; write($dataFile, $newData, "w"); } $all_posts = count($posts); foreach($posts as $post) { if(empty($post)){ $all_posts--; } } function write($dataFile, $newData, $mode) { $fp = fopen($dataFile, $mode); fwrite($fp, $newData); fclose($fp); } ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>簡易掲示板</title> </head> <body> <h1>簡易掲示板</h1> <form action="" method="post"> 名前:<input type="text" name="user"> コメント:<input type="text" name="message"> <input type="submit" name="toukou" value="投稿"> </form> <form method="post" action=""> 削除指定番号:<input type="text" name="delno"> <input type="submit" name="delete" value="削除"> </form> <h2>投稿一覧 (<?php echo $all_posts; ?>件)</h2> <ul> <?php if (count($posts)): ?> <?php foreach ($posts as $post): ?> <?php if (empty($post)) continue; ?> <?php list($cnt, $user, $message, $time) = explode("\t", $post); ?> <li><?php echo h($cnt); ?> <?php echo h($user); ?> <?php echo h($message); ?></li> <?php endforeach ?> <?php else: ?> <li>まだ投稿はありません。</li> <?php endif; ?> </ul> </body> </html>

投稿2015/03/03 14:36

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saki_program

2015/03/04 10:09

luckerさん  コード有難うございます。すごく助かりました。 写経だけでは自分の力にならないのですが、それぞれのコードの意味をしっかりと理解するようにします。 また質問スレ上げると思うので、ぜひ今後とも宜しくお願いします。
退会済みユーザー

退会済みユーザー

2015/03/04 10:43

このコードでは削除レコードを空にしていますが、 せっかくですからit_solution_labさんの言っているフラグを持たせて 削除レコードを残すように改変してみてはどうでしょう? その辺の改変も簡単にできるようなコードにしたつもりです。 最初はみんなちょっとしたことで迷宮に入ってしまうので、 めげない、あきらめない、あせらない、で続けていっていただけたら嬉しいですね。
saki_program

2015/03/04 11:05

luckerさん 課題まで頂けて嬉しいです。また自分で調べながら挑戦してみますね^^
guest

0

fopen の 'a' は追記ですから、
後ろに追加することはできても、途中は削除できないのでは?

削除時は、別途添付ファイルに元の "bbs.dat" を複写しながら、削除対象の行だけ
複写しないで、書き込んで、終わったら bbs.dat に上書きする。

というのではどうでしょうか?

ちなみに、これらBBSデータをテキストファイルで管理した場合、
ファイルが壊れたりもしますけど・・・

削除処理をやってる間に追加されたり、とかそういったことについての
考慮は、別途工夫されたりしている、ということですよね?

複数が同時に削除にいったり、複数の人が書き込んだり、

投稿2015/03/03 09:10

it_solution_lab

総合スコア71

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saki_program

2015/03/03 10:57

ご回答ありがとうございます。 環境はローカルのテスト環境のみで行います。 fopen の 'a' は,'a' のままにしないと連番で新しく投稿できないので変えることができないと思ってます。 >>削除時は、別途添付ファイルに元の "bbs.dat" を複写しながら、削除対象の行だけ >>複写しないで、書き込んで、終わったら bbs.dat に上書きする。 if (isset($_POST['delete'])) { for ($i = 0; $i < count($lines); $i++) { $items = explode("\t", $lines[$i]); if ($items[0] == $_POST['delno']) { array_splice($lines, $i, 1); } } } ここにfopenを追記していくということだと思いますが、おっしゃられている処理はどのようなコードを書けばよいか、まだまだ勉強不足で分かりません。すいません。
it_solution_lab

2015/03/04 00:58

"a"は、追記する、というオプションですから、何もしなくても、fopen したあと write すれば、無条件で、後ろに追加されます。 特定の場所を削除する、ということは、"a"では実現できないので、 もう一つ、別の作業ファイルに、複写しながら該当行をコピーしない、か または、表示するかしないかのフラグ項目'del_flag'のようなものをもう一つ作って、 簡易掲示板で del_flag が1のときは表示しない、ようにして、 他の方のおっしゃっているように、行数を変えないなら、削除対象のところだけ、 del_flag=1 になるようにして書き出せばよいと思います。 "a"でfopen している時点で、そもそも、所定の位置を消す(編集する)ということが出来ないのではないでしょうか?
munyaX

2015/03/04 01:16

目に入ったもので横からすみません、 以下の箇所の話しでしたら、 > $fp = fopen($dataFile, 'a'); > fwrite($fp, $newData); > fclose($fp); これは新規投稿を記録する部分だと思うので、ここについては問題無いと思いますよ。 その後、私が回答したコメント部分で、削除後の記録処理も入れていただいたのですが、そこでは > $fp = fopen($dataFile, 'w'); という記述をされていたので、ファイルオープン時のモードについては理解されているようです。 プログラム初めたばかりだと、フラグの考え方はコロンブスの卵ですよねw 自分は10数年前の出来事なのであまり覚えてないですがw
it_solution_lab

2015/03/04 01:38

fopen のモードについてご理解してらっしゃるとのことなので、それでしたら フラグ処理が一番 かんたんでは? レコードを消してしまうのではなくて、削除というフラグを用意し、 通常の新規投稿時は、0にしておいて、 削除したら、1にする 表示する側で、削除フラグが1なら表示しないようにすれば、表向きは 削除したようになります。 どんな投稿が削除されたか?を残しておくってのも一つの考え方です。 もし、誤って削除してしまった、というとき復活できる、というのも データベースの考え方からすると、私は、そういう考えで作ってます。 本当にデータを削除したいときは、メンテナンスで行います・・・
munyaX

2015/03/04 01:56

> fopen のモードについてご理解してらっしゃるとのことなので、それでしたら > フラグ処理が一番 かんたんでは? まぁ何が簡単かはご本人に判断していただきましょうw 練習用とか個人用途であればカウンター用のファイル用意するのも、既存コードのロジックから変更が少ないので楽かもしれません。 > 本当にデータを削除したいときは、メンテナンスで行います・・・ ここらへんは組織によって運用変わりますよね。 自分もメンテナンス時にやることが多いですが、ボリュームが相当数になってからは一定のタイミングで削除処理を平行して走らせたりする案件も過去にありました。まぁケースバイケースですかね。
it_solution_lab

2015/03/04 02:39

一定日付以前の古いものの 削除フラグが立っているものを自動的にクリア、なんてこともしたりしますが、 本件では、日付も記録していないようなので、練習用なのでしょう テキストであれこれやるより、むしろDB使ってしまったほうが、このあたり すごく楽なのですがね
munyaX

2015/03/04 03:14

> テキストであれこれやるより、むしろDB使ってしまったほうが、このあたり > すごく楽なのですがね 慣れるとそうですねー。 この手の議論のポイントは、自転車に乗れるようになると、自転車に乗れない人の気持ちがわからなくなるのと同じで、質問者さんの技術レベルに合わせて、どう説明したら一番わかってもらえるかを考えるのが良いのですよね。そう考えるとはDBの提案はもう少し先でしょうか。 口出しはここらへんにしておきます。 お邪魔しました。
saki_program

2015/03/04 10:15

munyaX さん DBはまだ手を出していないんです。 テキストファイルに保存するというやり方で行ってます。
saki_program

2015/03/04 10:18

it_solution_lab さん >特定の場所を削除する、ということは、"a"では実現できないので、 >もう一つ、別の作業ファイルに、複写しながら該当行をコピーしない、か >または、表示するかしないかのフラグ項目'del_flag'のようなものをもう一つ作って、 >簡易掲示板で del_flag が1のときは表示しない、ようにして、 >他の方のおっしゃっているように、行数を変えないなら、削除対象のところだけ、 >del_flag=1 になるようにして書き出せばよい 折角のご提案ですが、どうやってコード書くのと、頭がこんがらがってます。 まだまだ勉強不足ですね。 自分が情けないです・・・、
guest

0

削除番号を指定して、投稿を削除できる機能がうまく書けません。

ご質問される際には、何がどううまくいかないのかを記述されると良いかと思います。
回答者側が勝手に想像したことが、質問者さんの望む答えとは限りませんので、
本来期待する結果を書いていただけるとスムーズに質疑が行えると思います。

lang

1if (isset($_POST['delete'])) { 2 for ($i = 0; $i < count($lines); $i++) { 3 $items = explode("\t", $lines[$i]); 4 if ($items[0] == $_POST['delno']) { 5 array_splice($lines, $i, 1); 6 } 7 } 8}

詳しく見ていませんが、まずは上記の箇所にファイルに書き込む処理を追加してみてください。

またここで記事番号を作成しているようですが、削除処理で物理的にデータを削除してしまうと、番号がずれませんか?

lang

1 $lines = file('bbs.dat'); 2 $cnt = count($lines); 3 $cnt += 1;

以下のいずれかの方法をとってみてください
・カウンター用のデータファイルを別に用意する、
・ファイル中から記事番号の最大値を取得する、
・物理的に削除するのではなく、論理削除する
※データの最後に1, 0をつけて、0なら表示する、1なら表示しない
削除は0を1にして記録

あと、これから書かれるのだと思いますが、投稿された内容から「改行」「タブ」を削除しておく必要があります。ついでにHTMLのタグを許可されないのであれば、<, >、”あたりを置換などされると良いでしょう。

投稿2015/03/03 09:02

編集2015/03/03 10:04
munyaX

総合スコア783

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

saki_program

2015/03/03 11:09

ご回答ありがとうございます。 質問があいまいで申し訳ございませんでした。 >>削除番号を指定して、投稿を削除できる機能がうまく書けません。 とは、 削除指定番号:<input type="text" name="delno"> <input type="submit" name="delete" value="削除"> テキストボックスに投稿番号を入力して(1番なら1と入力) 削除ボタンを押すと該当番号の投稿が削除される機能がほしいということです。 >>まずは上記の箇所にファイルに書き込む処理を追加してみてください。 if (isset($_POST['delete'])) { for ($i = 0; $i < count($lines); $i++) { $items = explode("\t", $lines[$i]); if ($items[0] == $_POST['delno']) { array_splice($lines, $i, 1); } } $fp = fopen($dataFile, 'w'); fwrite($fp, $newData); fclose($fp); } と、書き込んでみましたが、該当番号は削除されず、何も入力せずにもう1回削除ボタンを押したら、全部の投稿が削除されてしまいました。 おそらく解決方法は ・カウンター用のデータファイルを別に用意する、 ・ファイル中から記事番号の最大値を取得する、 ・物理的に削除するのではなく、論理削除する とmunyaXさんのおっしゃっている方法で解決できるのだろうと思いますが、私の勉強不足および理解不足のため、どのようなコードを書けばよいのやらと、迷走しております。 折角のご親戚な回答ですのに、本当に申し訳ないです。
munyaX

2015/03/03 15:41

まずは落ち着いて、変数の中に何が入っているかを考えて欲しいのですが、 > if (isset($_POST['delete'])) { > for ($i = 0; $i < count($lines); $i++) { この$linesには何が入っているでしょうか? forの直前あたりに、var_dump($lines); などとして中身を確認してみてください。 (ご自身の期待されたものであればそれでOKですし、違っていれば原因を考えてみてください) また削除を行う際に、 > if ($items[0] == $_POST['delno']) { > array_splice($lines, $i, 1); > } 削除したデータは $lines に入ってるっぽいじゃないですか。 ところが今回追加された記録処理では、 > $fp = fopen($dataFile, 'w'); > fwrite($fp, $newData); > fclose($fp); となっています。このとき$newDataの中には何が入っているか考えてみてください。 また実際に投稿内容を表示する際には、$postsを見ていますよね? > <?php foreach ($posts as $post): ?> $postsには削除されたデータが入っているでしょうか? 一箇所ずつ、変数が意図したものかをゆっくりと整理してみてください。 その後で > ・カウンター用のデータファイルを別に用意する、 > ・ファイル中から記事番号の最大値を取得する、 > ・物理的に削除するのではなく、論理削除する あたりの対策に乗り出されると良いかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問