最終更新:
Microsoft Virtual PC 2003
にて、PHP5に再挑戦してみる。Virtual PCについてはインストーラで簡単にインストールできるのでここでは書かないけど。
メモリは32M、ハードディスクは4GBで仮想マシンを作成しておき、FreeBSD 6.2-RELEASE i386
のインストール。一旦自動でスワップ領域の大きさを調べておき、スワップ領域とルートのみにしておいた。んで最小インストール。
時間短縮でapacheをパッケージインストールしようとしたら・・・無いじゃん。>FreeBSD 6.2 CD
apacheはあきらめて、他に必要っぽいものをパッケージインストール。この時点ではImageMagick
もインストールするつもりだった。
httpd-2.0.61.tar.gz
をSC430の時のスクリプトを利用してコンパイル。
#!/bin/sh
#### (compile option enviroments)
export CFLAGS="-DHAVE_BROKEN_REALPATH -O3"
export CXX=gcc
export CXXFLAGS="-O3"
#### apache2 build
cd /usr/src
tar xvf /dist/httpd-2.0.61.tar.gz
cd httpd*
./configure \
--enable-auth-digest \
--enable-expires \
--enable-mime-magic \
--enable-so \
--enable-static-support \
--enable-static-rotatelogs
make
make install
make clean
% sh apache.build.sh
php-5.2.4.tar.bz2
をSC430の時のスクリプトを利用してコンパイル。MySQLは指定だけしてみる。
#!/bin/sh
#### (compile option enviroments)
export CFLAGS="-DHAVE_BROKEN_REALPATH -O3"
export CXX=gcc
export CXXFLAGS="-O3"
#### PHP build
cd /usr/src
tar xvf /dist/php-5.2.4.tar.bz2
cd php*
{
./configure \
--with-apxs2=/usr/local/apache2/bin/apxs \
--enable-zend-multibyte \
--enable-mbstring \
--enable-mbregex \
--enable-bcmath \
--enable-calendar \
--enable-ctype \
--enable-exif \
--enable-ftp \
--with-gd \
--with-jpeg-dir=/usr/local \
--with-ttf \
--with-freetype-dir=/usr/local \
--enable-gd-native-ttf \
--enable-gd-jis-conv \
--with-zlib \
--with-mysql \
--enable-sockets \
--with-mime-magic \
--with-config-file-scan-dir=/usr/local/etc
make
make install
make clean
% sh php.build.sh
やはりMySQLは外部のクライアントライブラリがないと駄目みたい。・・・ん?そういえばインストーラCDのパッケージ集にクライアントが無かったか?
ところで、configureって「コンフィギャ」?「コンフィギュア」?。MySQLのマニュアルでは「コンフィギャ」って訳されていたけど。
ありました、ありました!mysql-client-5.0.27.tbz。早速パッケージ追加してビルドオプションを次の通りに変更し、make distclean
をしてからインストール再実行。
あいやー、「メモリが足んねぇぞゴルァ!」というエラーでコンパイル中止。しまった、32Mじゃ足りないか。
振り出しに戻り、仮想マシンのメモリは64M、FreeBSDをスワップ領域512Mとルートのみで最小インストールからやり直し。(泣)
やっとでPHPインストール終了まで戻ってきた。仮想マシンは非力だからコンパイルに2時間程度待つのよね。
Don't forget to run 'make test'.
ん?なんだこれ。「‘make test’の実行を忘れるなよ」・・・こんなメッセージ&makeオプションあったっけ?・・・とりあえずそれは後にしてWeb動作テストしてみる。
やっぱりうまくいかない。スクリプトを全てUTF-8にて保存し、php.iniを設定し直してあるのだが。
output_handler = "mb_output_handler"
mbstring.language = Japanese
mbstring.internal_encoding = UTF-8
mbstring.script_encoding = UTF-8
mbstring.http_input = auto
mbstring.http_output = UTF-8
mbstring.encoding_translation = On
mbstring.detect_order = auto
mbstring.substitute_character = none
mbstring.func_overload = 0
mbstring.strict_encoding = On
mbstring.strict_detection = On
Directive | Local Value | Master Value |
---|---|---|
default_charset | no value | no value |
default_mimetype | text/html | text/html |
output_buffering | 4096 | 4096 |
output_handler | mb_output_handler | mb_output_handler |
Multibyte Support | enabled |
Multibyte string engine | libmbfl |
HTTP input encoding translation | enabled |
Multibyte (japanese) regex support | enabled |
Multibyte regex (oniguruma) version | 4.4.4 |
Multibyte regex (oniguruma) backtrack check | On |
mbstring extension makes use of "streamable kanji code filter and converter", which is distributed under the GNU Lesser General Public License version 2.1. |
Directive | Local Value | Master Value |
---|---|---|
mbstring.detect_order | auto | auto |
mbstring.encoding_translation | On | On |
mbstring.func_overload | 0 | 0 |
mbstring.http_input | auto | auto |
mbstring.http_output | UTF-8 | UTF-8 |
mbstring.internal_encoding | UTF-8 | UTF-8 |
mbstring.script_encoding | UTF-8 | UTF-8 |
mbstring.language | Japanese | Japanese |
mbstring.strict_detection | On | On |
mbstring.substitute_character | none | none |
当然、php.iniファイルを変更したらapacheを再起動する。パスは通しておいたし。
% apachectl restart
キーワード「PHP5 文字化け」で調べても、大概はスクリプトファイルの保存エンコーディングとエンコーディング設定の食い違いによって表示が文字化けする場合の情報だ。しかし目の前の状況はというと、表示はうまくいっているのだがフォームからの入力(HTTPクエリ)が文字化けするのである。さらにCPUの使用率が異常になるのは明らかに他の場合とは違うようだ。
・・・ということは、設定が原因ではなくてやはりコンパイルされたバイナリがおかしい状況なのかもしれない。そう思った時、あのコマンドを思い出したので試してみる。
% cd /usr/src/php* % make test
あれ?またコンパイルが始まった・・・。あ、そうか、make clean
をやった後だったので(コンパイルスクリプトを参照)、またコンパイルから始まってしまうのか・・・。とりあえずまた2時間待たされることに。(泣)
3000弱ぐらいのテストで1時間ほどかかりました。こんなにたくさんテスト項目があったとは・・・。それはさておき、失敗「FAIL」の割合が10%近く・・・いいのか?!コレ。結構普段使いそうな関数でも失敗しているみたいだし。試しにWeb動作テストしてみたらやっぱりおかしいまま。
ひょっとするとコンパイラオプションで最適化しすぎなのかな?やりすぎると実行時に不具合が出ることがあるってどっかで聞いたことあるし・・・。と思って-O3
を-O2
にしてコンパイルし直してみる。今度はmake clean
をコメントアウトして。
それでもWeb動作テストの結果は同じ。今度は(どっかの情報のうろ覚えから)設定ファイルが結果を左右することがあるらしいので、php.iniを一旦消してmake test
してみる。
make testの結果は成功「PASS」の割合が99%まで上がった。最適化オプションが原因なのかphp.iniを一旦消したのが原因なのかよくわからなくなってしまったのだが、まぁいいや後にしよ(お)。
そういえばXREAはPHP5なのにこんな現象起きていないんだよなぁ・・・。ということは設定ファイルをもう一度見直してみる必要が出てきた。自分の頭の中だけでは固定観念があるかもしれないので、XREAのphpinfo()
結果とにらめっこしながら、関連部分の設定をそのまま写してみる。
写してみたものの、Web動作は全く変わらない。もう一度設定ファイルをにらめっこする。タブが含まれていたのでスペースに置き換えてみたり、全角スペースがないか探してみたりもした。phpinfo()
や非マルチバイトなスクリプトだけは動作するので、XREAのものと比べてみたりもした。コンパイルオプションには
なんてのもあったが、やっぱり変化無し。
phpinfo()
結果をよーく見比べてみたら。
Directive | Local Value | Master Value |
---|---|---|
detect_unicode | On | On |
なんだコレ?見たことないやつだな・・・と思って調べてみた。だがマニュアルに載っていないし、php.ini-reccomendやphp.ini-distにも記述されていない!。試しに明示的に解除してみた。
detect_unicode = Off
あっ!
・・・できた。CPU喰いまくっていたテストスクリプトはすぐに反応が返ってきて、フォームからの入力も正常に反映されているようだ。本番と同じスクリプトを動作してみても、今までの不具合が何事もなかったように動作している。ただ、若干フォントやレイアウトが崩れているのが気になったが、これはUTF-8に揃えた時にスタイルシート等のエンコーディングに間違いがあるからだろう。
早速「PHP5 detect_unicode」で調べてみたが、MLで別の事例で取り上げられているぐらいで、今回の事例は一般的でないかもしれない。apache2のビルドや設定も関連しているかもしれないが、調査するにはもっと時間がかかるだろう。
・・・と思ったのもつかの間。detect_unicode
以外の指定をシフトJIS向けに戻してみたら・・・やっぱり異常動作になってしまった。どっかで見たけど、自動変換をあてにしないほうがいいのかもしれない・・・。(泣)
ていうか、まさかapache2だからか?
・・・なんて思考さえ出てくる始末だ。振り出しに戻ってしまった。
ふと思い出したので再々チャレンジしてみる。とりあえず目的のPHP・HTML・CSS・JSをUTF-8にし直してみる。そしてphp.iniも設定しなおす。
output_buffering = 4096 output_handler = "mb_output_handler" default_mimetype = "text/html" ;default_charset = "iso-8859-1" ;detect_unicode = Off default_charset = "UTF-8" mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.script_encoding = UTF-8 mbstring.http_input = auto mbstring.http_output = UTF-8 mbstring.encoding_translation = On mbstring.detect_order = auto mbstring.substitute_character = long mbstring.func_overload = 0 ;mbstring.strict_encoding = On ;mbstring.strict_detection = On
一応、文字化けしないで表示はされている。が、なんか変。Firefoxだどいいんだけど、InternetExplorerだとフォントが得体の知れない設定になっているようで、日本語は日本語フォントに、英数字は欧文フォントになっているのよね。スタイルシートで設定してみたが、あまり気持ちの良いものではない。
しかし、データを入力してみると、返ってきたのはやっぱり文字化け・・・というか、変換に失敗して数値表示になっている(前述のphp.iniの設定参照)。やっぱりだめか・・・?。でもとりあえずPHPからの出力がおかしいわけではないようだ。
UTF-8でテストスクリプト・・・フォームからPOSTで受け取り、ファイルに保存、ファイルから読み直して表示するスクリプトを動かしてみる。表示も入力も問題ない。
シフトJISでテストスクリプトを動かしてみる。ページは文字化けした。が、データは文字化けしてない?
受け取ったデータをmb_detect_encoding()
に突っ込んだ結果も表示させてみる。ん?UTF-8か。
ちょっと気になってphp.iniを設定しなおす。
mbstring.script_encoding = auto
シフトJISのテストスクリプトを動かしてみる。ん?うまくいってるよ・・・?。データはUTF-8だ。
同じくUTF-8のテストスクリプトを動かしてみる。ん、これもうまくいってるよ・・・?。ということは、script_encodingの設定もちゃんと効いているってことかな?。
その気になってphp.iniを設定しなおす。
mbstring.http_output = SJIS
シフトJISのテストスクリプトを動かしてみる。ん?うまくいってるよ・・・?。データはUTF-8だ。しかも欧文フォントが混じらなくなった。
UTF-8のテストスクリプトを動かしてみる。ん?これもうまくいってるな。データはUTF-8だ。こっちも欧文フォントが混じらなくなった。
それじゃあ本番のスクリプトを、と思ってオリジナルからシフトJISのスクリプトをコピーして動かしてみた・・・。
あっっ!
いけてるじゃん。ちゃんと表示されてるよ。
じゃあデータの入力は?・・・
げっ!
やっぱダメじゃん。なんでー(泣)。どこが違うのかな・・・マニュアルを読み返してみるか。
注意: PHP 4.3.0 以降、このオプション --enable-mbstr-enc-trans は廃止され、実行時の設定 mbstring.encoding_translation に変更となります。HTTP 入力文字エンコーディング変換は、 このオプションを On に設定した場合のみ 有効となります (デフォルトは Offです)。
注意: PHP 4.3.2 およびそれ以前のバージョンの場合、 HTML フォームのenctype が multipart/form-data に設定された場合、 mbstring は、POST データの文字エンコーディングを変換しません。 この場合、文字列を内部文字エンコーディングに変換してやる必要があります。
注意: PHP 4.3.3 以降、HTML フォームの enctype が multipart/form-data に設定され、かつ、 php.ini において mbstring.encoding_translation に On が指定されている場合、 POST データの変数とアップロードされたファイルの名前の文字エンコーディングは、 内部文字エンコーディングに変換されます。 ただし、クエリキーに関しては、変換されません。PHPマニュアルより
・・・うん、問題ないよなぁ。mbstring.encoding_translationはOnになっているしなぁ。ていうか同じ設定で動作が違うというのはどういうこと?。multipart/form-dataは確か最近のバージョンじゃ「強制的にpass」しなかったはずだよなぁ。
キーワード「PHP5 multipart」で調べてみた・・・。ん?メーリングリストに同じような症状の人がいる・・・。
PHP5.2.0でmultipart/form-dataを指定するとPOSTしたマルチバイト文字が文字化けするらしい。自分も試してみよう。
UTF-8のテストスクリプト中のformタグにenctype="multipart/form-data"
を追記して動かしてみる。表示はいいな。
あぁっ!
入力したら文字化けした!。
同じようにシフトJISのテストスクリプト中のformタグにenctype="multipart/form-data"
を追記して動かしてみる。こちらもページ表示はいいな。すでにデータはさっきので化けてるけど。
ひぃっ!
やっぱり入力したら文字化けした!。データはSJISになってる・・・。
先ほどの調査の結果からメーリングリストのログをあさってみる。成果は・・・
といった感じだった。結局その人は自己エンコーディングすることにしたらしい。自己エンコーディングしかないのかなぁ・・・。
UTF-8のテストスクリプトを改造する。次を頭に追記。
mb_convert_variables(mb_internal_encoding(), 'auto', $_POST, $_GET);
スクリプトを動かしてみる・・・あぁ・・・データを入力しても問題ないな。(テンション低い)
同じようにシフトJISのテストスクリプトを改造して動かしてみる。あぁ・・・これも問題ないな。(やっぱりテンション低い)
それじゃあ、と本番のシフトJISのスクリプトを動かしてデータの入力・・・
できた。
できたよ。
君は青春のゴールだったよ。
ねぇ・・・わかってたんだよ。
・・・わかってるんだよ。
ということで(何がじゃ)PHPユーザグループで投げかけてみようかしら。
<?php
// (PHP5で)multipart/form-data使用時に自動エンコーディングの補完
if ( ini_get('mbstring.encoding_translation') == 1 ) {
mb_convert_variables(mb_internal_encoding(), 'auto', $_POST, $_GET);
}
?>
これをスタートアップスクリプトに書く。通常の使い方なら勝手に変換しても問題ないと思うが・・・。RAWなデータを扱うとしても多分別の変数イコール別の領域だと思いたい。
<?php
// (PHP5で)multipart/form-data使用時に自動エンコーディングの補完
if ( ini_get('mbstring.encoding_translation') and isset($_SERVER["CONTENT_TYPE"]) and strpos($_SERVER["CONTENT_TYPE"], "multipart/form-data;") === 0 ) {
mb_convert_variables(mb_internal_encoding(), 'auto', $_POST, $_GET, $_REQUEST);
if ( is_array($_FILES) and count($_FILES) ) foreach ( $_FILES as $input => $hash ) {
mb_convert_variables(mb_internal_encoding(), 'auto', $_FILES[$input]['name']);
}
}
?>
前のやつを本気で訂正。$_REQUEST
と$_FILES[]['name']
もやっとかないとダメみたいだ。あと条件を少し厳密にしてみる。
XREAのサーバだとmbstring.script_encoding
を指定しても有効にならなかったんだけど(当然phpinfo()
にも反映されない)、Win32バイナリのPHP 5.2.5
でもやっぱりmbstring.script_encoding
が有効にならなかったんだよなぁ。でもソースからコンパイルしたPHP 5.2.4
では有効になる・・・configureオプションか?。
mbstring.script_encoding
の指定はconfigureオプションで--enable-zend-multibyte
を指定する必要があるそうな。なるほど、XREAのサーバのPHP 5.2.3
もWin32バイナリのPHP 5.2.5
も--enable-zend-multibyte
の指定が無かった。自分でコンパイルしたのは(以下略)。
<?php
// (PHP5で)multipart/form-data使用時に自動エンコーディングの補完
if ( ini_get('mbstring.encoding_translation') and isset($_SERVER["CONTENT_TYPE"]) and strpos($_SERVER["CONTENT_TYPE"], "multipart/form-data;") === 0 ) {
mb_convert_variables(mb_internal_encoding(), 'auto', $_POST, $_GET);
if ( is_array($_FILES) and count($_FILES) ) foreach ( $_FILES as $input => $hash ) {
mb_convert_variables(mb_internal_encoding(), 'auto', $_FILES[$input]['name']);
}
$_REQUEST = $_POST + $_FILES + $_GET + $_COOKIE;
}
?>
しまった、$_REQUEST
の中には$_FILES
や$_COOKIE
もすでに入ってしまってるのでダメだ。
ついでなのだがPDF出力したいのでPDF関数を使ってみる・・・。そんな関数は無いと蹴られる。やっぱそうだよな・・・。
PDFlibが有名どころらしいが、なんとなく有料ライセンスになりそうだ。ちょっと他のを探してみよう。
これもなんとなく有料ライセンスになりそうだ。有料しかないのかな?
あー、無料なのあるじゃん。でもJPEG画像に対応してるのかな?
あれ?PDFlibの無料版PDFlib-Lite
(http://www.pdflib.com/download/free-software/pdflib-lite/)があるじゃん。なんとなくギリギリ無料ライセンスでよさそうだな。ちょっと試してみよう。PDFlib-Lite-7.0.2p8.tar.gzか。
で?PECLインストール?なにそれ?おいしいもの?(笑)。
ということで調べてみたが・・・そのコマンドのパラメータってリモートファイルじゃね?。おいおい、インターネット接続を前提にされると困ります。
結局巡り巡ってPHPマニュアルに辿りついた。./configure
の直前でphpize
を実行すればよいらしい。そういえば前に「何コレ?」って思っていたファイルだったり。
で、サクっとコンパイルスクリプトを組んで実行してみた。・・・が、
Cannot find config.m4. Make sure that you run '/usr/local/bin/phpize' in the top level source directory of the module
phpizeでconfig.m4が見つからないとエラー。ソースディレクトリに入ったところ/usr/src/PDFlib-Lite-7.0.2/だし。別の場所かと思って何度もソースディレクトリを調べてみたが、そんなものは何処にも無い。
無い。やっぱりない。ん?そういえばメーリングリストでPECLのインストールできない話があったような。でももうどこで見たか忘れた。確か、ライブラリとモジュールのインストールはそれぞれ別だったとか・・・。
気になってPHPマニュアルを見たらPECL 拡張モジュールのダウンロードはhttp://pecl.php.net/package/pdflib、と書いてあったので見に行ったら、pdflib-2.1.4.tgzなるものがあった。こっちは小文字。
別かもしれないのでとりあえずPDFlib-Liteをコンパイル。こっちは大文字。ややこしや。とりあえずインストールされたらしい。
あら、やっぱりconfig.m4はこっちにあったのね。小文字のpdflibをphpize付きでコンパイル。ややこしや。っと、あれ?
あれ?
Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable is set correctly and then rerun this script.
あ、もしかしてautoconf
とautomake
ってまだ入っていないのかしら?
% which autoconf % find / -name "autoconf*"
・・・入っていなかったらしい(笑)。こういう微妙なものは先に入ってくれるとありがたいようなそうでもないような。とりあえずCDにgnu-autoconf-2.59.tbz
とgnu-automake-1.9.6.tbz
があったのでパッケージインストール。
あれ?
Cannot find autoconf. (以下略)
なんで?違うの?これじゃないの?。もう一度調べてみると、環境によっては名前が違ってたりすることもあるとか。で、こいつの場合は
/usr/local/gnu-autotools/bin/autoconf
パス違ぇーじゃん。パス通ってないじゃん。どうしようかな?シンボリックリンクを作っている人もいたけど・・・スクリプト内だけでパス通しちゃうか。
あれ?パス通らない・・・。あっ、path
じゃなくてPATH
か(笑)。
ようやっとビルド作業が進んだ。autoconfってconfigure作るのね。へぇ。
で、コンパイル終了。
ちょっと待て。PDFlibのライブラリの場所を指定してないけど、大丈夫か?。./configure --help
してみると、
--with-pdflib=DIR Include PDFlib support.
あぁっ、やっぱり(泣)。じゃあconfigureのログは?
checking for PDFlib support... yes, shared
・・・あ、探せたのかも。
早速php.iniを編集・・・。ちょっとまて、;extension=php_zip.dllって何だ?Windows版のphp.iniじゃねぇかよ(爆笑)。まぁ動いているからいいや。(おい)
extension=pdf.so
% apachectl restart
とりあえずモジュール組み込みできたみたい。phpinfoのPDFlib GmbH Versionでバージョンが正しく表示されているので大丈夫でしょう。
PHPマニュアルに載っていたサンプルスクリプトを実行させてみる・・・・。
・・・・(沈黙)
Hello world!
(says PHP)
できた!よっしゃー!
コンパイルスクリプトはこんな感じ。
(作成中)
(作成中)
サンプルをいじって日本語を表示させようと思うのだがエラーの連続。さっっぱりわからない。
ふとfPDFだと日本語対応していたよなーと思って調べてみたら、JPEG使えるじゃん!fPDIなんてあるじゃん!やっぱこっちにしよ。(笑)
早速情報収集。必要なものは・・・
それぞれ展開したフォルダの中のファイルやフォルダをひとまとめにして、PHPのインクルードパスに置く。本来、mdfPDI.phpはfPDI.phpをコピーしたものにパッチ当てをして作るのだが、勘のいい人は(→オレ?)テキストエディタでmbfpdi102.patch.gzとfPDI.phpをテキストエディタで開き、2ヶ所ほどコピペしたのち名前を変えて保存すればすむ事に気づくだろう。
あと自分の場合はサーバの適当な所に置いて、php.iniをこんな感じに。(Windowsサーバ)
include_path = ".;X:\public_html\fpdf"
とりあえずPDF出力するだけのサンプルスクリプトをコピペしたのを実行。ブラボ〜!
PDI機能を使ってみる・・・ちょっとスクリプトをいじる必要があったので少してこずったが・・・。ブラボ〜!
な〜んだ、こんなに簡単なら最初からこっちにしとけば良かった。
頑張ってさらにmbfpdiにオーバーロードするクラスを作成。
それとは別に、mbfpdiの半角カタカナの幅計算でEUC-JP依存だったバグを直接修正。