PHP による超簡易掲示板 ( JSONでデータを保存します ) / CSS でレスポンシブ対応

▼ ノーマル

▼ スマホ




保存データを行単位で区切り文字で分けて投稿データを保存する方法は古くからありますが、JSON 形式で保存しておくと、投稿データ内の改行やクォートなどのデータを自分で処理する必要がなくなる上に、新しい項目も追加するのが容易になります。さらに、データが JSON で作られるので、そのまま http で他のアプリケーションからアクセスする事も容易になります

一応、MVC にのっとり、M(model.php) / V(view.php) / C(board.php) になっています

board.php

error_reporting(E_ALL & ~E_NOTICE); は、$_POST 等の変数の参照時に未定義(ブラウザから送られていない)時にでも、空文字列が入っているとみなして処理できるようにするものです。逆に、全てのエラーを出力するようにした場合、代入されていな い値を使用した場合は、警告を発生します( 必要であれば、php.ini で設定します )

01.<?php
02.error_reporting(E_ALL & ~E_NOTICE);
03.// **************************************
04.// php.ini の output_buffering をチェックして
05.// 有効になっていた場合は、header の前に出力可能です
06.// **************************************
07. 
08.// **************************************
09.// 通常の HTML として出力します
10.// **************************************
11.header( "Content-Type: text/html; charset=utf-8" );
12. 
13.// **************************************
14.// キャッシュを無効にするヘッダ
15.// ※ いろいろあるのは念のため
16.// **************************************
17.header( "Expires: Thu, 19 Nov 1981 08:52:00 GMT" );
18.header( "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0" );
19.header( "Pragma: no-cache" );
20. 
21.// **************************************
22.// 関数の定義を読み込みます
23.// **************************************
24.require_once("model.php");
25. 
26.// **************************************
27.// $_POST['send'] != "" は送信ボタンが
28.// クリックされた事を示します
29.// さらに、テキストエリアに何か入力され
30.// た場合に処理を行います
31.// **************************************
32.$_POST['text'] = preg_replace( "/^[ \s]+/u", "", $_POST['text'] );
33.$_POST['text'] = preg_replace( "/[ \s]+$/u", "", $_POST['text'] );
34.if ( $_POST['send'] != "" && $_POST['text'] != "" ) {
35. 
36.        // データの書き込み処理
37.        post_data();
38. 
39.}
40. 
41.// データの表示処理
42.disp_data();
43. 
44. 
45.// **************************************
46.// ▼ 以下は画面です。$log_text を
47.//    埋め込んでいます
48.// **************************************
49.require_once("view.php");
50.?>

キャッシュ無効は、先頭に 
session_cache_limiter('nocache');
session_start();
でもいいと思います


FORM は一般的な POST メソッドで送信されます。なので、書き込んだ直後にリダイレクトして GET メソッドで呼び出しなおすという処理が入っています。タイトルの『超簡易掲示板 ( JSON )』をクリックすると、GET メソッドでの呼び出しであるリンクとなっています。

投稿データの表示内容は、いったん文字列で作成して後から view.php の該当部分に埋め込む形式です。最新のデータは、array_unshift によって、データの先頭に追加されます。

HTML 要素を無効にする方法としては、htmlentitieshtmlspecialchars がありますが、初心者向けとして最低限の置き換えを str_replace で実装しています。

json_encode による、オブジェクトから文字列の変換では、オプションの JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT でデバッグしやすいように可読性に重点を置いています。

