PHPの最近のブログ記事

ちょっと他人の書いた PHP の修正案件があったので、メモ。

UTF-8 で書かれた PHP ソースの中で、以下のような記述でメールの送信を行っている。

$w_from = "From: ほげほげ星人 <no-reply@exsample.jp>";
$w_to = "hogehoge@exsample.com"
$w_subject = "[返信]ありがとうございます";
$w_body = "あれやこれや...";

mb_language("Japanese");
mb_internal_encoding("UTF-8");

mb_send_mail($w_to, $w_subject, $w_body,  $w_from);

が、これ、実際にはむちゃくちゃな内容のメールが届く。

Content-Type: text/plain; charset=ISO-2022-JP
Content-Transfer-Encoding: 7bit

とか言いながら本文は UTF-8 だし、FROM アドレスは MIME B エンコードされず、Subject だけは ISO-2022-JP で MIME B エンコードされているという状況である。

まあ、最近のメールソフト(Web メール含む)は charset の記述を無視して、実際に本文の文字コードをチェックして表示を行うものが多いから、こんな状況でも一見、ちゃんと表示されてたりするので大丈夫・・・というか、質が悪いな、これ(^^;
なんのための、charset 指定だっつうの(^^;

どうも、UTF-8 のメールを送りたいようなので、

$w_from = "From: ほげほげ星人 <no-reply@exsample.jp>";
$w_to = "hogehoge@exsample.com"
$w_subject = "[返信]ありがとうございます";
$w_body = "あれやこれや...";

header('Content-Type: text/html; charset=UTF-8');
header('Content_Language: ja');

mb_language("uni");
mb_internal_encoding("UTF-8");

mb_send_mail($w_to, $w_subject, $w_body,  $w_from);

という具合に、Content-Type ヘッダーを明示的に指定し、mb_language は Japanese ではなく uni を指定してやれば、Subject は UTF-8 で MIME B エンコードされるし、

Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: BASE64

という Content-Type がセットされて、本文との整合性が取れる。

いや、俺の世代だと、そもそも UTF-8 のメールというのがすでに気持ち悪いのだけど、これも時代の流れ(^^;

・・・あ、うまくいったと思ったけど、これだと From アドレスは MIME B エンコードされないままだな。
そこは自前でエンコードしてからセットしてやる必要があるのか。ふむふむ。

$w_from = "From: " . mb_encode_mimeheader("ほげほげ星人", "UTF-8", "B") . " <no-reply@exsample.jp>";

だな。
そうか(^^;

PHP の round 関数に mode パラメータが追加されたのは 5.3.0 からか。
うちの一番 PHP のバージョンの古いサーバでテストしてたからエラーになってたんやな(^^;

まあ、それは良いとして、mode で PHP_ROUND_HALF_UP を指定したら、Excel 関数の ROUNDUP と同じ動きをしてくれるのかと思ってたら違うのね。

Excel 関数で

=ROUNDUP(1.05, 0)

とすれば、セルには 2 が表示される。

これと同じことを PHP でしたかったので、

round(1.05, 0, PHP_ROUND_HALF_UP)

としてみたけど、計算結果は 1。
うーん(^^;これ違うんだな。

ちなみに、

round(1.05, 0, PHP_ROUND_HALF_UP)
round(1.05, 0, PHP_ROUND_HALF_DOWN)
round(1.05, 0, PHP_ROUND_HALF_EVEN)
round(1.05, 0, PHP_ROUND_HALF_ODD)

このどれでも結果は 1 であります。

はぁ?っと思ったら、PHP ではこういう場合 ceil 関数を使うんだね。

ceil(1.05)

で、バッチリでありやした。(結局、round 関数の話じゃなくなったな(^^;)
他人様が作られた PHP ソースに「文字数チェック入れてもらえますか」と依頼があったので、

$w_len = mb_strlen($word);
if ($w_len > 300) {
Fnc_Err_Html("エラー","文字数が300文字を超えています。(" . $w_len . "文字)" );
}

とコードを追加しといたんだけど、何か、全角文字の時挙動がおかしい。

300文字を超えたらエラーになるようにしてるのに、200文字でもエラーになるし(^^;
600文字あると判断されてる様子。完全に、UTF-8 の全角1文字を3文字としてカウントしてる。コードが UTF-8 だとちゃんと認識してないから、全角1文字を構成する3バイトを3文字と判断してるんだな。

mb_strlen は第二引数に文字コードを指定できるが、指定しなきゃ内部コードを採用するはず。
ソースも UTF-8 で書かれているし、受け取るデータも UTF-8 である。なのに UTF-8 だと認識できていない・・・はぁ???

ググってみると、どうも、mb_strlen は文字コードが UTF-8 の時に限り、明示的にコードを指定しないといけないようだ・・・

明かなバグやないか(^^;

たまにしか PHP 使わないので知らんかったワ(^^;;;

$w_len = mb_strlen($word, "UTF-8");

とすれば OK であった・・・何やねん(^^;
あれこれ試した時間を返せ、こんにゃろ!(^^;

ところで、Web のフォーム入力されたデータを受け取ってるんだけど、フォームの入力中も文字数をチェックしてる。JavaScript でね。
で、JavaScript のチェックではOKになったデータが、PHP 側ではエラーになる。
どうも、JavaScript で document.form.hoge.value.length で取得すると「改行コード(CR+LF)は1文字として扱う」のに、mb_strlen は「CR と LF を1文字ずつ、計2文字として扱う」ようだ。
これも果てしなくバグ臭いのお(^^;
PHP プログラマは何も感じないのか、この仕様(^^;

まあ、これも、

$word = str_replace("\r\n", " ", $word);

してからチェックすればいいんだけど。

何だかなぁ~

<追記>
ああ、php -i してみたら、
mbstring.internal_encoding => no value => no value
になってんなあ。これだと、内部コードは ISO-8859-1 になっちゃうんかな?
ま、面倒くさがらず、mb_strlen の第二引数くらい設定しろってことやね(^^;すまん、すまん。
お客さんから「PDO の mysql ドライバ入れて!」と連絡あり。

うちの管理しているサーバの一つで、PHP プログラム動かそうとしたら「The mysql driver is not currently installed」って怒られたって。

ということで mysql driver をインストールしたわけだが、CentOS 4.8 のサーバなので、yum インストールしようにもリポジトリがもう正規の場所に無いし(^^;、設定変更するのも面倒なので手動でインストール。

# cd /usr/local/src
# /usr/local/bin/pecl download pdo_mysql
# tar xvfz PDO_MYSQL-1.0.2.tgz
# cd PDO_MYSQL-1.0.2
# /usr/local/bin/phpize
# ./configure --with-pdo-mysql=/usr/local/mysql
# make
# make install

で、すんなり入ったんだけど、/usr/local/lib/php.ini に、

extension = /usr/local/lib/php/extensions/no-debug-non-zts-20060613/pdo_mysql.so

って追加しても、一向に PDO mysql ドライバがロードされない。

# /usr/local/bin/php -i|grep PDO
PDO
PDO support => enabled
PDO drivers => sqlite2, sqlite
PDO Driver for SQLite 3.x => enabled

というまんま。

しばし悩んだが、結局、extension_dir の設定が、

extension_dir = /usr/lib64/php4

みたいに腐ってた(^^;
古い環境(PHP4系)から設定を移してる時、間違って入れちゃったんだな(^^;

これを、

extension_dir = /usr/local/lib/php/extensions
extension = no-debug-non-zts-20060613/pdo_mysql.so

みたいに設定してやれば、無事、

# /usr/local/bin/php -i|grep PDO
PDO
PDO support => enabled
PDO drivers => sqlite2, sqlite, mysql
PDO Driver for MySQL, client library version => 5.1.25-rc
PDO Driver for SQLite 3.x => enabled

となった。

う~む、php.ini の内容、一度ちゃんとチェックしといた方がええなあ(^^;;;
俺は「ショートタグなんか使うな!」と言われるようになってから PHP を触ることが多くなったもんで、ショートタグには違和感というか、悪感情しかない。使ったことがないんでね。

俺自身が絶対使うことはないし、うちから仕事を出した外注さんがショートタグ使って書いてきたら、無慈悲に作り直しを命じるだけである。(まあ、PHP開始タグを直すだけの話なんだから大したことじゃなけど)

まあ、最近はさすがに

<? phpinfo(); ?>

なんて書いてくる人はいなくなったけど、未だにに echo を書くのを、

<?= $hogehoge >

なんてする人はいる。

こんなの、<?php echo $hogehoge; > って書けばいいだけじゃん。'<?=' 使って、誰得?って思うんだけど、こういうのは、Perl の人が変数名省略するのと(要は $_ 使いたがるのと)一緒で、まあ、狭いコミュニティの中の「美学」があるんだろうけどなあ・・・

そんな美学、業務システム作る時には不要です。客先に納品する物は、省略せず、「冗長」にソースを書きましょう。

「省略の美学」は「自分一人だけで将来にわたってもメンテナンスするソース」だけで適用してください。

まあ、PHP 5.4 から、「ショートタグを許さない設定でも、<?= だけは許す」みたいな仕様になったみたいなんで、'<?='使いたいヤツって、糞みたいに多いんだろうなあ(^^;;;

いや、OpenID のサンプルコードの中にも一本だけ(discover.php)'<?='多用しているものがあったので書いてみました。(うちの PHP は 5.3.6 なので引っかかるのよ(^^;)

今時の PHP はディフォルトで、

short_open_tag = Off

って設定になってるのに、未だに <? echo 'hoge' ?> とか書いてくる人、頭おかしいの?親の教育がなってないわ!・・・とか思っちゃうわ、ホンマ(^^;

「すっきりしたソースになる」だって(笑)

お前、PHP しか知らない「Web プログラマ」だろ?

あのさあ、納品するソースはちゃんと「ディフォルト設定」で動くように書けよ。

お前が自宅のサーバで

short_open_tag = On

にしてプログラミングしてようが知ったこっちゃないけど、ユーザへの納品物を short open tag で書くのはやめろ。常識だろうが。

ホンマ、趣味の延長でプログラミングを仕事にしてる「Web プログラマ」は、「素人には冗長に見えても、『正しい』書き方で書くソースが一番美しい」ということに早く気づいてほしいわ。

仕事ではなく、自宅で趣味でプログラミングしている・・・っていう人は、好きなだけ short open tag 使ってください。

もう午前4時だ・・・俺はまだ十日市にいる。

ずっと PHP のインストールをしていたのだ。

今日時点で最新の PHP 5.3.8 をインストールしたところ、phpinfo の実行で、

Warning: phpinfo() [function.phpinfo]: It is not safe to rely on the system's timezone settings. You are *required* to use the date.timezone setting or the date_default_timezone_set() function. In case you used any of those methods and you are still getting this warning, you most likely misspelled the timezone identifier. We selected 'Asia/Tokyo' for 'JST/9.0/no DST' instead in /var/apache/htdocs/test.php on line 1

というようなワーニングが出てしまう。
どうも、Default timezone と php.ini で設定している timezone が同じでないと警告されるようなのだ。セキュリティの問題なのかな?よくわからんが、5.3系からの仕様らしい。

php.ini 内に

date.timezone = Asia/Tokyo

という記述を加えれば解決するらしいのだが、ここで困った問題が。

configure した時、特に --with-config-file-path は指定していないので、出来上がった php は /usr/local/lib/php.ini を参照するはずである。
なのに、phpinfo で表示されている Configuration File (php.ini) Path は /usr/local/php/lib を指しているのである。

/usr/local/lib/php.ini に date.timezone の記述を追加し、httpd を再起動しても状況変わらず。だからといって、/usr/local/php/lib/php.ini に同じものを置いても、やっぱり状況変わらずなのだ。どうにも php.ini の内容が反映していない様子。(ちなみに、ブラウザのキャッシュが・・・というような素人じみた落ちは無い(^^;)

何度か --with-config-file-path オプションをつけて再インストールしてみたのだが、何か php 動かなくなっちゃったし(^^;
make clean してやり直していたのだが、make clean した後でソース展開したディレクトリも消して、ソースを展開するところからやり直せばよかったのかな・・・
どうも、make clean だけではさっぱりきれいにならないようである。

結局、解決策は、

5.2系をインストールする

・・・である(^^;

元々ユーザー要件としては「PHP 5.2 のインストール」となっていたので、その最新の 5.2.17 をインストールした。
5.2系は良いなあ。
Default timezone と php.ini で設定している timezone が同じでなくとも、ワーニングなんか吐かない。
そして、php.ini に date.timezone の記述を追加して httpd を再起動すれば、phpinfo の date.timezone directive に関する情報も、すぐに Asia/Tokyo に変更された。

う~ん・・・何か、もっと configure の時に色々とオプションが必要だったんかなあ?

ま、今回は 5.2.17 でまったく問題無いんだけど、今後のことを考えると、5.3系で上手くいかなった理等を調べておきたかったな。

ま、もう、今日は駄目です(^^;

今から岩国まで帰れるかなあ・・・

いや、まあ、もう「汎用データベースモジュール」は使わないことにしたので、どうでも良いっちゃ良いんだけど、この間"GDモジュールが「画像の読み書きをサポートしてない」と言われるのだが"というエントリーに書いたように、PHP でちゃんと gd モジュールのセットアップをしても、

gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートしていません。このモジュールで画像を処理するには、gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートする必要があります。

と「汎用データベースモジュール」の管理画面で怒られちゃう件。

今日、たまたまソースを見てみると、このエラーを出しているところは、admin/index.php の

    if (!$gd_infos['GIF Read Support'] || !$gd_infos['GIF Create Support'] || !$gd_infos['JPG Support'] || !$gd_infos['PNG Support']) {
        $errors[] = constant('_AM_' . $affix . '_GD_NOT_SUPPORTED_ERR');
    }

この部分だった。

「JPG Support」なんて添字の gd 情報をチェックしているよ。
それは、古いバージョンの PHP が戻してくる値でしょうが。今のバージョンだと、「JPEG Support」って項目名なんすけど。

こんなしょうもないことのために、どれだけ PHP の再インストールをしたことか(^^;。俺の貴重な時間を返せ。(ま、その時、自分の PHP のインストール手順ではなく、すぐにソースを疑えばよかったんだけどね(^^;)

つーことで、「坊主憎けりゃ袈裟まで憎い」ではないが、ますます XOOPS が嫌いになった俺なのであった。

いやぁ、ちょっとハマって無駄な時間を過ごした。(^^;

例えば、db_user と db_shop というディレクトリ名で、XOOPS 汎用データベースモジュールを元にした外部モジュールをアップしてインストールをしようとすると、どちらの外部モジュールも一覧に同じ名前で表示されてしまうのだ。

modinfo.php の中で、db_user は「ユーザ検索」、db_shop は「お店検索」と名前を付けているのに、どちらも「ユーザ検索」と表示されてしまう・・・という具合だ。

結局、問題なのは db_user と db_shop というディレクトリ名であった。

XOOPS 汎用データベースモジュールは、ディレクトリ名を変えれば複数設置出来るようになっているのだが、そのため、モジュール名に添字(affix)を付けてモジュールを区別出来るようにしているみたい。

その添字の作り方が

$affix = strtoupper(strlen($dirname) >= 3 ? substr($dirname, 0, 3) : $dirname);

という具合にディレクトリ名の頭 3文字だけを取っているのが問題のようである。

ということで、db1_user、db2_shop のように先頭 3文字を抜いても問題の無いディレクトリ名にしてやれば問題ないのであった。

なんか、もう、いちいちこういう細かい仕様で引っかかって、全然本来の開発のところにたどり付けんな。

複数のプログラマ仲間が「今更 XOOPS?PHP のバージョンアップにもまともに対応出来てないのに?XOOPS に手を出すなんて 3~4年遅いよ。」と言うてたのは本当だな。今更 XOOPS なのである(^^;

う~む・・・お手上げだ。(^^;

うちのテスト用サーバで、XOOPS Cube Legacy の外部モジュール

汎用データベースモジュール
http://xoopscube.jp/module/413

の検証をしようと思ったんだけど、インストールを終えて管理画面を開くと、

gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートしていません。このモジュールで画像を処理するには、gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートする必要があります。

なんてエラー(?)が出ちゃう。う~ん?

確かに、phpinfo() で見てみると、

20101210_gd_before.jpg

という具合に gd の情報に JPEG Support enabled が出ていない。

どうも、PHP のバグなのか、configure する時に、--with-gd オプションを最後に指定しないと駄目らしい。

./configure --with-apxs2=/usr/local/apache2/bin/apxs --enable-mbstring --enable-zend-multibyte --with-pgsql --with-mysql --with-gd -with-jpeg-dir=/usr/local/lib --with-zlib --with-png-dir=/usr/local --with-zlib-dir

という具合に configure していたんだが、

./configure --with-apxs2=/usr/local/apache2/bin/apxs --enable-mbstring --enable-zend-multibyte --with-pgsql --with-mysql -with-jpeg-dir=/usr/local/lib --with-zlib --with-png-dir=/usr/local --with-zlib-dir --with-gd

みたいにしないと駄目なようである。

確かに、これで configure し直して make すると、ちゃんと JPEG Support enabled が表示されるようになった。

20101210_gd_after.jpg

今回使っている PHP のバージョンは 5.3.3。少なくとも、5.2.11 の時には、

./configure --with-apxs2=/usr/local/apache2/bin/apxs --enable-mbstring --with-mysql --with-gd --with-zlib --with-jpeg-dir --with-pdo-mysql

のように --with-gd が前の方にあっても問題なく JPEG が使えた。

PHP のバージョンアップをずっと追いかけているわけではないのでわかんないのだが、どっかの段階で --with-gd より前に -with-jpeg-dir を置かないといけなくなったということだよな?

ま、何か気持ち悪いが、JPEG もこれで使えるようになった。

さぁ、GIF も JPEG も PNG も全部サポートよぉ~!と汎用データベースモジュールの管理画面を開くと、

gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートしていません。このモジュールで画像を処理するには、gdモジュールがGIF/JPEG/PNG画像の読み書きをサポートする必要があります。

なんだ、これ。わけわからん。お手上げだ。

なんか、こんなことを繰り返してて、全然 XOOPS の検証が終わらん。
XOOPS なんか使わずに、素直に CGI とかで組んでサイト作った方が今回の案件は確実に早いよなあ。
ま、ユーザのご指名なので、XOOPS Cube Legacy を使うしかないのだが・・・

「お手軽」と言われるシステムは、いざ「動かん」という時の調査/対応がほんと大変なのだ・・・

このアーカイブについて

このページには、過去に書かれたブログ記事のうちPHPカテゴリに属しているものが含まれています。

前のカテゴリはPerlです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら