MySQLを利用した掲示板 プログラム演習9
それではMySQLを利用して簡単な掲示板を作成してみましょう。掲示板の仕様は以下の通りにします
【仕様】
- 掲示板からは名前とコメントを投稿できる
- メイン画面には投稿フォームを設置する
- メイン画面には過去投稿が新しい順に表示できるようにする
- 名前とコメントは両方必須にして、空欄の場合はエラーと画面に表示する
- XSS対策はちゃんとする(ウエブセキュリティ参照)
DBの設計
今回、掲示板情報を保存するDBは前回作成したprog9というDBでTableは以下のbbsというテーブルを一つ作ります
bash-3.2$ cat create_table.sql CREATE TABLE bbs ( id int auto_increment, name varchar(255) not null default '', body text not null default '', pubdate timestamp, primary key(id) ) DEFAULT CHARSET=utf8;
Tableを作成します
bash-3.2$ /Applications/MAMP/Library/bin/mysql -u root -p prog9 < create_table.sql
mysql> show fields from bbs; +---------+--------------+------+-----+-------------------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+-------------------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(255) | NO | | | | | body | text | NO | | | | | pubdate | timestamp | NO | | CURRENT_TIMESTAMP | | +---------+--------------+------+-----+-------------------+----------------+ 4 rows in set (0.01 sec)
idカラムは自動採番(auto_increment)されるカラムでpubdateは更新(投稿)日付が自動で入るようにしてあります。掲示板に投稿する場合はこのbbsテーブルに name=名前 body=本文で1行インサートします。過去投稿をリストする場合は
SELECT * FROM bbs ORDER BY id DESC;
で取得します。
サイトの開発
基本的には演習6のプログラムを基本として開発します.
|-- ACTION | |-- Action_Base.class.inc | |-- Action_main.class.inc | `-- Action_post.class.inc |-- COMMON | |-- Config.inc | |-- Logs.class.inc | `-- RequestManager.class.inc |-- MODEL | `-- bbsDataAccessMySQL.class.inc |-- VIEW | |-- ViewManager.class.inc | |-- cache | |-- footer.tpl | |-- form.tpl | |-- header.tpl | |-- list.tpl | `-- main.tpl |-- create_table.sql `-- index.php
action=main(default)でメイン画面を表示します。action=postで投稿を行います. Action_post.class.incで投稿を行いますが、投稿完了時に即action=mainにリダイレクトさせます。以下がAction_post.class.incのececute関数です
function execute() { Logs::debug("EXECUTE"); $dataControl = new bbsDataAccessMySQL(); if(($dataControl->saveBBS($this->req->getAll())) == bbsDataAccessMySQL::REQUEST_OK) { header("Location: ./" . $this->templParams['env']['scriptname']); } else { header("Location: ./" . $this->templParams['env']['scriptname'] . "?error=1"); } exit; }
投稿完了後に header("Location")でメイン画面に遷移させます。投稿がエラーの場合はerror=1を付けて遷移させます。MySQLを操作する(投稿をINSERTる。過去投稿をSELECTする)は MODEL/bbsDataAccessMySQL.class.inc で操作します。
bash-3.2$ cat MODEL/bbsDataAccessMySQL.class.inc <?php require_once('./COMMON/HttpApiRequest.class.inc'); class bbsDataAccessMySQL { private $_db; const REQUEST_OK = 0; const REQUEST_ERROR = 1; function __construct() { $this->_db = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT); $this->_db->query("SET NAMES utf8"); } function __destruct() { $this->_db->close(); } function saveBBS($item) { try { if($item['name'] == "" || $item['body'] == "") { throw new Exception("param error"); } $sql = "INSERT INTO bbs(name, body) values (?, ?)"; if(($stmt = $this->_db->prepare($sql)) === false) { throw new Exception("prepare error"); } if(($stmt->bind_param("ss", $item['name'], $item['body'])) == false) { throw new Exception("binding error"); } if(($stmt->execute()) == false) { throw new Exception("execute error"); } $stmt->close(); return self::REQUEST_OK; } catch (Exception $e){ if($stmt) { $stmt->close; } logs::error($e->getMessage()); return self::REQUEST_ERROR; } } function listBBS() { try { $sql = "SELECT * FROM bbs order by id desc"; if(($result = $this->_db->query($sql)) == false) { throw new Exception("execute error"); } $res = array(); while($row = $result->fetch_array(MYSQLI_ASSOC)) { array_push($res, $row); } return $res; } catch (Exception $e) { logs::error($e->getMessage()); return array(); } } } ?>
最後にSmartyのtemplateですが、今回定義したのはメイン画面のmain.tplだけです。その中身も実際は
bash-3.2$ more VIEW/main.tpl {include file='header.tpl'} {include file='form.tpl'} {include file='list.tpl'} {include file='footer.tpl'}
です。 form.tpl が投稿フォームの部分, list.tplはリスト部分を定義しています. list.tplは
bash-3.2$ cat VIEW/list.tpl <table width="500px;"> {foreach from=$p.bbs item=data} <tr><td> {$data.name|escape:'html'} </td><td> {$data.pubdate} </td></tr> <tr><td colspan="2"> {$data.body|escape:'html'|nl2br} </td></tr> {/foreach} </table>
です。 $data.name $data.bodyの部分は Smartyの変数の修飾子を用いて加工しています。escapeではXSS対策をnl2brは改行をbrタグに置換する処理です。Smartyでhそれ以外にもプラグインという形で変数をtemplate側で加工することが可能です。必要に応じて使うと有効です。
今回のプログラム一式は
http://trac.assembla.com/cX0noKTPir3A7Oab7jnrAJ/browser/prog9
にありますので、必要に応じて参照してください。
【演習】
前回の、地図のAPIと組み合わせて、場所も特定できる掲示板を作成してみましょう。
DBの保存情報に緯度経度を加えます。ポイントは地図を選択した際に form の input hidden の値を書き換えるJavaScriptを書くことが必要になるでしょう. Ajaxで一気に投稿する拡張をすればさらにステップアップできます。