model.php
001.<?php
002. 
003.// **************************************
004.// データの書き込み処理
005.// **************************************
006.function post_data() {
007. 
008.        // データを一括読み込み
009.        $log_text = @file_get_contents("board.log");
010. 
011.        $json = json_decode( $log_text );
012.        // 空のファイルかまたは、JSON データでは無い場合
013.        if ( $json === null ) {
014. 
015.                // JSON 用クラス作成
016.                $json = new stdClass;
017.                // 行データを格納する配列を作成
018.                $json->item = array();
019. 
020.        }
021. 
022.        // 改行コードを \n のみ(1バイト)にする
023.        $_POST['text'] = str_replace("\r","",$_POST['text']);
024. 
025.        // HTML 要素を無効にする
026.        $_POST['text'] = str_replace("<","&lt;",$_POST['text']);
027.        $_POST['text'] = str_replace(">","&gt;",$_POST['text']);
028. 
029.        // HTML 要素を無効にする
030.        $_POST['subject'] = str_replace("<","&lt;",$_POST['subject']);
031.        $_POST['subject'] = str_replace(">","&gt;",$_POST['subject']);
032.        $_POST['name'] = str_replace("<","&lt;",$_POST['name']);
033.        $_POST['name'] = str_replace(">","&gt;",$_POST['name']);
034. 
035.        // 新しい投稿用のクラス作成
036.        $board_data = new stdClass;
037. 
038.        // text プロパティに 入力された本文をセット
039.        $board_data->text = $_POST['text'];
040.        // subject プロパティに 入力されたタイトルをセット
041.        $board_data->subject = $_POST['subject'];
042.        // name プロパティに 入力された名前をセット
043.        $board_data->name = $_POST['name'];
044.        // subject プロパティに 入力されたタイトルをセット
045.        $board_data->datetime = $_POST['datetime'];
046. 
047.        // 配列の先頭に 新しい投稿データをセット
048.        array_unshift($json->item, $board_data);
049. 
050.        // 全ての投稿データを JSON として一括書き込み
051.        file_put_contents("./board.log", json_encode( $json, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT ) );
052. 
053.        // GET メソッドで再表示します
054.        header( "Location: {$_SERVER["PHP_SELF"]}" );
055. 
056.        exit();
057. 
058. 
059.}
060. 
061.// **************************************
062.// データの表示処理
063.// **************************************
064.function disp_data() {
065. 
066.        // 埋め込み用データを global 宣言
067.        global $log_text;
068. 
069.        // データを一括読み込み
070.        $log_text = @file_get_contents("./board.log");
071.        // ファイルが存在しない場合
072.        if ( $log_text === false ) {
073.                $log_text = "ここに投稿データが表示されます";
074.                return;
075.        }
076. 
077.        $json = json_decode( $log_text );
078.        // 空のファイルかまたは、JSON データでは無い
079.        if ( $json === null ) {
080.                $log_text = "ここに投稿データが表示されます";
081.                return;
082.        }
083. 
084.        // 表示用の埋め込みに使用される文字列変数
085.        $log_text = "";
086.        foreach( $json->item as $v ) {
087.         
088.                // **************************************
089.                // 本文の改行は br 要素で表現します
090.                // **************************************
091.                $v->text = str_replace("\n", "<br>\n", $v->text );
092. 
093.                // **************************************
094.                // 記事の境界を hr 要素で表現します
095.                // **************************************
096.                $v->text .= "<hr>\n";
097. 
098.                // **************************************
099.                // 行毎に表示 HTML を作成
100.                // **************************************
101.                $log_text .= "<div class='title'>【{$v->subject}】( {$v->name} : {$v->datetime} ) </div>" . $v->text;
102.         
103.        }
104. 
105. 
106.}
107. 
108.?>

投稿時の日付データは、ブラウザ側でセットするようにしています。特に日付に関しては JavaScript ではスマートな方法が無いので、学習のきっかけ用としてこのようになっています。また、送信時のイベント処理としても重要なサンプルとなり、jQuery の基本サンプルでもあります。

※ jQuery は、Google のホスティングを使用しています。

view.php
01.<!DOCTYPE html>
02.<html>
03.<head>
04.<meta charset="utf-8">
05.<meta content="width=device-width initial-scale=1.0 minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" name="viewport">
06.<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
07. 
08.<style>
09.* {
10.        font-family: "ヒラギノ角ゴPro W3","Hiragino Kaku Gothic Pro","メイリオ",Meiryo,"MS Pゴシック",Verdana,Arial,Helvetica,sans-serif;
11.}
12. 
13.textarea {
14.        height: 100px;
15.}
16. 
17.@media screen and ( min-width:480px ) {
18.        input {
19.                width: 400px;
20.        }
21.        textarea {
22.                width: 500px;
23.        }
24.}
25. 
26.@media screen and ( max-width:479px ) {
27. 
28.        input,textarea {
29.                width:100%;
30.        }
31. 
32.}
33. 
34..title {
35.        border: 1px solid #aaa;
36.        padding: 4px;
37.        margin-bottom: 6px;
38.}
39. 
40.</style>
41. 
42.<script>
43. 
44.$( function(){
45. 
46.        // フォーム送信イベント
47.        $("form").on("submit", function(){
48. 
49.                // 日付文字列をクライアントで作成して送信
50.                var dateNow = new Date();
51.                var dateString =
52.                        dateNow.getFullYear() + "/" +
53.                        ("0"+(dateNow.getMonth()+1)).slice(-2)+ "/" +
54.                        ("0"+(dateNow.getDate())).slice(-2);
55.                var timeString =
56.                        ("0"+(dateNow.getHours())).slice(-2) + ":" +
57.                        ("0"+(dateNow.getMinutes())).slice(-2) + ":" +
58.                        ("0"+(dateNow.getSeconds())).slice(-2);
59. 
60.                // hidden フィールドにセット
61.                $("#datetime").val( dateString + " " + timeString );
62. 
63.        });
64.});
65. 
66.</script>
67.</head>
68. 
69.<body>
70.<h3><a href="board.php" style="color:black;">超簡易掲示板 ( JSON )</a></h3>
71. 
72.<form method="POST">
73.        <div>タイトル <input type="text" name="subject"></div>
74.        <div>名  前 <input type="text" name="name"></div>
75.        <div><textarea name="text"></textarea>
76.        <input type="hidden" name="datetime" id="datetime"></div>
77.        <div><input type="submit" name="send" value="送信"></div>
78.</form>
79.<br>
80. 
81.<?= $log_text ?>
82. 
83.</body>
84.</html>

JSON は、item プロパティが配列になり、複数項目の投稿データが格納されます。

JSON データ
01.{
02.    "item": [
03.        {
04.            "text": "最低限の機能を持った掲示板です。\nデータ形式は JSON でとても拡張しやすく便利です。",
05.            "subject": "こんにちは",
06.            "name": "山田 タロウ",
07.            "datetime": "2019\/02\/22 13:48:00"
08.        }
09.    ]
10.}