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

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

ただいまの
回答率

88.36%

php簡易掲示板に特定の番号だけを削除する削除機能をつけたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 751

hkr.0921

score 2

前提・実現したいこと

phpで簡易掲示板に「削除機能」を付加し、指定された番号の投稿だけ削除できるようにしたいです。
削除番号指定用フォームを追加→ファイル読み込み関数でファイルの中身を1行1要素として配列変数に代入→ファイルを開き、先ほどの配列の要素数(=行数)だけループさせるところまでは調べて書き込むことができたのですが、"ループ処理内で投稿番号と削除対象番号を比較し、等しくない場合は、ファイルに追加書き込みを行う"の部分がわからず、実装出来ません。
初歩的な質問ではあると思いますがご教授お願いします。

該当のソースコード

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>簡易掲示板</title>
</head>
<body>
    <form action="" method="post">
        <!--名前の入力フォーム-->
        <input type="text" name="name" value="名前">
        <!--コメントの入力フォーム-->
        <input type="text" name="comment" value="コメント">
        <input type="submit" name="submit">
        <!--消去の入力フォーム-->
        <input type="text" name="deleteno" value="">
        <input type="submit" name="delete" value="削除">
    </form>
    <?php
          /*ファイルの指定*/
          $filename = "mission_3-1.txt";
          /*POST送信があったとき*/
          if(isset($_POST["delete"])){
          /*変数に代入*/
          $delete = $_POST["deleteno"];
          /*ファイル全体を読み込んで配列に格納する*/
          $delCon = file("mission_3-1.txt");
          /*配列の要素数(=行数)だけループさせる*/
          for ($j = 0; $j < count($delCon) ; $j++){ 
          /*区切り文字「<>」で分割して、投稿番号を取得*/
          $delData = explode("<>", $delCon[$j]);
          /*投稿番号と削除対象番号を比較。等しくない場合はファイルに追加書き込みを行う*/
          if ($delData[0] == $delete) {
          array_splice($delcon, $j, 1);
          file_put_contents($filename, implode("\n", $delCon));
          }

          }
          fclose($fp);
          }
            /*POST送信があった時*/
            if (isset($_POST["submit"])){
            /*変数に代入*/
            $name = $_POST["name"];
            $comment = $_POST["comment"];
            /*日付データ取得*/
            $date = date("Y/m/d H:i:s");
            /*ファイルの存在がある場合は投稿番号+1、なかったら1を指定*/
            if (file_exists($filename)) {
            $num = count(file($filename))+1;
            } else {
            $num = 1;
            }
            /*書き込む文字列を組み合わせた変数*/
            $data = "$num <> $name <> $comment <> $date". PHP_EOL;
            $fp2 = fopen($filename , "a");
            fwrite( $fp2 , $data);
            fclose($fp2);
            }
    ?>

            【 投稿一覧 】<br>

    <?php   
            /*ファイル全体を読み込んで配列に格納する*/
            $ret_array = file( $filename );
            if(file_exists($filename)){
            foreach( $ret_array as $value ) {
            $result = explode("<>", $value);
            echo "$result[0] $result[1] $result[2] $result[3] <br>"  ;
            }
            }

    ?>
