SC430のうろ覚え

最終更新:

番外:テスト用仮想サーバにてPHP5リベンジ

Microsoft Virtual PC 2003にて、PHP5に再挑戦してみる。Virtual PCについてはインストーラで簡単にインストールできるのでここでは書かないけど。

FreeBSD 6.2インストール

メモリは32M、ハードディスクは4GBで仮想マシンを作成しておき、FreeBSD 6.2-RELEASE i386のインストール。一旦自動でスワップ領域の大きさを調べておき、スワップ領域とルートのみにしておいた。んで最小インストール。

apacheをパッケージインストール???

時間短縮でapacheをパッケージインストールしようとしたら・・・無いじゃん。>FreeBSD 6.2 CD

とりあえず必要なものをパッケージインストール

apacheはあきらめて、他に必要っぽいものをパッケージインストール。この時点ではImageMagickもインストールするつもりだった。

apache2をコンパイル

httpd-2.0.61.tar.gzをSC430の時のスクリプトを利用してコンパイル。

apache.build.sh
#!/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
PHP5をコンパイル

php-5.2.4.tar.bz2をSC430の時のスクリプトを利用してコンパイル。MySQLは指定だけしてみる。

php.build.sh
#!/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
configureエラー

やはりMySQLは外部のクライアントライブラリがないと駄目みたい。・・・ん?そういえばインストーラCDのパッケージ集にクライアントが無かったか?

ところで、configureって「コンフィギャ」?「コンフィギュア」?。MySQLのマニュアルでは「コンフィギャ」って訳されていたけど。

パッケージ追加

ありました、ありました!mysql-client-5.0.27.tbz。早速パッケージ追加してビルドオプションを次の通りに変更し、make distcleanをしてからインストール再実行。

今度はコンパイルエラー

あいやー、「メモリが足んねぇぞゴルァ!」というエラーでコンパイル中止。しまった、32Mじゃ足りないか。

振り出しに戻り、仮想マシンのメモリは64M、FreeBSDをスワップ領域512Mとルートのみで最小インストールからやり直し。(泣)

make直後の不思議なメッセージ

やっとでPHPインストール終了まで戻ってきた。仮想マシンは非力だからコンパイルに2時間程度待つのよね。

Don't forget to run 'make test'.

ん?なんだこれ。「‘make test’の実行を忘れるなよ」・・・こんなメッセージ&makeオプションあったっけ?・・・とりあえずそれは後にしてWeb動作テストしてみる。

やっぱり・・・orz

やっぱりうまくいかない。スクリプトを全てUTF-8にて保存し、php.iniを設定し直してあるのだが。

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
PHP Core
DirectiveLocal ValueMaster Value
default_charsetno valueno value
default_mimetypetext/htmltext/html
output_buffering40964096
output_handlermb_output_handlermb_output_handler
mbstring
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.
DirectiveLocal ValueMaster Value
mbstring.detect_orderautoauto
mbstring.encoding_translationOnOn
mbstring.func_overload00
mbstring.http_inputautoauto
mbstring.http_outputUTF-8UTF-8
mbstring.internal_encodingUTF-8UTF-8
mbstring.script_encodingUTF-8UTF-8
mbstring.languageJapaneseJapanese
mbstring.strict_detectionOnOn
mbstring.substitute_characternonenone

当然、php.iniファイルを変更したらapacheを再起動する。パスは通しておいたし。

% apachectl restart
逃げてちゃ駄目だ!×3

キーワード「PHP5 文字化け」で調べても、大概はスクリプトファイルの保存エンコーディングとエンコーディング設定の食い違いによって表示が文字化けする場合の情報だ。しかし目の前の状況はというと、表示はうまくいっているのだがフォームからの入力(HTTPクエリ)が文字化けするのである。さらにCPUの使用率が異常になるのは明らかに他の場合とは違うようだ。

・・・ということは、設定が原因ではなくてやはりコンパイルされたバイナリがおかしい状況なのかもしれない。そう思った時、あのコマンドを思い出したので試してみる。

% cd /usr/src/php*
% make test
make testの罠

あれ?またコンパイルが始まった・・・。あ、そうか、make cleanをやった後だったので(コンパイルスクリプトを参照)またコンパイルから始まってしまうのか・・・。とりあえずまた2時間待たされることに。(泣)

散々な結果

3000弱ぐらいのテストで1時間ほどかかりました。こんなにたくさんテスト項目があったとは・・・。それはさておき、失敗「FAIL」の割合が10%近く・・・いいのか?!コレ。結構普段使いそうな関数でも失敗しているみたいだし。試しにWeb動作テストしてみたらやっぱりおかしいまま。

ひょっとすると

ひょっとするとコンパイラオプションで最適化しすぎなのかな?やりすぎると実行時に不具合が出ることがあるってどっかで聞いたことあるし・・・。と思って-O3-O2にしてコンパイルし直してみる。今度はmake cleanをコメントアウトして。

