トップ » 技術記事 » PHPで週末プログラミング(3) - 掲示板を作ってみよう(3)

PHPで週末プログラミング(3) - 掲示板を作ってみよう(3) はてなブックマーク数 このエントリーをブックマークに追加

もし、Webサイトの管理者で週末に何か気軽に作ってみようと思ったなら、自分専用の「掲示板」が作ってみるのはどうでしょうか。本連載では、PHPを使うことで手軽にできる掲示板の制作を紹介しています。掲示板を題材にPHPを学ぶことで、Webプログラミングの仕組みを学ぶことができます。ゼロからの掲示板作りに挑戦してみましょう。

対象とする読者

  • 週末に何か作ってみたい人
  • 何かしらのプログラミング言語の経験がある
  • PHPに挑戦してみたい人
  • 掲示板を作ってみたい人

ここで作る掲示板

連載の一回目では、環境のセットアップから簡単な掲示板を作るまでを紹介しました。

二回目では、データベースを利用して、より手軽に書き込みを管理する方法を紹介しました。

三回目の今回は、実際にWebサイトに設置して使ってもらえるような掲示板を作ってみようと思います。せっかくなので、筆者が制作している、日本語プログラミング言語「なでしこ」のサポート用の掲示板を作ってみました。

真夏の盛りに開発したので、掲示板の名前を manatubbs としました。

機能としては、普通のツリー掲示板の機能に加えて、RSSの出力機能や検索機能まで作りました。プログラムの作りとしては非常にオーソドックスで、特別なフレームワークを使うわけでもなく、オブジェクト指向も使わず、PHPをはじめたばかりの人の参考になるように作っています。

実際のプログラムは上記のサイトからダウンロードしてもらうことにして、実際にツリー掲示板を作る上でポイントなる部分を紹介したいと思います。

テンプレートとプログラムを分離しよう

manatubbs では、ユーザーがデザインを変更しやすいように、HTMLのテンプレートを tpl ディレクトリに分離するようにしました。デザインとプログラムを分離しておくと、デザインの変更が容易になるだけでなく、プログラムの管理もしやすくなります。

テンプレートファイルを取り込む方法

PHPでは、include 文を使うことで、PHPファイルを取り込むことができます。例えば、manatubbs では、HTMLの画面上部の部分を header.tpl.php というテンプレートファイルで表示させていますが、メインファイルと、テンプレートは次のようになっています。

メインファイルから抜粋:

    include "tpl/header.tpl.php";

tpl/header.tpl.php から抜粋:


<div id="title">
    <h1><a href="<?=$script_name?>"><?=$TITLE?></a></h1>
</div>
<div class="description"><?=$DESCRIPTION?></div>

PHP では、「<?php プログラム ?>」という構文のほかに、「<?= 式 ?>」として、変数や式を表示させることができます。

テンプレートエンジンの紹介

今回はシステムの簡易化のために利用しませんでしたが、smarty などの本格的なテンプレートエンジンを導入すると、より柔軟にデザインを記述することができるようになります。PHPでは、HTMLの中にプログラムを埋め込むような形で記述しますので、それ自体がテンプレートとも言えますが、smarty を使うことで、よりシンプルにデザインを記述できるようになります。

パラメータでページ遷移を管理しよう

また、こういった掲示板などでは、書き込みやログの表示などを1つのPHPファイルで行うことが多いですが、ページの遷移を表すのに、URLパラメータを使います。

manarubbs では、パラメータの変数の m で遷移状態を表しています。トップ画面を表示する場合は、m=all で、各ログを表示する場合には、m=log というパラメータで表示できるようにしています。

これをプログラムにするには、m が all なら、m_mode__all() という関数を実行し、m が log なら、m_mode__log() という関数を実行するようにしました。

これを実現しているのが以下のコードです。パラメータの値から、実行する関数名を特定し、関数が実行可能か調べ実行できるなら実行するというようになっています。