</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • dameo

    2020/09/02 10:19

    m6uさんがご指摘されてるとおり、いくつか問題がありますし、多分まだ指摘できるところがあるけど言ってない部分もあると思います。が、プログラムは動かないと面白くないので、まずは細かいところは端折って動くように考えましょう。

    ■指定番号の削除ってどう実現すればいいの?

    恐らく質問者さんが分からないのはココでしょう。何か文章で実現方法を聞いたのでしょうが、それがイマイチ納得できていないのだと思います。

    今は

    1 <> ほげ <> ふが <> 2020/09/02 10:03:07
    2 <> ふが <> ぴよ <> 2020/09/02 10:03:24

    のような形で記録されているmission_3-1.txtですが、これをどうやったら、例えば1の投稿を削除できるのでしょうか?現在2件しかない状態なので、ファイルの内容が

    2 <> ふが <> ぴよ <> 2020/09/02 10:03:24

    こうなったら、1行目を削除したことになります。当たり前ですよね。

    今回はどうやってそれを実現するかというと、、、

    元のファイル内容を丸ごと読み込んで、「書き込むときに、1行目の内容だけ書き込まないようにする」

    という方式です。普通は、1行目を書き込んで、2行目を書き込んで、、、という形でループするのですが、1行目のときはスキップして、2行目を書き込む、、、という形でループするのです。そして、1行目をスキップする方法が、、、

    /*投稿番号と削除対象番号を比較。等しくない場合はファイルに追加書き込みを行う*/
    if ($delData[0] == $delete) {
    array_splice($delcon, $j, 1);
    file_put_contents($filename, implode("\n", $delCon));
    }

    まあこのままだと、意図したとおりに動いたとしても、投稿番号と削除番号が等しいときだけ、ファイルに書き込もうとしているので、今回の例だと1行目だけ書き込もうとして、2行目をスキップしちゃうので、逆の動作になってしまいますが。。。

    まずは

    if ($delData[0] == $delete) {

    ではなく

    if ($delData[0] != $delete) {

    でないとダメですよね。これだけではまだ思ったとおりに動かないですが、いっぺんに理解しようとせず、1つずつ理解していけばいいので、気長に頑張ってください。

    次のヒントは「$delData[0]に余計な空白がないか」です。

    キャンセル

回答 1

checkベストアンサー

+3

削除処理のところをピックアップしてみます。

  /*POST送信があったとき*/
  if (isset($_POST["delete"])) {
    /*変数に代入*/
    $delete = $_POST["deleteno"];
    /*ファイル全体を読み込んで配列に格納する*/
    $delCon = file("mission_3-1.txt");
    /*配列の要素数(=行数)だけループさせる*/
    for ($j = 0; $j < count($delCon) ; $j++){
      /*区切り文字「<>」で分割して、投稿番号を取得*/
      $delData = explode("<>", $delCon[$j]);
      /*投稿番号と削除対象番号を比較。等しくない場合はファイルに追加書き込みを行う*/
      if ($delData[0] == $delete) {
        array_splice($delcon, $j, 1);
        file_put_contents($filename, implode("\n", $delCon));
      }
    }
    fclose($fp);
  }

file_put_contents()implode()で連結したものをファイルに書き出しているようですが、
書き出したあとのファイルの中身を確認していますか?

書き出しの処理のところで

    /*書き込む文字列を組み合わせた変数*/
    $data = "$num <> $name <> $comment <> $date". PHP_EOL;

としていてPHP_EOLを使っているのに、
implode()でなぜ"\n"を使うのでしょう?
ふつうは、同じ改行コードにしますよね。
結果が同じだったらどう表記してもいいという考えでしょうか。

そして、
implode()で投稿データの再連結をしていますが、
一番最後のデータの後ろに"\n"はつくのかなぁ。
丁寧に、投稿データの加工のそれぞれの場面で、
var_dump()とか駆使しながら、狙った通りのデータの持ち方になっているかを
しっかり確認してください。
思い込みを排除して冷静に丁寧に。

あと、削除の動作についてですが、
投稿番号が一致したら削除ですよね、
投稿データをひとつ削除して書き出すので物理削除します。
例えば1,2,3,4,5の投稿があって、4を削除すると、
ファイル上には1,2,3,5があります。
データ数を$num = count(file($filename))+1;にて求めると「5」が使われてしまいます。
簡単に投稿番号の重複を呼び起こします。

重複を起こさないためには、

a)
面倒でも投稿データをひとつひとつチェックして、
投稿番号の最大値を求め、+1して使う。

b)
投稿データファイルとば別に
投稿番号のみを管理するファイルを設け、
投稿を書き込むたびに+1した内容に更新する。

などといった方法が考えられます。

投稿データの書き込みの箇所でもう一点。

    /*書き込む文字列を組み合わせた変数*/
    $data = "$num <> $name <> $comment <> $date". PHP_EOL;

こんな連結方法でいいのでしょうか?
分離方法が

$result = explode("<>", $value);

となっているので、どちらかに統一しないと、
前後に余計に空白がついたデータが使われます。
HTML上に出力したソースコードで意図せず空白が前後についていると思われます。
揃えるなら例えば

$result = explode(" <> ", $value);

とするか、そもそも連結箇所を

    /*書き込む文字列を組み合わせた変数*/
    $data = implode("<>", [$num, $name, $comment, $date]) . PHP_EOL;

などとするかです。

まぁ、それを言い出すと、
フォームで投稿文字列に「<>」が入っている場合の対策がないことも気になります。
$nameや$commentに当たる箇所に「<>」が入っていると、
ファイルから読み出して分離するときに投稿データに含まれる「<>」で区切られると
おかしなことになります。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.36%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る