ハッハッハッハ、さっっぱりわからない。by 湯川 学

それでもWeb動作テストの結果は同じ。今度は(どっかの情報のうろ覚えから)設定ファイルが結果を左右することがあるらしいので、php.iniを一旦消してmake testしてみる。

ふーん

make testの結果は成功「PASS」の割合が99%まで上がった。最適化オプションが原因なのかphp.iniを一旦消したのが原因なのかよくわからなくなってしまったのだが、まぁいいや後にしよ(お)

現象には必ず理由がある。by 湯川 学

そういえばXREAはPHP5なのにこんな現象起きていないんだよなぁ・・・。ということは設定ファイルをもう一度見直してみる必要が出てきた。自分の頭の中だけでは固定観念があるかもしれないので、XREAのphpinfo()結果とにらめっこしながら、関連部分の設定をそのまま写してみる。

実に面白い。by 湯川 学

写してみたものの、Web動作は全く変わらない。もう一度設定ファイルをにらめっこする。タブが含まれていたのでスペースに置き換えてみたり、全角スペースがないか探してみたりもした。phpinfo()や非マルチバイトなスクリプトだけは動作するので、XREAのものと比べてみたりもした。コンパイルオプションには

なんてのもあったが、やっぱり変化無し。

んぉ?

phpinfo()結果をよーく見比べてみたら。

PHP Core
DirectiveLocal ValueMaster Value
detect_unicodeOnOn

なんだコレ?見たことないやつだな・・・と思って調べてみた。だがマニュアルに載っていないし、php.ini-reccomendphp.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からの出力がおかしいわけではないようだ。

テスト1・UTF-8

UTF-8でテストスクリプト・・・フォームからPOSTで受け取り、ファイルに保存、ファイルから読み直して表示するスクリプトを動かしてみる。表示も入力も問題ない。

テスト2・Shift_JIS

シフトJISでテストスクリプトを動かしてみる。ページは文字化けした。が、データは文字化けしてない?

テスト3・Shift_JIS

受け取ったデータをmb_detect_encoding()に突っ込んだ結果も表示させてみる。ん?UTF-8か。

php.iniの変更2

ちょっと気になってphp.iniを設定しなおす。

mbstring.script_encoding = auto
テスト4・Shift_JIS

シフトJISのテストスクリプトを動かしてみる。ん?うまくいってるよ・・・?。データはUTF-8だ。

テスト5・UTF-8

同じくUTF-8のテストスクリプトを動かしてみる。ん、これもうまくいってるよ・・・?。ということは、script_encodingの設定もちゃんと効いているってことかな?。

php.iniの変更3

その気になってphp.iniを設定しなおす。

mbstring.http_output = SJIS
テスト6・Shift_JIS

シフトJISのテストスクリプトを動かしてみる。ん?うまくいってるよ・・・?。データはUTF-8だ。しかも欧文フォントが混じらなくなった。

テスト7・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_translationOnになっているしなぁ。ていうか同じ設定で動作が違うというのはどういうこと?。multipart/form-dataは確か最近のバージョンじゃ「強制的にpass」しなかったはずだよなぁ。

困った時の検索頼み

キーワード「PHP5 multipart」で調べてみた・・・。ん?メーリングリストに同じような症状の人がいる・・・。

これかっ!?

PHP5.2.0でmultipart/form-dataを指定するとPOSTしたマルチバイト文字が文字化けするらしい。自分も試してみよう。

テスト8・UTF-8

UTF-8のテストスクリプト中のformタグにenctype="multipart/form-data"を追記して動かしてみる。表示はいいな。

あぁっ!

入力したら文字化けした!。

テスト9・Shift_JIS

同じようにシフトJISのテストスクリプト中のformタグにenctype="multipart/form-data"を追記して動かしてみる。こちらもページ表示はいいな。すでにデータはさっきので化けてるけど。

ひぃっ!

やっぱり入力したら文字化けした!。データはSJISになってる・・・。

引き続き捜査せよ

先ほどの調査の結果からメーリングリストのログをあさってみる。成果は・・・

といった感じだった。結局その人は自己エンコーディングすることにしたらしい。自己エンコーディングしかないのかなぁ・・・。

テスト10・UTF-8

UTF-8のテストスクリプトを改造する。次を頭に追記。

mb_convert_variables(mb_internal_encoding(), 'auto', $_POST, $_GET);

スクリプトを動かしてみる・・・あぁ・・・データを入力しても問題ないな。(テンション低い)

テスト11・Shift_JIS

同じようにシフト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出力したいのでPDF関数を使ってみる・・・。そんな関数は無いと蹴られる。やっぱそうだよな・・・。

PDFlib

PDFlibが有名どころらしいが、なんとなく有料ライセンスになりそうだ。ちょっと他のを探してみよう。

