SmartyとPearDBを利用した掲示板作成 http://www.ark-web.jp/sandbox/wiki/179.html

SmartyとPearDBを利用した掲示板作成

11月から新しく入社した小沼です。現在研修中でPHPの勉強をしています。
先日、研修の一環として「SmartyとPearDBを利用した掲示板」を作成しました。
自分の頭の中を整理する意味もこめて、ここにその成果の一部を発表したいと思います。

[edit]

目次

[edit]

概要

[edit]

環境

動作環境 : Linux
Webサーバ : Apache
開発言語 : PHP
DB : MySQL
使用したライブラリなど : Smarty、PearDB
開発はWindowsマシンからSSHでLinuxにつなぎ、おこないました。

[edit]

システム構成

作成したアプリケーションは以下のような構成になりました。

smarty_board
├ js
│ └ smarty_board.js --list.tpl内で利用するjavaScript
├ templates
│ └ list.tpl --画面のテンプレート
├ article_dao.php --データアクセスオブジェクト
├ list.php --list.tplに変数を設定するモジュール
├ paging_manager.php --ページング管理をおこなうクラス
└ submit_new_article.php --新規投稿を行うクラス

[edit]

困った点

[edit]

Smartyとjavascript

テンプレートファイルの中では中括弧{}が予約語として扱われます。そのためテンプレート内に以下のような記述をするとエラーになってしまいます。

function addPageNum(num) {
    document.list_form.page_num.value 
      = new Number(document.list_form.page_num.value) + num;
}

回避方法としては以下の二つがあります。

[edit]

文字化け

始めはHTMLのエスケープを、Smartyの機能を使いテンプレートの中で以下のようにやろうと思いました。

<td>{$article.name|escape:"htmlall"}</td>

そしたら文字化けするようになってしまったので、テンプレートを次のように修正し、

<td>{$article.name}</td>

php内で以下の関数を使ってエスケープすることにしました。

function escape($str) {
    return nl2br(htmlentities($str, ENT_QUOTES, 'EUC-JP'));
}
[edit]

\nと'(シングルクォーテーション)

入力された値をそのままDBに登録するといろいろ問題が発生します。例えば「\n」が入力されると、改行されて表示されてしまいます。もっとひどいのは「'(シングルクォーテーション)」を入力された場合です。SQLインジェクションが可能になってしまいます。さいわいPHPには

addslashes()

という便利な関数があるので、簡単に対応できます。

2007/10/25 追記 上のSQLインジェクション対策では完全ではないようです。
http://www.irisdti-jp.com/web/

[edit]

ソース

[edit]

list.tpl

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=EUC-JP ">
<title>スマーティーを利用した掲示板</title>

<script language="javascript" src= "./js/smarty_board.js" ></script>

</head>

<body>

<center>スマーティーを利用した掲示板</center>

<!-- 入力部分 -->
<form action="submit_new_article.php" name="submit_form" method="POST" >
<table align="center">
    <tr>
        <td>名前</td>
        <td><input type="text" name="name" size="40"></td>
    </tr>
    <tr>
        <td>内容</td>
        <td><textarea name="message" rows="6" cols="70" ></textarea></td>
    </tr>
    <tr>
        <td><input type="submit" value="新規投稿" /></td>
    </tr>
</table>

</form>

<!-- 一覧部分 -->
<form action="list.php" name="list_form" method="POST" >
<input type="submit" value="前へ" {$is_prev_disabled} onclick="addPageNum(-1);" />
<input type="submit" value="次へ" {$is_next_disabled} onclick="addPageNum(1);" />
{$page_num} / {$page_count}
<input type="hidden" name="page_num" value="{$page_num}" />

{foreach from=$articles item=article}

<hr>
<table>
    <tr>
        <td>名前:</td>
        <!--<td>{$article.name|escape:"htmlall"}</td>-->
        <td>{$article.name}</td>
    </tr>
    <tr>
        <td nowrap>投稿日時:</td>
        <td>{$article.date|date_format:"%Y/%m/%d %H:%M:%S"}</td>
    </tr>
    <tr>
        <td>内容:</td>
        <td>{$article.message}</td>
    </tr>
</table>

{/foreach}
<hr>

<input type="submit" value="前へ" {$is_prev_disabled} onclick="addPageNum(-1);" />
<input type="submit" value="次へ" {$is_next_disabled} onclick="addPageNum(1);" />
{$page_num} / {$page_count}

</form>
</body>
</html>
[edit]

list.php

<?php

require_once('Smarty.class.php');
require('paging_manager.php');

