- 追加された行はこの色です。
- 削除された行はこの色です。
&pgid();
#include_interwiki(in3c,Ajax/Comet)
11月から新しく入社した小沼です。現在研修中でPHPの勉強をしています。
先日、研修の一環として「SmartyとPearDBを利用した掲示板」を作成しました。
自分の頭の中を整理する意味もこめて、ここにその成果の一部を発表したいと思います。
tag: [[Ajax>tag/Ajax]], [[comet>tag/comet]]
jfjfjfjff
#blikimore
**目次 [#nce29998]
#contents();
**概要 [#ffc248be]
***環境 [#sf8649dd]
動作環境 : Linux
Webサーバ : Apache
開発言語 : PHP
DB : MySQL
使用したライブラリなど : Smarty、PearDB
開発はWindowsマシンからSSHでLinuxにつなぎ、おこないました。
***システム構成 [#z45c15bc]
作成したアプリケーションは以下のような構成になりました。
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 --新規投稿を行うクラス
**困った点 [#k07e5025]
***Smartyとjavascript [#j6accfa2]
テンプレートファイルの中では中括弧{}が予約語として扱われます。そのためテンプレート内に以下のような記述をするとエラーになってしまいます。
function addPageNum(num) {
document.list_form.page_num.value
= new Number(document.list_form.page_num.value) + num;
}
回避方法としては以下の二つがあります。
-javascriptは外部ファイルに記述する。
-Smartyの中括弧が持っている機能を他の記号に割り当てる。(以下例)
$smarty->left_delimiter = '<!--{';
$smarty->right_delimiter = '}-->';
ちなみに私は前者の方法を取りました。
- もう1つ、javascriptの部分を{literal}{/literal}で囲むという表記法があります。(by 竹村 on 06/11/13)
-- http://sky.freespace.jp/smarty/SmartyManual_2-6-6J_html/language.function.literal.html
***文字化け [#t08c9daa]
始めはHTMLのエスケープを、Smartyの機能を使いテンプレートの中で以下のようにやろうと思いました。
<td>{$article.name|escape:"htmlall"}</td>
そしたら文字化けするようになってしまったので、テンプレートを次のように修正し、
<td>{$article.name}</td>
php内で以下の関数を使ってエスケープすることにしました。
function escape($str) {
return nl2br(htmlentities($str, ENT_QUOTES, 'EUC-JP'));
}
***\nと'(シングルクォーテーション) [#u091fe98]
入力された値をそのままDBに登録するといろいろ問題が発生します。例えば「\n」が入力されると、改行されて表示されてしまいます。もっとひどいのは「'(シングルクォーテーション)」を入力された場合です。SQLインジェクションが可能になってしまいます。さいわいPHPには
addslashes()
という便利な関数があるので、簡単に対応できます。
2006/11/09 追記 上のSQLインジェクション対策では完全ではないようです。
http://d.hatena.ne.jp/hoshikuzu/20060211#P20060211PHPSQLINJECTION
**ソース [#g1df0ee8]
***list.tpl [#g3a926a4]
<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>
***list.php [#c12499f7]
<?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'));
}
?>
***submit_new_article.php [#r21ca826]
<?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://carrot.ark-web.jp/~konuma/smarty_board/list.php");
?>
***paging_manager.php [#a7afbe30]
<?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);
}
}
?>
***article_dao.php [#nf2ddffb]
<?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 一部修正 インサート時にブレースホルダを使用するように修正しました。
***smarty_board.js [#vd9922dc]
function addPageNum(num) {
document.list_form.page_num.value = new Number(document.list_form.page_num.value) + num;
}
#blikifooter(小沼);