clibPDF

これもなんとなく有料ライセンスになりそうだ。有料しかないのかな?

fPDF

あー、無料なのあるじゃん。でもJPEG画像に対応してるのかな?

PDFlib-Lite

あれ?PDFlibの無料版PDFlib-Litehttp://www.pdflib.com/download/free-software/pdflib-lite/)があるじゃん。なんとなくギリギリ無料ライセンスでよさそうだな。ちょっと試してみよう。PDFlib-Lite-7.0.2p8.tar.gzか。

はじめてのPECL

で?PECLインストール?なにそれ?おいしいもの?(笑)
ということで調べてみたが・・・そのコマンドのパラメータってリモートファイルじゃね?。おいおい、インターネット接続を前提にされると困ります。

はじめてのphpize

結局巡り巡って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付きでコンパイル。ややこしや。っと、あれ?

autoconfの罠

あれ?

Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF
environment variable is set correctly and then rerun this script.

あ、もしかしてautoconfautomakeってまだ入っていないのかしら?

ねぇ、入ってる?
% which autoconf
% find / -name "autoconf*"

・・・入っていなかったらしい(笑)。こういう微妙なものは先に入ってくれるとありがたいようなそうでもないような。とりあえずCDにgnu-autoconf-2.59.tbzgnu-automake-1.9.6.tbzがあったのでパッケージインストール。

autoconfの罠、リターンズ

あれ?

Cannot find autoconf. (以下略)

なんで?違うの?これじゃないの?。もう一度調べてみると、環境によっては名前が違ってたりすることもあるとか。で、こいつの場合は

/usr/local/gnu-autotools/bin/autoconf

パス違ぇーじゃん。パス通ってないじゃん。どうしようかな?シンボリックリンクを作っている人もいたけど・・・スクリプト内だけでパス通しちゃうか。

ちょいミス

あれ?パス通らない・・・。あっ、pathじゃなくてPATH(笑)

autoconf、はじめました

ようやっとビルド作業が進んだ。autoconfってconfigure作るのね。へぇ。

で、コンパイル終了。

何か忘れているような

ちょっと待て。PDFlibのライブラリの場所を指定してないけど、大丈夫か?。./configure --helpしてみると、

--with-pdflib=DIR     Include PDFlib support.

あぁっ、やっぱり(泣)。じゃあconfigureのログは?

checking for PDFlib support... yes, shared

・・・あ、探せたのかも。

php.ini

早速php.iniを編集・・・。ちょっとまて、;extension=php_zip.dllって何だ?Windows版のphp.iniじゃねぇかよ(爆笑)。まぁ動いているからいいや。(おい)

php.ini(変更点)
extension=pdf.so
% apachectl restart
完了

とりあえずモジュール組み込みできたみたい。phpinfoのPDFlib GmbH Versionでバージョンが正しく表示されているので大丈夫でしょう。

テスト

PHPマニュアルに載っていたサンプルスクリプトを実行させてみる・・・・。
・・・・(沈黙)

Hello world!
(says PHP)

できた!よっしゃー!

メモ

コンパイルスクリプトはこんな感じ。

PDFlib-Lite.build.sh
(作成中) 
pdflib.pecl.sh
(作成中) 
しかしそんなに甘くない

サンプルをいじって日本語を表示させようと思うのだがエラーの連続。さっっぱりわからない。

鞍替え

ふとfPDFだと日本語対応していたよなーと思って調べてみたら、JPEG使えるじゃん!fPDIなんてあるじゃん!やっぱこっちにしよ。(笑)

さっそく

早速情報収集。必要なものは・・・

インストール

それぞれ展開したフォルダの中のファイルやフォルダをひとまとめにして、PHPのインクルードパスに置く。本来、mdfPDI.phpfPDI.phpをコピーしたものにパッチ当てをして作るのだが、勘のいい人は(→オレ?)テキストエディタでmbfpdi102.patch.gzfPDI.phpをテキストエディタで開き、2ヶ所ほどコピペしたのち名前を変えて保存すればすむ事に気づくだろう。

あと自分の場合はサーバの適当な所に置いて、php.iniをこんな感じに。(Windowsサーバ)

php.ini(変更点)
include_path = ".;X:\public_html\fpdf"
サンプルその1

とりあえずPDF出力するだけのサンプルスクリプトをコピペしたのを実行。ブラボ〜!

サンプルその2

PDI機能を使ってみる・・・ちょっとスクリプトをいじる必要があったので少してこずったが・・・。ブラボ〜!

な〜んだ、こんなに簡単なら最初からこっちにしとけば良かった。

ラッパー

頑張ってさらにmbfpdiにオーバーロードするクラスを作成。

それとは別に、mbfpdiの半角カタカナの幅計算でEUC-JP依存だったバグを直接修正。


SC430インデックスへ
トップページへ

こな