Skip to content

Instantly share code, notes, and snippets.

@clairvy
Created February 4, 2010 00:35
Show Gist options
  • Select an option

  • Save clairvy/294232 to your computer and use it in GitHub Desktop.

Select an option

Save clairvy/294232 to your computer and use it in GitHub Desktop.
^__MACOSX/
^flexigrid/
AddHandler cgi-script .pl
Options +ExecCGI

解説っぽいもの?

動作

だいたいこんな感じ?

  1. ブラウザが grid.pl にアクセスする.
  2. grid.pl が,
    1. 関数 init() で,テンプレートのパス設定とDB 接続をする.
    2. grid.pl?mode=grid_data のようにアクセスされていないので,関数 grid_data() を無視
    3. 関数 main() で,テンプレート template_flexigrid.htm をロードし て,ブラウザに返す.
  3. ブラウザが,返ってきた html を解釈する.
  4. ブラウザが,flexigrid.js や jquery.js や タグ <script> の内容を実行する.
  5. ブラウザがJS関数 $("#flex1").flexgrid() を実行したときに,grid.pl?mode=grid_data に,アクセスする.(アクセスするページ番号,ソートカラム名,ソート方向とかも一緒に送る)
  6. grid.pl が,
    1. 関数 init() は(略
    2. 関数 grid_data() が,sql を発行し,JSON データを返す.
  7. ブラウザが,返ってきたデータをもとに,テーブルの表示を変更する.

テーブルのどっかイジったときには,5 番あたりから同じように アクセスする.

以降,UNIX 系 OS で Apache 系だと仮定.

基本的な確認

  1. Perl は動く? $ /usr/bin/perl -v :

  2. 必要なモジュールは入っている? 以下は標準じゃないっぽいモジュール名と入ってるかの簡略な確認法.

    • DBI - $ /usr/bin/perl -mDBI -cwe1
    • JSON - $ /usr/bin/perl -mJSON -cwe1 もうちょっと例 #!/usr/bin/perl use CGI; use JSON; print CGI->header('text/x-json'); print to_json([{foo => bar}, 1, 2]);
    • Template - $ /usr/bin/perl -mTemplate -cwe1
  3. CGI は動く? 例えば,grid.pl と同じ位置に,hello.pl を配置したらhello って表示される? 以下 hello.pl の内容例. #!/usr/bin/perl use CGI; print CGI->header; print "hello";

  4. データは入っている? $ mysql5 -u test -p -e 'select * from country' test Enter password: test +----+------+------+----------------+------+---------+ | id | iso | name | printable_name | iso3 | numcode | +----+------+------+----------------+------+---------+ | 1 | AR | aaaa | bbbb | cccc | dddd | | 2 | BR | aaa2 | bbb2 | ccc2 | ddd2 | +----+------+------+----------------+------+---------+

  5. データはPerl 側から取得できる? 以下は,dbi.pl 内容例.

     #!/opt/local/bin/perl
     
     use DBI;
     use Data::Dumper;
     
     {
         my $user = 'test';
         my $pass = 'test';
         my $database = 'test';
     
         # DB 接続
         my $dbh = DBI->connect("DBI:mysql:database=$database;host=", $user, $pass, {
             RaiseError => 1,
             PrintError => 1,
             AutoCommit => 0,
         }) or die $DBI::errstr;
     
         my $sql = q(
             SELECT SQL_CALC_FOUND_ROWS
                   id
                 , iso
                 , name
                 , printable_name
                 , iso3
                 , numcode
             FROM
                 country
         );
     
         my $h = $dbh->prepare($sql) or die $DBI::errstr;
         $h->execute() or die $DBI::errstr;
     
         my @c = @{ $h->{NAME_lc} };
         my %r;
         $h->bind_columns(\(@r{@c}));
         while ($h->fetch) {
             print(Data::Dumper->Dump([\%r]));
         }
     
         # DB 切断
         $dbh->disconnect;
     }
    

枠が出ていないならば

  1. flexigrid.js 等の配置が正しいか確認.
  2. grid.pl の実行権の確認. $ ls -ln grid.pl -rwxr-xr-x 1 501 20 3460 2 4 10:03 grid.pl*
  3. そもそも grid.pl がコマンドラインで実行できるか確認. $ ./grid.pl : // HTML っぽいもの このときできるなら,標準エラーだけ見たい. $ ./grid.pl > /dev/null

投稿されたファイルだと,(最低でも)以下のファイルが必要.

ROOT/
  grid.pl
  template_flexigrid.htm

  jquery.js
  flexigrid.js
  
  css/flexigrid/flexigrid.css
  css/flexigrid/images/bg.gif
  css/flexigrid/images/ddn.png
  css/flexigrid/images/fhbg.gif
  css/flexigrid/images/first.gif
  css/flexigrid/images/last.gif
  css/flexigrid/images/line.gif
  css/flexigrid/images/load.gif
  css/flexigrid/images/load.png
  css/flexigrid/images/magnifier.png
  css/flexigrid/images/next.gif
  css/flexigrid/images/prev.gif
  css/flexigrid/images/up.png
  css/flexigrid/images/uup.png
  css/flexigrid/images/wbg.gif
  css/images/add.png
  css/images/close.png
  images/default.png

枠は出ているならば

  1. firebug で,JSON を追ってみて,データがブラウザ側に来ているか確認
  2. firebug が無いならば,ブラウザから http://<hostname>/<path>/grid.pl?mode=grid_data;page=1;rp=15;sortname=id;sortorder=asc みたいな感じでアクセスしてデータが取れるか試す.
  3. データが来ているなら,データ構成を確認してみる.
    1. rows が無ければ表示されない.
    2. total が 0 ならば,rows があっても表示されない(っぽい).
  4. データが来ていない
    1. JSON でエラーになっている. JSON モジュールが正しくインストールされていない.
    2. JSON に渡す文字列は,decode 済み(UTF-8フラグON) でなければならな いので,Devel::Peek の 関数 Dump() で確認する.

JSON のデータ例

{
    "page" : "1",
    "total" : "239",
    "rows" : [
        {
            "id" : 5,
            "cell" : ["AD", "ANDORRA", "Andorra", "AND", "20", 0, "5"]
        },
           : // 続く
    ]
}
#!/opt/local/bin/perl
use FindBin;
use lib ("$FindBin::RealBin/perl5/lib/perl5", "$FindBin::RealBin/perl5/lib/perl5/darwin-2level");
use DBI;
use Data::Dumper;
{
my $user = 'test';
my $pass = 'test';
my $database = 'test';
# DB 接続
my $dbh = DBI->connect("DBI:mysql:database=$database;host=", $user, $pass, {
RaiseError => 1,
PrintError => 1,
AutoCommit => 0,
}) or die $DBI::errstr;
my $sql = q(
SELECT SQL_CALC_FOUND_ROWS
id
, iso
, name
, printable_name
, iso3
, numcode
FROM
country
);
my $h = $dbh->prepare($sql) or die $DBI::errstr;
$h->execute() or die $DBI::errstr;
my @c = @{ $h->{NAME_lc} };
my %r;
$h->bind_columns(\(@r{@c}));
while ($h->fetch) {
print(Data::Dumper->Dump([\%r]));
}
# DB 切断
$dbh->disconnect;
}
#!/opt/local/bin/perl
# ↑ 標準じゃないパスのPerl を使っているので修正.
# 通常ならば,「#!/usr/bin/perl」or「/usr/bin/env perl」など,自分の環境に合わせる.
# パス設定
# 標準ではない場所に入れているので,必要.
# 通常は必要ではない.
# (ちなみに以下の設定は,gird.pl と同じディレクトリ配下の perl5 ディレクトリにモジュールが置いてあるときの設定)
use FindBin;
use lib ("$FindBin::RealBin/perl5/lib/perl5", "$FindBin::RealBin/perl5/lib/perl5/darwin-2level");
use CGI;
use CGI::Carp qw (fatalsToBrowser);
use DBI;
use JSON;
use Template;
use Env;
use strict;
use warnings;
use vars qw ($q $tt $dbh);
use lib '.';
use Encode;
init();
grid_data() if ($q->param('mode') and $q->param('mode') eq 'grid_data');
main();
# 表示
# テンプレートファイルをブラウザ側に返す
sub main {
# パラメータ title を追加
my $title = $q->param('title') || 'Flexigrid Perl Demo';
my $vars = {
title => $title,
script_name => $ENV{SCRIPT_NAME},
};
# HTML の文字コードを SJIS に固定
# もちろん,テンプレートの内容も文字コードSJIS にする必要がある.
print $q->header(-type => 'text/html', -charset => 'Shift_JIS');
$tt->process('template_flexigrid.htm', $vars) || die $tt->error(), "\n";
exit;
}
# データ送信関係
#
sub grid_data {
my @rows;
my @bind;
my $where = '';
my @where = ();
# 問い合わせデータの取得
my $query = $q->param('query') || '';
my $qtype = $q->param('qtype') || '';
my $page = $q->param('page');
my $limit = $q->param('rp');
my $sort = $q->param('sortname');
my $order = $q->param('sortorder');
# パラメータ testID を追加した
my $testID = $q->param('testID') || '';
my $offset = ($page -1) * $limit;
# where 句作成
if ($query) {
push(@where, "$qtype like ?");
$query = '%' . $query . '%';
push @bind, $query;
}
if ($testID) {
push(@where, "id = ?");
push(@bind, $testID);
}
if (@where > 0) {
$where = "WHERE " . join(' AND ', @where);
}
warn($where);
my $sql = qq~select SQL_CALC_FOUND_ROWS
id,
iso,
name,
printable_name,
iso3,
numcode
from country
$where
order by $sort $order
limit $offset,$limit
~;
# SQL 発行
my $h = $dbh->prepare($sql) or die $DBI::errstr;
$h->execute(@bind) or die $DBI::errstr;
my %r;
my @c = @{ $h->{NAME_lc} };
$h->bind_columns( \( @r{ @c } ));
# 結果をJSON 用のデータ形式に変更
while ($h->fetch) {
my @cell;
$r{default} = ($r{iso} eq 'AR') ? 1 : 0;
foreach (qw (iso name printable_name iso3 numcode default)) {
# DB のデータは,SJIS 決め打ちでロードした.
my $value = decode('sjis', $r{$_});
push @cell, $value;
}
push @rows, {
id => $r{id},
cell => [ @cell ]
};
}
$h->finish;
my $result = {
page => $page,
total => _total(),
rows => [ @rows ]
};
# JSON 形式に変換してブラウザへ出力
# JSON 形式は,Unicode しか許していないみたい.
# 参考
# - http://blogs.wankuma.com/kacchan6/archive/2007/04/12/71235.aspx
# - http://www.ietf.org/rfc/rfc4627.txt
# 部分引用
# JSON can represent four primitive types (strings, numbers, booleans,
# and null) and two structured types (objects and arrays).
#
# A string is a sequence of zero or more Unicode characters [UNICODE].
print $q->header(-type => 'text/x-json', -charset => 'UTF-8');
print to_json($result, {utf8 => 1});
exit;
}
# マッチしたデータ数の取得
sub _total {
my $h = $dbh->prepare('SELECT FOUND_ROWS() as total');
$h->execute;
my $row = $h->fetchrow_hashref;
return $row->{total};
}
# 初期化
# 問い合わせ設定,テンプレートのパス設定,DB(MySQL) 接続
sub init {
$q = new CGI;
unless (defined $tt) {
$tt = new Template({
# INCLUDE_PATH => $ENV{DOCUMENT_ROOT} . '/',
INCLUDE_PATH => $FindBin::RealBin . '/',
INTERPOLATE => 0,
}) or die "$Template::ERROR\n";
}
unless (defined $dbh) {
$dbh = DBI->connect('DBI:mysql:database=test;host=', 'test', 'test', {
RaiseError => 0,
PrintError => 1,
AutoCommit => 1
}) or die $DBI::errstr;
}
}
# 終了時の処理
# DB 切断
END {
$dbh->disconnect
}
#!/usr/bin/perl
use CGI;
print CGI->header;
print "<body>hello</body>";
#!/bin/sh
# -*- coding: utf-8-unix; -*-
# flexigrid の配置
wget http://flexigrid.googlecode.com/files/flexigrid.zip
unzip flexigrid.zip
cp flexigrid/flexigrid.js .
cp flexigrid/lib/jquery/jquery.js .
# 以下は,「cp -r flexigrid/css .」としてもいいかも.
mkdir -p css/images
cp flexigrid/css/images/add.png css/images
cp flexigrid/css/images/close.png css/images
mkdir -p css/flexigrid/images
cp flexigrid/css/flexigrid/flexigrid.css css/flexigrid
cp flexigrid/css/flexigrid/images/bg.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/wbg.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/fhbg.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/line.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/first.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/prev.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/next.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/last.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/load.gif css/flexigrid/images
cp flexigrid/css/flexigrid/images/up.png css/flexigrid/images
cp flexigrid/css/flexigrid/images/load.png css/flexigrid/images
cp flexigrid/css/flexigrid/images/magnifier.png css/flexigrid/images
cp flexigrid/css/flexigrid/images/uup.png css/flexigrid/images
cp flexigrid/css/flexigrid/images/ddn.png css/flexigrid/images
# 画像の配置
mkdir images
wget -O images/default.png http://chines.com.ar/flexigrid/images/default.png
# MySQL の設定
cat setup.sql | mysql5 -u root -t
/opt/local/bin/perl -MEncode -Mutf8 -mstrict -mDBI -we "my@vs=('AR', encode('sjis', 'ほげ ソ 構 能 表'), 'bbbb', 'cccc', 'dddd');my\$dbh=DBI->connect('DBI:mysql:database=test;host=', 'test', 'test');\$dbh->do(q|INSERT INTO country (iso, name, printable_name, iso3, numcode) VALUES (?, ?, ?, ?, ?);|, undef, @vs);\$dbh->disconnect;"
/opt/local/bin/perl -MEncode -Mutf8 -mstrict -mDBI -we "my@vs=('BR', encode('sjis', 'ふが'), 'bbb2', 'ccc2', 'ddd2');my\$dbh=DBI->connect('DBI:mysql:database=test;host=', 'test', 'test');\$dbh->do(q|INSERT INTO country (iso, name, printable_name, iso3, numcode) VALUES (?,?,?,?,?);|, undef, @vs);\$dbh->disconnect;"
mysql5 -u root -t -e 'select * from country;' test
-- -*- coding: utf-8-unix; -*-
-- -----------------------------------------------------------------------------------
-- 準備
-- -----------------------------------------------------------------------------------
-- ユーザ定義
GRANT ALL PRIVILEGES ON test.* TO 'test'@'localhost' IDENTIFIED BY PASSWORD 'test';
-- 確認
SHOW GRANTS FOR 'test'@'localhost';
-- テストデータ設定
USE test;
CREATE TABLE IF NOT EXISTS country (
id INT AUTO_INCREMENT PRIMARY KEY
, iso BLOB
, name BLOB
, printable_name BLOB
, iso3 BLOB
, numcode BLOB
) DEFAULT CHARACTER SET sjis;
-- 確認
SHOW CREATE TABLE country;
-- -----------------------------------------------------------------------------------
-- 後始末用
-- -----------------------------------------------------------------------------------
-- ユーザ削除
-- DROP USER 'test'@'localhost';
-- テーブル削除
-- DROP TABLE IF EXISTS country;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>[% title %]</title>
<link rel="stylesheet" type="text/css" href="css/flexigrid/flexigrid.css">
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="flexigrid.js"></script>
<style>
.flexigrid div.fbutton .add
{
background: url(css/images/add.png) no-repeat center left;
}
.flexigrid div.fbutton .delete
{
background: url(css/images/close.png) no-repeat center left;
}
</style>
</head>
<body>
<h1>[% title %]</h1>
<table id="flex1" style="display:none"></table>
<script type="text/javascript">
function default_params() {
return [
{name: 'mode', value: 'grid_data'}
];
}
$("#flex1").flexigrid (
{
url: '[% script_name %]',
dataType: 'json',
params : default_params(),
colModel : [
{display: 'ISO', name : 'iso', width : 40, sortable : true, align: 'center', process: procMe},
{display: 'Name', name : 'name', width : 180, sortable : true, align: 'left'},
{display: 'Printable Name', name : 'printable_name', width : 120, sortable : true, align: 'left'},
{display: 'ISO3', name : 'iso3', width : 130, sortable : true, align: 'left', hide: true},
{display: 'Number Code', name : 'numcode', width : 80, sortable : true, align: 'right'},
{display: ' ', name : 'default', width : 40, sortable : true, align: 'center', process: showDefault}
],
buttons : [
{name: 'Add', bclass: 'add', onpress : test},
{name: 'Delete', bclass: 'delete', onpress : test},
{separator: true}
],
searchitems : [
{display: 'ISO', name : 'iso'},
{display: 'Name', name : 'name', isdefault: true}
],
sortname: "iso",
sortorder: "asc",
usepager: true,
title: 'Countries',
useRp: true,
rp: 15,
showTableToggleBtn: true,
width: 700,
height: 200
}
);
function procMe(celDiv,id)
{
$(celDiv).click
(
function ()
{
alert(this.innerHTML);
}
);
}
function showDefault(cel,id) {
var v = cel.innerHTML;
if (v == '1') {
cel.innerHTML = '<img src="images/default.png" width="16" height="16">';
}
else {
cel.innerHTML = '';
}
}
function test(com,grid) {
if (com=='Delete')
{
confirm('Delete ' + $('.trSelected',grid).length + ' items?')
}
else if (com=='Add')
{
alert('Add New Item');
}
}
</script>
<p><a href="grid.txt">Source</a></p>
<p>この辺の文字列は,Shift_JIS で書いてあるよ.</p>
<form action="[% script_name %]" method="post">
<fieldset>
<legend>テンプレートへの引数(main)</legend>
<label for="title">title</label>
<input type="text" name="title" value="[% title %]"/>
</fieldset>
<input type="submit" />
</form>
<form action="#" id="testIDForm">
<fieldset>
<legend>SQL への引数(grid_data)</legend>
<label for="testID">testID</label>
<input type="text" id="testID"/>
</fieldset>
<input type="submit"/>
</form>
<script>
$('#testIDForm').submit(function() {
var params = default_params();
params.push({
name: 'testID', value: $('#testID').val()
});
$('#flex1').flexOptions({params: params}).flexReload();
return false;
});
</script>
<pre>
[% env %]
</pre>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment