動作サンプル - JSON+Ajaxでソートなどを可能にしたテーブルリスト

FlexigridはJSON形式やXML形式で一覧画面に表示するデータをやりとりさせることで、ページャやソートなどの機能を簡単に組み込むことができるようになっている。ここではPHPを使用し、MySQLから郵便番号データを取り出してJSON形式で返すサンプルファイルを作成してみた。サーバ実行環境は次のとおり。

  • OS: FreeBSD 8-current
  • Webサーバ: Apache 2.2.8
  • PHP: 5.2.6
  • MySQL: 5.0.51a
  • pdo_mysqlインストール済み

各ソースコードと、実行結果は次のとおり。

zip_json.php (※)

<?php

function sanitizeTag($var)
{
    if ( is_array($var) )
    {
        $var = array_map("sanitizeTag", $var);
    }
    else
    {
        $var = htmlspecialchars(trim($var));
    }
    return $var;
}

$postdata = sanitizeTag($_POST);

$postdata['page'] = ( !$postdata['page'] ) ? 1 : $postdata['page'];
$postdata['rp'] = ( !$postdata['rp'] ) ? 10 : $postdata['rp'];
$postdata['sortname'] = ( !$postdata['sortname'] ) ? 'zip_code' : $postdata['sortname'];
$postdata['sortorder'] = ( !$postdata['sortorder'] ) ? 'asc' : $postdata['sortorder'];

try
{
    $dbh = new PDO
    (
        'mysql:host=localhost;dbname=zip',
        'root', // DB接続ユーザ名
        'password' //DB接続ユーザパスワード
    );

    $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    $sql_field_array = array
    (
        'zip_code', // 郵便番号
        'pref_name', // 都道府県名
        'city_name', // 市区名
        'area_name' // 地名
    );

    $select_field_name = '';
    for($n=0; count($sql_field_array) > $n; $n++)
    {
        if ( 0 < $n )
        {
            $select_field_name .= ', ';
        }
        $select_field_name .= $sql_field_array[$n];
    }

    $where = ($postdata['qtype'] && $postdata['query']) ? 'where ' . $postdata['qtype'] . ' like \''. $postdata['query']. '\'' : '';

    $stmt = $dbh->query( 'select COUNT(*) from zip ' . $where );
    $count = $stmt->fetchColumn();

    $sql = 'select '. $select_field_name . ' from zip '.
        $where .
        'order by ' . $postdata['sortname'] . ' ' . $postdata['sortorder'] . ' ' .
        'limit ' . ( ( $postdata['page'] - 1 ) * $postdata['rp'] ) . ', ' . $postdata['rp']; 
    $stmt = $dbh->prepare( $sql );
    $stmt->execute();

    $json = array
    (
        'page' => $postdata['page'] - 0,
        'total' => $count,
    );

    while( $row = $stmt->fetch(PDO::FETCH_ASSOC) )
    {
        foreach($row as $key => $value)
        {
            $tmp[] = $value;
        }

        $json['rows'][] = 
        (
            array
            (
                'cell' => $tmp
            )
        );

        unset($tmp,$key,$value);
    }

    $stmt = null;

    echo json_encode($json);

}
catch (PDOException $e)
{
    var_dump($e);
}

?>
※ 本サンプルはFlexigridの使用法を示すことに主眼を置いたものであり、セキュリティの観点からは不十分な点も存在するので注意していただきたい。具体的には、
  • htmlspecialchars(trim($var))では、「'」(シングルクォート)がエスケープされない。htmlspecialchars(trim($var), ENT_QUOTES, 'UTF-8') と記述したほうが好ましい
  • SQL文の組み立て時に、代入する文字列はmysql_real_escape_stringなどで必ずエスケープするべき
といった対処が必要である。さらにエスケープ処理だけに頼らず、なるべくホワイトリストを用意し、あらかじめ許可されたパラメータのみを通すようにコーディングしたたほうが良い。このあたりの詳細については、改めて解説する予定だ。

table_with_flexigrid_ajax.html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>テーブル+Flexigrid+Ajax</title>

<meta http-equiv="Content-Style-Type" content="text/css">
<meta http-equiv="Content-Script-Type" content="text/javascript">
<link href="./css/flexigrid.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="./js/jquery-1.2.6.js"></script>
<script type="text/javascript" src="./js/flexigrid.js"></script>

<script type="text/javascript">
<!--
$(document).ready(function() 
{
    $("#zip_list").flexigrid
    (
        {
            url: './zip_json.php',
            procmsg: '読み込み中です..',
            pagestat: '全 {total} 件のうち、{from} - {to} 件目を表示中',
            method: 'POST',
            dataType: 'json',
            colModel :
            [
                {display: '郵便番号', name : 'zip_code', width: 50, sortable : true, align: 'center' },
                {display: '都道府県名', name : 'pref_name', width: 70, sortable : true, align: 'left' },
                {display: '市区名', name : 'city_name', width: 70, sortable : true, align: 'left' },
                {display: '地名', name : 'area_name', width: 150, sortable : true, align: 'left' }
            ],
            searchitems :
            [
                {display: '郵便番号', name : 'zip_code'},
                {display: '都道府県名', name : 'pref_name'}
            ],
            sortname: "zip_code",
            sortorder: "asc",
            usepager: true,
            useRp: true,
            rp: 10,
            width: 'auto',
           height: 'auto'
        }
    )
}
);
-->
</script>

</head>

<body>

<table id="zip_list" style="display:none"></table>

</body>
</html>

図4: Windows XP SP2 / Internet Explorer 7でアクセス。各種サイズ変更のほかにソート・検索・ページャが利用できるようになった

図5: FreeBSD 8-current / Firefox 2でアクセスし、検索を行ったところ。問題なく動作している