2006-05-02 (火)
■ PHP 5.1.3 リリース
PHP の最新版の 5.1.3 がリリースされていた。 試すのはしばらく先になりそうだが、 とりあえずダウンロードしておく。
2006-05-03 (水)
■ counterview.inc.php を試用
どのページへのアクセスが多いのか知りたくなり、 counterview.inc.php というプラグインを試してみた。
counterview.inc.php.2 を試したところエラーが出たので、 44 行目を以下のように修正。
if(eregi('^:.+',$pageName)) continue;
感想としては、 確かにアクセスカウンタの一覧が見られて便利なのだが、 結果が何もソートされずに表示されるので、 見にくくて仕方が無い。 後で改良してみよう。
■ counterview.inc.php のソート対応パッチ
counterview.inc.php のソースを少しいじってみたが、 action 型のプラグインとして書き直した方が良い気がしてきた。
といっても、そこまで時間をかけるのもアレなので、
とりあえず、ページ名でソートするように改造してお茶を濁す。
以下、counterview.inc.php に対するパッチ。
44c44,48
< $counter = plugin_counterview_get_count($pageName);
---
> $counters[$pageName] = plugin_counterview_get_count($pageName);
> }
> }
> ksort($counters);
> foreach ($counters as $pageName => $counter) {
52d55
< }
(追記) 結局、書き直して、 こんなの を作ってしまった。
2006-05-04 (木)
■ counterlist.inc.php をリリース
結局、counterview.inc.php を参考に、 上位互換なプラグインを1から作ってしまった。
解説ページはまた後で書くとして、 とりあえずダウンロードだけできるようにしておく。
2006-05-05 (金)
■ PukiWiki 本家からの謎のアクセス
今朝、アクセスログを見てみたら、 http://pukiwiki.sourceforge.jp/ からのアクセスが若干あった。 なんだこれ? そう思って見に行ったら…。
げげっ! counterview.inc.php のページで、 自分が作ったパッチ が紹介されてる!
自分はブログに書いただけで、特に宣伝してないのに。 すげー。 どこの誰が見つけて紹介してくれたんだろ。
■ 整形済みテキストのワードラップ
ブログのレイアウトが崩れているのに気がついた。 整形済みテキストの部分が、なんというか、横にはみ出している。
ということで、長い行はワードラップして表示されるように、 theme の css ファイルの pre の箇所に以下のような設定を追加。
div.section pre {
……
white-space: -moz-pre-wrap; /* Mozilla */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
line-break: strict; /* IE 5.5+ */
word-break: break-all;
word-wrap: break-word;
}
PukiWiki のスキンからそのままパクってきた設定だが、 とりあえずこれで直ったっぽい。
■ counterlist.inc.php のページを公開
PukiWiki 本家 からリンクされていることが分かったので、 あわてて counterlist.inc.php の解説ページを書き上げた。
後は、昔のブログに追記して、 そちらのページへ誘導するようにすればよいだろう。
■ プラグインのライセンス
コメントがついてたので、 counterlist.inc.php のライセンスについて。 特に問題が無ければ、GPL2 でいいと思うのだが、 こういう考え方で良いのだろうか?
- アイデアは他のプラグインのパクりだが、最初から書き直している
→ ライセンスは自由
- PukiWiki のプラグインは、GPL のソフトウェアを利用するのではなく利用される側
→ ライセンスは自由
- PukiWiki 本体で定義されている関数を使っている
→ PukiWiki 本体の GPL ライセンスが伝染
2006-05-09 (火)
■ lighttpd を試す
高速・軽量だと評判の lighttpd を、 Debian on VMware の環境で試してみた。 とりあえず、 PukiWiki の整形ルールのページを表示するのにかかる時間を測定。
| Apache2 + mod_php4 | 0.342 sec |
| lighttpd + PHP4 (FastCGI) | 0.327 sec |
アクセラレータを入れるとか、ApacheBench で計るとかすれば、 また違った結果になってくるかもしれないが、 体感としてもほぼ同等の速度だと思う。 ただし、メモリ消費量は Apache よりも少ないようだ。 手元の PukiWiki はこれで動かすようにしようかな。
手順は、そのうち Wiki にまとめる予定なので、 ここではそれ以外のつまずいた点を。
- lighty-enable-mod コマンドを実行したら、Term/ReadLine.pm がないといわれた
perl-modules パッケージをインストールして解決。
- .php のファイルにアクセスすると lighttpd のプロセスが死ぬ
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=362827 に従って、 10-fastcgi.conf を修正。 (1.4.11-4 以降のバージョンでは直っているらしい。)
■ つまずく? つまづく?
上の文章で「躓いた点」と書いた後で、 平仮名に直しておこうと思って手が止まった。 あれ? どっちが正しいんだっけ?
両方書いてみると、「つまずく」の方が正しい気がする。 辞書で調べても、やはり「つまずく」が正しい。 でも、元々の語源的には「つまづく」っぽいし、 いつも無意識に「tumaduku」って入力して変換してるなぁ。
2006-05-10 (水)
■ ls2.inc.php に title_only オプションを追加する改造
今日も必要に駆られて PukiWiki いじり。 ls2.inc.php を改造して、title_only というオプションを追加してみた。 あくまで自分用の改造なのだが、 こちらのページ にパッチを載せておく。
以下、動作例。 「VMware/Debian/テスト環境/クローンの作成」 というページの先頭に、 「Debian のテスト環境用クローンの作成」 という見出しが書いてある。 title だと、 ページ名と最初の見出しが似た内容で並ぶが、 title_only だと見出しだけ表示する。
#ls2(,title) の表示
- VMware/Debian/テスト環境/クローンの作成
- Debian のテスト環境用クローンの作成
- テンプレートの選択
- クローンの作成
- VM の設定変更
- Debian のテスト環境用クローンの作成
- VMware/Debian/テスト環境/環境設定
- Debian のテスト環境の設定
- パッケージのアップデート
- SSH のインストール
- その他のパッケージのインストール
- スナップショットの作成
- Debian のテスト環境の設定
#ls2(,title_only) の表示
- Debian のテスト環境用クローンの作成
- テンプレートの選択
- クローンの作成
- VM の設定変更
- Debian のテスト環境の設定
- パッケージのアップデート
- SSH のインストール
- その他のパッケージのインストール
- スナップショットの作成
2006-05-11 (木)
■ Zend Optimizer 3.0 が無償公開
Zend Optimizer 3.0 が公開された。 っていうか、無料だったのか。 Zend 社の製品だから、有料なんだと思ってた。
PowerPC に対応って書いてあるな。 玄箱でも使用できるかなぁ。
あと、対応 Web サーバは Apache と IIS と書いてあるが、 lighttpd なんかでは使えないのだろうか? 後でダウンロードして色々試してみよう。
2006-05-14 (日)
■ VMware のページを一挙公開
VMware のページ のコンテンツを一気に追加した。
主に、VMware 上に Debian をインストールして PHP の開発環境を構築するまでの作業内容を書きまとめる予定なのだが、 まだ半分くらいまでしか書けていない。
それでも、この前試してみた lighttpd のインストール方法とか、 結構有用な情報もあると思うので、途中ではあるが公開しておく。
2006-05-15 (月)
■ PHP のソースコードの整形
昔書いた PHP のスクリプトを、 PEAR のコーディング規約に沿った形に整形したい。 そう思って、いくつかのソフトを試してみた。 シンプルな例として、こんな test.php を整形させてみる。
<?
if($a==TRUE){
echo "TRUE";
}
else {
echo "FALSE";
}
?>
PHP_Beautifier
以下のコマンドを実行し、インストール。
# pear config-set preferred_state beta # pear install --alldeps PHP_Beautifier
コマンドラインから php_beautifier コマンドを実行。
php_beautifier -l "Pear()" test.php
こんな出力結果が得られた。
<?
if ($a == TRUE) {
echo "TRUE";
} else {
echo "FALSE";
}
?>
…なんだ、これは? あちこちに改行が入って、スカスカのコードになる。 マニュアルを読んだが、それを抑制するオプションも無いっぽい。 よく見たら、インデントも変わっていないじゃないか。 ダメ、却下。
phpCodeBeautifier (コマンドライン版)
コマンドライン版と GUI 版があるが、 まとめて変換したいのでコマンドライン版の方を使う。 オプションの入力を省くため、以下の phpCB.bat を作る。
phpCB.exe -space-after-if -space-after-switch -space-after-while -space-before-start-angle-bracket -space-after-end-angle-bracket -one-true-brace-function-declaration -glue-amperscore -change-shell-comment-to-double-slashes-comment -force-large-php-code-tag -force-true-false-null-contant-lowercase -align-equal-statements --padding-char-count 4 %1 %2 %3 %4 %5 %6 %7 %8 %9
phpCB.bat test.php を実行。
<?php
if ($a == true) {
echo "TRUE";
}
else {
echo "FALSE";
}
?>
これも、} の位置がおかしい。 却下。
phpCodeBeautifier (GUI 版)
仕方ないので、GUI 版を試してみる。 マニュアルに従い、以下のオプションにチェックを入れる。
- space after if
- space after switch
- space after while
- space before start angle bracket
- space after end angle bracket
- one true brace function declaration
- glue amperscore
- glue arrow
- change shell comment to double slashes comment
- force large php code tag
- force true false null contant lowercase
- align equal statements
- optimize eol
変換結果は以下の通り。
<?php
if ($a == true) {
echo "TRUE";
} else {
echo "FALSE";
}
?>
ようやく、それなりに期待通りの結果が得られた。 しかし、バッチ処理できないのが困りものだし、 微妙な部分は手作業で修正しないといけない。 例えば、最後の } の後にスペースが入ってしまっている。 難読なソースコードを読みやすくするのには使えそうだが、 これで変換してそれでOK、というわけにはいかなさそうだ。
(追記) GUI 版のオプションと見比べていたら、 コマンドライン版の } の位置をまともにする方法が分かった。 -optimize-eol オプションをつければ良い。
2006-05-17 (水)
■ PHP のソースコードの整形 (2)
一昨日 の試みの続き。
php-mode.el
php-mode.el をインストール。
# tar xvfz php-mode-1.2.0.tgz # cp php-mode.el /usr/share/emacs/site-lisp/ # emacs -batch -f batch-byte-compile /usr/share/emacs/site-lisp/php-mode.el
~/.emacs に以下の設定を追加。
;;;php-mode (load-library "php-mode") (require 'php-mode) (custom-set-variables '(php-mode-force-pear t))
emacs を起動して PHP のファイルを読みこみ、 C-x h ESC C-\ と入力。
- C-x h (mark-whole-buffer)
- 現在のバッファ全体を region にする
- ESC C-\ (indent-region)
- region 内の全ての行をインデントし直す
以下のような変換結果になる。
<?
if($a==TRUE){
echo "TRUE";
}
else {
echo "FALSE";
}
?>
スペースを1つ入れるといった細かい調整はしてくれないが、 インデントだけ直すのなら完璧。 Emacs で編集した時にインデントが崩れないようにするためにも、 インストールはしておいた方がいいな。
■ 複数ファイルの行末の空白を除去
結局、 phpCodeBeautifier で整形を行うことにしたが、 } の後に必ず空白が入ってしまうのが気持ち悪い。 ということで、 行末の空白を取り除く PHP スクリプトを作成した。
以下のコードを rtrim という名前でファイルに保存。 (改行コードは \n にすることに決めうち)
#!/usr/bin/php
<?php
array_shift($argv);
foreach ($argv as $filename) {
$file = file($filename);
$fp = fopen($filename, 'w');
foreach ($file as $line) {
fwrite($fp, rtrim($line) . "\n");
}
fclose($fp);
}
?>
実行属性を与える。
$ chmod 744 rtrim
一応、バックアップを取って、
$ mkdir backup $ cp -p *.php backup/
行末の空白を一気に取り除く。
$ rtrim *.php
これでよし、と。
2006-05-18 (木)
■ MySQL 4.1 以降の文字化け問題
先に結論を書いておく。 skip-character-set-client-handshake オプションを使いましょう。 それで解決します。
今回、MySQL 4.0 → 4.1 に移行しようと思い、 あちこちで情報を集めて回ったが、 init-connect を使えばいいとか、 そのはずなのになぜかうまくいきませんとか、 いろいろ書いてあって混乱させられた。
結局、 日本 MySQL ユーザ会のサイトの FAQ に載っている情報が、一番詳しくてまとまっていると思うので、 そちらの情報を一読することをオススメする。 が、せっかくなので、 自分なりに理解したことをまとめてみる。
(以下の説明で、**** の部分は utf8 か ujis か sjis のいずれか)
MySQL 本体の設定
バイナリで配布されている MySQL は、 大抵はデフォルトの文字コードが日本語にはなっていない。 インストールしたままだと、こんな状態になっている。
mysql> SHOW VARIABLES LIKE 'char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | latin1 | | character_set_connection | latin1 | | character_set_database | latin1 | | character_set_results | latin1 | | character_set_server | latin1 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 7 rows in set (0.00 sec)
そこで、my.cnf に以下の設定を追加する。
[mysqld] default-character-set = **** [mysqldump] default-character-set = **** [mysql] default-character-set = ****
それぞれ、MySQL サーバの文字コード、 mysqldump コマンドで使われる文字コード、 mysql コマンドで使われる文字コード。 なるべく同じ文字コードにそろえる。
設定して MySQL を再起動するとこうなる。 (**** を utf8 に設定した場合)
mysql> SHOW VARIABLES LIKE 'char%'; +--------------------------+----------------------------+ | Variable_name | Value | +--------------------------+----------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/share/mysql/charsets/ | +--------------------------+----------------------------+ 7 rows in set (0.00 sec)
MySQL を利用するアプリ用の設定
上記の設定は、 コンソールから mysql コマンドで データベースを操作したりする時のための設定であり、 PHP で作られたアプリから接続したりする場合は、 また別の問題が出てくる。
バイナリで配布されている PHP は、 大抵はデフォルトの文字コードが日本語にはなっていない。 そのため、MySQL 4.1 以上のサーバにそのまま接続すると、 latin1 とかの文字コードでの接続扱いになって、 確実に文字化けが起こってしまう。
- 解決策1
MySQL 4.1.15, 5.0.13 以降の場合、my.cnf に以下の設定を追加する。
[mysqld] skip-character-set-client-handshake
これは、文字コードの自動変換機能を無効にする。 つまり、MySQL 4.0 までの動作と同じにする。 MySQL サーバの設定を変更できるのなら、この方法が最も簡単。 とにかくこの設定はしておいた方が良い。
- 解決策2
サーバ接続直後に以下の SQL 文を実行するように、 それぞれのアプリを修正する。
SET NAMES ****;
要するに、クライアントの側からサーバに対して、 「サーバさん、今から **** という文字コードでデータをやり取りしましょう。」 と宣言するわけだ。 それぞれのアプリを修正しなければならないのが難点だが、 考え方としては素直で分かりやすい。
- 解決策3(あまりオススメしない)
my.cnf に以下の設定を追加する。
[mysqld] init-connect="SET NAMES ****"
これは、接続するクライアントの文字コードを決めうちする。 つまり、サーバの側からクライアントに対して、 「おい、お前たち。 送られてくるデータは全部 **** の文字コードのつもりで処理するから、**** の文字コードでデータをよこせ。」 と言っているようなものか。 クライアント側の文字コードが統一されているのならば、これで良い。 アプリの修正も不要。
ただし、この設定を行うと、 default-character-set の設定は無効になってしまう ので、**** で設定した以外の文字コードで接続したい場合は、 結局、SET NAMES をアプリ側から実行する必要がある。 mysql コマンドを使う時でさえも、 最初に SET NAMES する必要がでてきたりして面倒。
- 解決策4(オススメしない)
my.cnf に以下の設定を追加する。
[mysqld] init-connect="SET NAMES binary"
これは、文字コードの自動変換機能を無効にする設定。 ただし、default-character-set の設定も無効になる。
サーバ側とクライアント側で 文字コードが統一されている場合はこれで良いのだが、 そうでない場合は、結局、SET NAMES **** の SQL 文を クライアント側で実行しなければならない。 ということで、トラブルの原因になりやすい。
2006-05-19 (金)
■ MySQL 4.1 以降の文字化け問題 (2)
昨日の話 の続き。
任意のバージョンの MySQL サーバに対応できるように、 MySQL サーバのバージョンが 4.1 以上ならば SET NAMES **** という SQL 文を実行するよう、 PHP のアプリを修正してみる。
まず、MySQL サーバのバージョンは、 SELECT version(); を実行することで以下のように得られる。
mysql> SELECT version(); +----------------------------+ | version() | +----------------------------+ | 4.0.24_Debian-10sarge1-log | +----------------------------+ 1 row in set (0.00 sec)
mysql> SELECT version(); +---------------------------+ | version() | +---------------------------+ | 4.1.11-Debian_4sarge2-log | +---------------------------+ 1 row in set (0.01 sec)
この結果を考慮して、こんなコードを追加してみた。
$sql = 'SELECT version()';
$result = mysql_query($sql);
$version = mysql_result($result, 0);
$version = floatval($version);
if ($version >= 4.1) {
$sql = 'SET NAMES ujis';
$result = mysql_query($sql);
}
MySQL サーバのログを取って確認してみたが、 これで期待通りの動作をしてくれる。
2006-05-20 (土)
■ VARCHAR 型の消費バイト
MySQL 4.0 → 4.1 に移行しようとして、 テーブルの定義を眺めていた時に、ふと思った疑問。
「この varchar(32) で定義されたメールアドレスのカラムも、 UTF-8 で書き込まれて、以前の3倍容量を食うのか?」
そう思い、MySQL のマニュアルの Unicode のところを読むと、 以下のように書かれていた。
ヒント:スペースを UTF8 で保存するには、CHAR ではなく VARCHAR を使用してください。 そのようにしないと、MySQL では CHAR(10) CHARACTER SET utf8 カラムに対して 30 バイトを確保しなければなりません。 これは、使用可能な最大長が 30 バイトであるためです。
??? 意味が分かりません。 多分、翻訳のミスか何かだろうと思い、英語の原文のほうを見てみる。
Tip: To save space with UTF-8, use VARCHAR instead of CHAR. Otherwise, MySQL must reserve three bytes for each character in a CHAR CHARACTER SET utf8 column because that is the maximum possible length. For example, MySQL must reserve 30 bytes for a CHAR(10) CHARACTER SET utf8 column.
ようやく意味が分かった。 最初の部分の訳は、「UTF-8 使用時に容量を節約したければ」が正解。 CHAR(10) と定義すると問答無用で 30 バイト持っていかれるが、 VARCHAR(10) って定義しても、 データが英数字だけなら 10 バイトくらいしか消費しないってことか。
2006-05-21 (日)
■ MySQL 4.1 & PHP5 の環境構築
Debian on VMware 上に、 MySQL 4.1 サーバと、 PHP5 の動く Web サーバをようやく構築できたので、 Wiki の方に作業記録を追加しておいた。
2006-05-22 (月)
■ PDO で複数の SQL 文を連続実行するとエラーになる理由
PDO を使って、こんな感じのコードを書いていた。
$dbh = new PDO($dsn); $sql = "SELECT * FROM table1 WHERE id='$id'"; $stmt = $dbh->prepare($sql); $stmt->execute(); $row1 = $stmt->fetch(); $sql = "SELECT * FROM table2 WHERE id='$id'"; $stmt = $dbh->prepare($sql); $stmt->execute(); $row2 = $stmt->fetch();
ところが、実行すると以下のようなエラーが出て止まってしまう。
Fatal error: Call to a member function execute() on a non-object.
エラーメッセージを見ると、 1回目でなく2回目の $stmt->execute(); でエラーになっている。 スクリプトの他の箇所では SQL 文をいくつも連続して実行できているのに、 なぜかここの箇所だけエラーになる。
試行錯誤して、 $stmt->fetch(); の後に $stmt = null; を追加してみたら、 一応動くようにはなった。 しかし、なぜそんな処理が必要になるのか、理由がさっぱり分からない。
そうしてさらに調べた結果、 PDOStatement::closeCursor のマニュアル に答えが書いてあった。 要するに、最後まで fetch しきらずに次の SQL 文の実行に移る場合は、 $stmt->closeCursor(); を実行する必要があるということか。
2006-05-25 (木)
■ a2ps と ps2pdf と a2pdf
PHP のソースコードを印刷しようと思い、 久しぶりに a2ps を使ってみることにした。 a2ps をインストールしてあるマシンが無かったので、 VMware 上の Vine Linux に a2ps を apt-get でインストール。 ただし、プリンタが接続できていないので、 さらに ps2pdf で PDF ファイルに変換して、 プリンタのつながっている Windows マシンから印刷しようとした。
ところが、出来上がった PDF ファイルをプレビューしてみると、 右端が切れてしまっている。 その原因を調べるのにまた時間を費やしてしまったが、 結局、犯人は ps2pdf だった。 日本発のディストリビューションなのに、 ps2pdf のデフォルトの用紙設定が、 A4 でなく Letter サイズになっていた…。
さて、どう対処しよう? 設定をいちいち手入力するのも面倒だから、 シェルスクリプトを書いて一気に変換するか。
#!/bin/sh for file in $*; do a2ps $file | ps2pdf -sPAPERSIZE=a4 - > $file.pdf done
これでよし。 なんて名前で保存しようか? 機能から言って a2pdf かな? そう考えたところで、嫌な予感がして、 以下のコマンドを実行してみた。
[revulo@vine revulo]$ which a2pdf /usr/bin/a2pdf [revulo@vine revulo]$
…あるじゃん。 しかも、中身を見てみると、 上のシェルスクリプトと同じようなことをやっている。 最初からこれを使えばよかったのか orz
…と思ったが、 /usr/bin/a2pdf は複数のファイルを一度に処理できなかったので、 結局、上記のシェルスクリプトが役立った。
2006-05-28 (日)
■ Debian に Ethna をインストール
フレームワークというものを試してみたくなり、手始めに、 Ethna を手元の環境にインストールしてみた。 Debian で Ethna を試す場合、以下のようにするのが楽なようだ。
- Ethna 0.2.0 を使用
- Ethna は /usr/share/php/Ethna にインストール
- Smarty は /usr/share/php/Smarty にインストール
以下、そこに至るまでの作業記録。
まず、必要なパッケージをインストール。
# pear install DB # aptitude install smarty
さて、Ethna はどこのディレクトリにインストールすれば良いか? phpinfo() の表示を見てみると、以下のような設定になっていた。
include_path .:/usr/share/php
ということで、/usr/share/php 以下にインストールしてみる。
# cd /usr/share/php # tar xvfz Ethna-0.2.0.tar.gz # ln -s Ethna-0.2.0 Ethna
実は最初、Ethna-2.1.0-preview1.tgz をインストールしたが、 チュートリアルで使う generate_project_skelton.php というファイルが入っていなかった。 まぁ、preview 版だからなぁ。 ということで、バージョン 0.2.0 をインストールし直した。
次に、チュートリアルに従い、以下のコマンドを実行してみた。
$ php /usr/share/php/Ethna/bin/generate_project_skelton.php ~/Ethna sample
ところが、こんな Warning が。
Warning: include_once(Smarty/Smarty.class.php): failed to open stream: No such file or directory in /usr/share/php/Ethna-0.2.0/Ethna.php on line 19 Warning: include_once(): Failed opening 'Smarty/Smarty.class.php' for inclusion (include_path='.:/usr/share/php:/usr/share/php') in /usr/share/php/Ethna-0.2.0/Ethna.php on line 19
調べてみると、Smarty が /usr/share/php/smarty/libs という、 ちょっと妙なディレクトリにインストールされていた。 Ethna の設定をこれに合わせて書き換えても良いが、 とりあえず、シンボリックリンクを張ってごまかす。
# cd /usr/share/php # ln -s smarty/libs Smarty
これで、あとはチュートリアル通りに進められた。
2006-05-29 (月)
■ Ethna で PDO や Simplate は使える?
Smarty & PDO を使っているプログラムを、 フレームワーク上に構築し直そうと考えている。 今のところ、以下のフレームワークに目をつけている。
雰囲気としては symfony が最強っぽいのだが、 Smarty と連携するのがキツいらしい。 Zend Framework は Smarty も PDO も使えるらしいが、 まだ発展途上で、これからどう化けるか分からないので敬遠してしまう。 Ethna は最初から Smarty を利用する仕組みになっているので、 移行作業は比較的楽かもしれない。
このような理由から、とりあえず Ethna がいいかと思うのだが、 テンプレートエンジンは Simplate に切り替えることも考えており、
- Smarty 以外のテンプレートエンジンは使えるのか?
- SQL 文にプレースホルダーは使えるのか?
- PDO を使うようにはできるのか?
この辺りの問題がクリアにならないと、どうも踏み込む気になれない。 ということで、調べてみた。
まず、テンプレートエンジンの件。 公式ページの FAQ には以下のように書かれている。
現状は、デフォルトの状態ではSmartyしか使えません。 しかし、flexyが利用できるようにハックしている方がいるのですこし手をいれれば使うことも可能ではないでしょうか。
なるほど。 エラーメッセージを表示するのに、 Smarty 関数が使われたりしているのが気がかりだが、 恐らくそれくらいなら何とかなるだろう。
次、プレースホルダーの問題。 Ethna prepare というキーワードで検索した結果、 以下のページが見つかった。
- http://ethna.jp/pipermail/users/2005-November/000077.html
- http://ethna.jp/pipermail/users/2005-November/000078.html
要するに、prepare は未実装なだけで、実装することは可能、と。
最後に、PDO を使うようにはできるのか? Ethna の beta 版には、Ethna_DB_ADOdb.php なんてのが入っているので、 PEAR::DB べったりというわけでもなさそうだ。 検索してみると、以下のページが見つかった。
http://dozo.matrix.jp/pear/index.php/Framework/Ethna/PDO.html
このページの ToDo には、
prepareとか使えるようにしたい。
と書かれている。 じゃあ prepare は、 上の方法のように自分で実装すればいいかなと思ったが、 ダウンロードした Ethna_DB_PDO.tar.gz を見てみると、 prepare() も実装されているようだ。 おぉ、すばらしい。
ということで、なんだか人柱になりそうな雰囲気ではあるが、 見通しは立ったので、とりあえず Ethna でやってみますか。
2006-05-30 (火)
■ Ethna で PEAR::DB を使うサンプル
Ethna でのデータベースの扱い方を知るための練習として、 チュートリアルで作ったサンプルを、 データベースを使って認証するようにしてみた。
まず、準備として、データベースの user というテーブルに、 email と md5(password) の値の組を保存しておく。
肝心のデータベースアクセスの部分は、 http://ethna.jp/ethna-db.html のやり方に従って書いてみる。 後で PDO に移行するつもりなので、 エラー処理とか SQL インジェクション対策とかはここでは考えない。
etc/sample-ini.php に以下のような設定を追加。
$config = array(
……
'dsn' => 'mysql://username:password@unix+localhost/dbname',
);
app/action/Login/Do.php の perform() の、 auth メソッドを呼び出している箇所を以下のように変更。
$db = $this->backend->getDB();
$mailaddress = $this->af->get('mailaddress');
$password = $this->af->get('password');
$result = $um->auth($db, $mailaddress, $password);
app/Sample_UserManager.php を以下のように変更。
<?php
class Sample_UserManager
{
function auth($db, $mailaddress, $password)
{
$sql = "SELECT password FROM user WHERE email='" . $mailaddress . "'";
$result = $db->query($sql);
$row = $result->fetchRow();
if ($row[0] != md5($password)) {
return Ethna::raiseNotice('パスワードが違います', E_SAMPLE_AUTH);
}
return 0;
}
}
?>
やってみたら、これで動いてくれた。 もっと良い書き方があるのかもしれないが、 とりあえず、PEAR::DB を使ってデータベースにアクセスすることはできた。
なお、他のサンプルを見ていると、 やたらと =& のような参照を使っているが、 これは PHP4 時代の名残なんだろうか? 参照を使う必要性は特に感じなかったので、 上記の例では全部 = にしてある。
2006-05-31 (水)
■ Ethna で PDO を使うサンプル
昨日の続き。 PDOをEthnaのデータベースオブジェクトに使う のページを参考にして、 Ethna のチュートリアルで作ったサンプルを、 PDO を使うようにしてみる。
Ethna_DB_PDO.php をインストール。
# cd /dev/shm # wget http://dozo.rgr.jp/Ethna_DB_PDO.tar.gz # tar xvfz Ethna_DB_PDO.tar.gz # cp Ethna_DB_PDO/class/DB/Ethna_DB_PDO.php /usr/share/php/Ethna/class/DB/
app/Sample_Controller.php の $class の設定を以下のように変更。
var $class = array(
……
'db' => 'Ethna_DB_PDO',
……
);
この段階でとりあえず実行してみたら、こんな風に言われた。
Fatal error: Class 'Ethna_DB_PDO' not found in /usr/share/php/Ethna/class/Ethna_Backend.php on line 367
なんで? エラーが出た辺りのコードを読んだり、 grep Ethna_DB_PEAR してみると、 /usr/share/php/Ethna/Ethna.php に以下のように書かれているのを発見。
include_once(ETHNA_BASE . '/class/DB/Ethna_DB_PEAR.php');
あー、決めうちしてるのか。 app/Sample_Controller.php の方で Ethna_DB_PDO.php を include しても良いのだろうが、 PEAR::DB でなく PDO オンリーで動くことを確認したいので、 ここはきっぱりと、 上記の箇所を Ethna_DB_PDO.php を include するように書き換えてしまう。
そうして、その後もいろいろと試行錯誤してみて、 以下のようなコードで動くことを確認できた。
<?php
class Sample_UserManager
{
function auth($db, $mailaddress, $password)
{
$sql = 'SELECT password FROM user WHERE email=?';
$db->prepare($sql);
$db->execute(array($mailaddress));
$row = $db->fetch();
if ($row[0] != md5($password)) {
return Ethna::raiseNotice('パスワードが違います', E_SAMPLE_AUTH);
}
return 0;
}
}
?>
ただ、動きはするのだが、どうも期待していたのと違う。
- execute() とか fetch() が $db のメソッド
- bindparam() などの PDOStatement クラスのメソッドが何も使えない
ところが、query() メソッドの方の実装を見てみると、 こちらは PDOStatement オブジェクトを返している。 他の Ethna_DB_PEAR とか Ethna_DB_ADODB を見ても、 query() メソッドはそのクラス独特の結果オブジェクトを返しているので、 単純に、return 文の書き忘れ、ではないかという気もしてきた。
とりあえず、prepare() メソッドに、 return $this->stmtObj; の1文を追加して、 PDOStatement オブジェクトを返すようにしてみた。 そうすると、上記のプログラムは以下のように書き直すことができる。
<?php
class Sample_UserManager
{
function auth($db, $mailaddress, $password)
{
$sql = 'SELECT password FROM user WHERE email=?';
$stmt = $db->prepare($sql);
$stmt->bindparam(1, $mailaddress);
$stmt->execute();
$row = $stmt->fetch();
$stmt->closeCursor();
if ($row[0] != md5($password)) {
return Ethna::raiseNotice('パスワードが違います', E_SAMPLE_AUTH);
}
return 0;
}
}
?>
PDO にべったりという感じになるが、 逆にこれくらいのことが書けないと PDO を使う意味が無い。 どうせ現状では、Ethna_DB はたいして抽象化されていないので、 これでいいんじゃないかと思う。

# ho [ライセンスは(ry]
# revulo [とりあえず GPL2 ってことで。]