//検索
$pager = new PagingManager(getPageNum());
$result = $pager->getArticles();

//画面用のリストに詰め替える。
$articles = array();
foreach ($result as $row){
    $articles[sizeof($articles)] 
	  = array(name=>escape($row[1]), date=>$row[2], message=>escape($row[3]) );
}

//スマーティーの設定
$smarty = new Smarty;
$smarty->assign('articles', $articles);
$smarty->assign('page_num', getPageNum());
$smarty->assign('page_count', $pager->getPageCount());
if (!$pager->hasPrevPage() ) {
    $smarty->assign('is_prev_disabled', 'disabled');
}
if (!$pager->hasNextPage()) {
    $smarty->assign('is_next_disabled', 'disabled');
}

$smarty->template_dir = './templates/';
$smarty->display('list.tpl');

function getPageNum(){

    $page_num = (int) $_POST[page_num];
    if ($page_num <= 1){
        $page_num = 1;
    }
    return $page_num;
}

function escape($str) {
    return nl2br(htmlentities($str, ENT_QUOTES, 'EUC-JP'));
}

?>
[edit]

submit_new_article.php

<?php

require('article_dao.php');

//画面からの情報を取得する。
$article = array();
$article[name] = addslashes($_POST[name]);
$article[message] = addslashes($_POST[message]);

//DBへの登録処理をおこなう。
$dao = New ArticleDao;
$dao -> registArticle($article);

//リダイレクト
header("Location:http://www.irisdti-jp.com/playonline/);

?>
[edit]

paging_manager.php

<?php

require('article_dao.php');

define('PAGE_COUNT', 5);

class PagingManager {

    var $current_page_num;
    var $articles;
    
    function PagingManager($page_num) {
        $this->current_page_num = $page_num;
        
        $dao = new ArticleDao;
        $this->articles = $dao->getArticles();
    }

    function getArticles() {
        
        $limit_from = (PAGE_COUNT * $this->current_page_num) - PAGE_COUNT;
        $limit_to = $limit_from + PAGE_COUNT -1;
        $index = 0;
        $part_of_articles = array();
        
        while($row =& $this->articles->fetchRow()){
            if( $limit_from <= $index && $index <= $limit_to ) {
                $part_of_articles[sizeof($part_of_articles)] = $row;
            }
            $index++;
        }
        return $part_of_articles;
    }

    function hasPrevPage() {
        return  ( $this->current_page_num > 1 ); 
    }

    function hasNextPage() {
        return ( $this->current_page_num * PAGE_COUNT < $this->articles->numRows() );
    }

    function getPageCount() {
        return ceil($this->articles->numRows() / PAGE_COUNT);
    }

}

?>
[edit]

article_dao.php

<?php

require('DB.php');

class ArticleDao {

    //一件の投稿をDBに登録する。
    function registArticle($article) {
        //コネクション
        $dsn = "mysql://root:@localhost/konuma_training";
        $db = DB :: connect($dsn, true);
        
        //sql文の作成
        $sql = "insert into articles(
                   submitter_name
                  ,submit_date
                  ,message
                ) values (
                   ?
                  ,sysdate()
                  ,?
                )";
                
        //SQLの実行
        $db->query($sql, array($article[name], $article[message]));        

        //コネクションの開放
        $db -> disconnect();

    }

    //DBより書き込みを取得する。
    function getArticlesLimit($limit_from, $count){
        
        //コネクション
        $dsn = "mysql://root:@localhost/konuma_training";
        $db = DB :: connect($dsn, true);
        
        //sql文の作成
        $sql = "select * from articles order by id desc";
                
        //SQLの実行
        $result = $db->limitQuery($sql, $limit_from, $count);        

        //コネクションの開放
        $db -> disconnect();

        return $result;
    }

    //DBより書き込みを取得する。
    function getArticles(){
        
        //コネクション
        $dsn = "mysql://root:@localhost/konuma_training";
        $db = DB :: connect($dsn, true);
        
        //sql文の作成
        $sql = "select * from articles order by id desc";
                
        //SQLの実行
        $result = $db->query($sql);        

        //コネクションの開放
        $db -> disconnect();

        return $result;
    }
}

?>

2006/11/09 一部修正 インサート時にブレースホルダを使用するように修正しました。

[edit]

smarty_board.js

function addPageNum(num) {
	document.list_form.page_num.value = new Number(document.list_form.page_num.value) + num;
}

投稿者小沼 | パーマリンク

| append.gif

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2007-10-23 (火) 17:07:49 (6021d)

アークウェブのサービスやソリューションはこちら