Skip to content

PHP_EX_02 「CSVに書き込む」

Last updated on 2019/7/11

今回、CSVを使って掲示板のような書き込みできるWebサイトを作ります。

処理の流れ

  1. 書き込む内容をフォームで入力
  2. 書き込みの処理を行う
  3. 一覧を表示する

書き込む内容をフォームで入力する

入力するためのタグを書きます。

<form action="./write.php" method="post">
    <div class="field">
        <label class="label">Name</label>
        <div class="control">
            <input name="name" class="input" type="text" placeholder="Text input">
        </div>
    </div>

    <div class="field">
        <label class="label">Message</label>
        <div class="control">
            <textarea name="comment" class="textarea" placeholder="Textarea"></textarea>
        </div>
    </div>

    <div class="field is-grouped">
        <div class="control">
            <button type="submit" class="button is-link">送る</button>
        </div>
    </div>
</form>

今回、CSSフレームワークのBulmaを使っています。

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<!-- bulmaで使うfontawesameも入れる -->
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>

一つのフィールドを下記のように書くと、いい感じでスタイルが当たります。

    <div class="field">
        <label class="label">Name</label>
        <div class="control">
            <input name="name" class="input" type="text" placeholder="Text input">
        </div>
    </div>

詳細については、BulmaのFormを使うときのドキュメントを参考にしてみてください。

https://bulma.io/documentation/form/

書き込みの処理を行う

今回、SplFileObjectを使って、書き込みの処理を行います。

まず、読み込んだものが消えないように一時的にファイルのすべての行を読み込み、PHPの配列に格納し、新しい項目を追加します。

    // ファイル操作をするためのオブジェクト (読み込み用)
    $file = new SplFileObject($filepath);
    // 空の行や行末の行をトリミングする処理
    $file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
    // 一行一行読み出す処理
    foreach ($file as $line) {
        // 書き込みするデータのリストに追加する。
        $list[] = $line;
    }

    // 今回新しく追加するデータをリストに追加
    $list[] = [$name, $comment, date("Y/m/d H:i:s")];

配列$listにすべてのデータが入ったら、書き込みを行います。

    // ファイル操作をするためのオブジェクト (書き込み用)
    $file = new SplFileObject($filepath, "w");
    // 一行一行書き込む処理
    foreach ($list as $fields) {
        $file->fputcsv($fields);
    }

今回、読み込む処理と書き込む処理のSplFileObjectを違うオブジェクトにしています。本来、SplFileObjectのinitの際の第二引数で指定するオプションの指定の仕方で書き込みと読み込みの同時ができます。

試してみたのですが、あまり上手くいかない結果になってしまったので、オブジェクトを変えました。

書き込みの処理が正常でも異常でもメッセージを表示します。

<p><?=$message?></p>

そして、書き込みが正常に終わったら、2秒後にリストページに飛ばしてやるHTMLのmetaタグを追加します。

<?php if (!$error) {?>

<meta http-equiv="refresh" content=" 2; url=./list.php">

<?php }?>

HTMLでページを何秒後に移動させるという便利なmetaタグがあるので、覚えておきましょう。

<meta http-equiv="refresh" content=" 秒数; url=飛び先">

一覧を表示する

最後に書き込んだデータを一覧表示する処理を書いていきます。

// ファイルの場所
$filepath = "./file/bbs.csv";
// ファイル操作をするためのオブジェクト (読み込み用)
$file = new SplFileObject($filepath);
// 空の行や行末の行をトリミングする処理
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);

表示部分にはBulmaのBoxというものを使っています。

<div class="box">
    <article class="media">
        <div class="media-left">
            <figure class="image is-64x64">
                <img src="https://source.unsplash.com/128x128?<?=$line[0]?>" alt="Image">
            </figure>
        </div>
        <div class="media-content">
            <div class="content">
                <p>
                    <strong><?=$line[0]?></strong> <small><?=$line[2]?></small>
                    <br>
                    <?=$line[1]?>
                </p>
            </div>
        </div>
    </article>
</div>