// パラメータの取得、m が省略されたら all をセットする
$mode = m_param("m", "all");
// m の値によって、実行する関数名を特定する
$ctrl_mode = "m_mode__{$mode}";
// 関数が実行可能か調べる
if (is_callable($ctrl_mode)) {
    call_user_func($ctrl_mode); // 関数を実行する
} else {
    m_show_error("<p>パラメータ【{$mode}】は利用できません。";
}

最近の PHP のプログラムでは、フレームワークと言って、こうしたコントローラーが既に用意されたものを利用することができます。有名なフレームワークでは、CakePHP や symphony などがあります。

ツリーでデータをつなぐ仕組み

manatubbs は、ツリー式の掲示板となっていますが、どのように書き込みを管理しているのかを紹介します。データベースの定義は、db/sql.txt というファイルに記録されています。

まず、掲示板のスレッドを、threads というテーブルで管理しています。また、個々のログは、スレッドとは別に logs というテーブルで管理しています。logs だけでもツリーを表現できるのですが、スレッドテーブルにログの要約を記録しておくことで、掲示板のログ表示が簡単になるように工夫しています。

ログを表示する場合には、新規で書き込みのあったログから表示するので、ログの要約である threads を見て掲示板の表示順番を決めて、そこから必要なログだけを取り出すようにしています。

threads テーブルは次のような定義になっており、書き込まれたログの要約を持つようにしています。

CREATE TABLE threads (
    threadid    INTEGER PRIMARY KEY,
    mode        TEXT,
    status      TEXT,
    title       TEXT,
    count       INTEGER, /* スレッドの個数 */
    ctime       INTEGER, /* スレッドの作成時刻 */
    mtime       INTEGER  /* スレッドの更新時刻 */
);

ログを管理するのが、logs テーブルで、以下は、その定義の抜粋です。threadid でどのスレッドに属するのかを表し、発言に対する返信の場合には、parentid に親となるログの logid を保持するようになっています。

CREATE TABLE logs (
    logid       INTEGER PRIMARY KEY,
    threadid    INTEGER, /* スレッドのID */
    parentid    INTEGER, /* 親(発言元)のログ */
    title       TEXT,    /* ログの件名 */
    body        TEXT,    /* ログの本文 */
    name        TEXT,    /* 名前 */
    ip          TEXT,
    ..

掲示板のスレッドをツリー表示する場合には、該当する threadid から、ログを取り出しておいて、parentid を参照して、スレッドをつなげていきます。

// テーブルから threadid をキーにしてログを取り出す
$r = m_db_query("SELECT * FROM logs WHERE threadid={$threadid}
                 ORDER BY ctime ASC");
// 配列変数 $items に $logid をキーにしてログを代入する
foreach ($r as $log) {
    $logid    = intval($log["logid"]   );
    $items[$logid] = $log;
}
// 親が設定されていれば、children 要素に追加する
foreach ($items as $log) {
    $logid    = intval($log["logid"]   );
    $parentid = intval($log["parentid"]);
    if ($parentid == 0) {
        $root = $logid;
    } else {
        $items[$parentid]["children"][] = $logid;
    }
}

そして、$items のルート要素から辿って再帰的に表示用のHTMLコードを生成します。

function m_get_index_title__($level, $items, $no)
{
    $log = $items[$no];
    extract($log);
    // .. 省略~HTMLの作成処理 ..
    // 子要素があれば再帰的に関数を読んでHTMLを作成する
    if ($log["children"]) {
        $len = count($log["children"]);
        for ($i = 0; $i < $len; $i++) {
            $row = $log["children"][$i];
            $s .= m_get_index_title__($level+1, $items, $row);
        }
    }
    return $s;
}

簡単ないたずら防止機構をつけよう

また、ネットに掲示板を公開した場合、どうしても、スパム書き込みに悩まされることになります。URLが大量に書き込まれたり宣伝が書き込まれます。そのために、NGワードや書き込み禁止IPを設けてはじいたりする方法がありますが、もっと簡単な実装でいたずらを防止することができます。

それは、日本語の簡単な確認キーを入力してもらう方法です。いたずら書き込みの大半は海外から自動巡回によって回ってきて機械的に書き込まれるものですから、ヒントに応じた答えを入力しないと書き込みができないようにするのです。

manatubbs でも、書き込みを行う際に『お手数ですが、いたずら防止のために、「なでしこ」と記入してください。』というメッセージを表示して、なでしこという文字を確認キーのフィールドに入力しないとエラーとしてはじくようにしています。本当に簡単な仕組みですが、これだけで、ほとんどのスパムをはじくことができています。

他には、CAPTCHA という技術があり、画像で表示されたメッセージを入力するものがあります。以下には、PHPで利用可能な CAPTCHA のライブラリの一覧がありますので、参考にしてみるとよいでしょう。

※ただし、CAPTHCA は完全ではなく、CAPTCHA を破るボットも増えています。

そこで、個人的な掲示板レベルなら、CAPTCHA使うまでもなく、簡単な質問に対する答えを入力してもらうだけで十分なのではというのが、現時点での費用対効果の答えでした。(ただし将来的には、対策が必要かも?!)

まとめ

以上、ツリー掲示板を作る上でのポイントを簡単に紹介しました。前回までの二回で、基本的な部分を紹介していますので、今回は、掲示板を改造する上でのヒントや公開する上で必要となるスパム対策について簡単に紹介しました。ぜひ、この記事を参考にして、オリジナルの掲示板を作ってみてください。

Series Navigation«掲示板を作ってみよう(2)掲示板を作ってみよう(4)»

このサイトについて

八角研究所
株式会社八角研究所のWEBサイトですよー。 いろんなものを創り出すことのできる環境をコツコツ構築中。 いったい、いつになったらできるのか。 この技術情報サイトもそのための活動の一環のつもり。

執筆者紹介

クジラ飛行机

クジラ飛行机

くじらはんど(http://kujirahand/)にて、日本語プログラミング言語「なでしこ」(IPA未踏ユース採択)、テキスト音楽「サクラ」(OSPオンラインソフト大賞入賞)など多くのオンラインソフトを開発。著書に「Flexプロフェッショナルガイド」「なでしこ公式バイブル」、「一週間でマスターするActionScript3.0」など。

TrackBack URL :