画像は、Unsplashというサービスを使っています。

<img src="https://source.unsplash.com/128x128?<?=$line[0]?>" alt="Image">

全体のコード

書き込みの処理を行うページ

<?php

$error = false;
$message = "書き込みしました<br>2秒後に一覧画面に遷移します。";

// 名前
$name = "";
// 本文
$comment = "";

if (empty($_POST["name"]) && empty($_POST["comment"])) {
    // どちらも空の場合はエラーにする。
    $error = true;
    $message = "名前 or コメントのどちらかを書いてください。";

} else {

    if (!empty($_POST["name"])) {
        $name = $_POST["name"];
    } else {
        $name = "名無し";
    }

    if (!empty($_POST["comment"])) {
        $comment = $_POST["comment"];
    } else {
        $comment = "...";
    }
}

// 書き込みするためのデータのリストを入れる配列
$list = [];

// ファイルの場所
$filepath = "./file/bbs.csv";

if (!$error) { // エラーではないならファイル操作を行う。

    // ファイル操作をするためのオブジェクト (読み込み用)
    $file = new SplFileObject($filepath);
    // 空の行や行末の行をトリミングする処理
    $file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
    // 一行一行読み出す処理
    foreach ($file as $line) {
        // 書き込みするデータのリストに追加する。
        $list[] = $line;
    }

    // 今回新しく追加するデータをリストに追加
    $list[] = [$name, $comment, date("Y/m/d H:i:s")];

    // ファイル操作をするためのオブジェクト (書き込み用)
    $file = new SplFileObject($filepath, "w");
    // 一行一行書き込む処理
    foreach ($list as $fields) {
        $file->fputcsv($fields);
    }
}

?>

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>書き込み | 掲示板</title>
    <?php if (!$error) {?>
    <meta http-equiv="refresh" content=" 2; url=./list.php">
    <?php }?>
</head>

<body>
    <p><?=$message?></p>
</body>

</html>

一覧の表示の処理を行うページ

<?php
// ファイルの場所
$filepath = "./file/bbs.csv";
// ファイル操作をするためのオブジェクト (読み込み用)
$file = new SplFileObject($filepath);
// 空の行や行末の行をトリミングする処理
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE);
?>

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title> リスト表示 | 掲示板</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
</head>

<body>
    <section class="section">
        <div class="container">
            <h1 class="title">
                書き込み一覧
            </h1>
            <p class="subtitle">
                自由に書き込んでね! 書き込みは <a href="./input.php">こちら</a>
            </p>
            <?php foreach ($file as $line) {?>
            <div class="box">
                <article class="media">
                    <div class="media-left">
                        <figure class="image is-64x64">
                            <!-- <img src="https://source.unsplash.com/128x128?<?=$line[0]?>" alt="Image"> -->
                        </figure>
                    </div>
                    <div class="media-content">
                        <div class="content">
                            <p>
                                <strong><?=$line[0]?></strong> <small><?=$line[2]?></small>
                                <br>
                                <?=$line[1]?>
                            </p>
                        </div>
                    </div>
                </article>
            </div>
            <?php }?>

        </div>
    </section>


</body>

</html>

入力フォームを設置するページ

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>入力画面 | 掲示板</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
    <script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>

</head>

<body>
    <section class="section">
        <div class="container">
            <h1 class="title">
                入力フォーム
            </h1>
            <p class="subtitle">
                名前かコメントは必須です。書き込み一覧は<a href="./list.php">こちら</a>
            </p>
            <form action="./write.php" method="post">
                <div class="field">
                    <label class="label">Name</label>
                    <div class="control">
                        <input name="name" class="input" type="text" placeholder="Text input">
                    </div>
                </div>

                <div class="field">
                    <label class="label">Message</label>
                    <div class="control">
                        <textarea name="comment" class="textarea" placeholder="Textarea"></textarea>
                    </div>
                </div>

                <div class="field is-grouped">
                    <div class="control">
                        <button type="submit" class="button is-link">送る</button>
                    </div>
                </div>
            </form>
        </div>
    </section>

</body>

</html>