[PHP-dev 1425] Re: mbstring のいくつかの関数の挙動について
Yasuo Ohgaki
yohgaki @ ohgaki.net
2008年 8月 6日 (水) 14:24:11 JST
Rui Hirokawa さんは書きました:
> 廣川です。
>
> 反応が遅くてすみません。
>
> ご指摘の点のうち、1,4についてはバグだと思いますので、
> CVSにコミットしました (PHP_5_2,PHP_5_3)。
>
> 2,3 (特に3)については直すかどうか微妙なところかと思います。
> 他の方のご意見はいかがでしょう?
確かに微妙ですね....
2は、基本的に同じ動作をするように調整した方が良い、と思いますが
\nで改行はRFC準拠的にどうか、と異論のある所だと思いますが\nで改行で
良いと思います。
mail()でも同じ動作の方が好ましい、と思います。
3はPHP_5_2で変更するのは良く無いと思います。正規表現のデフォルトは最長
一致であるべき、というご意見には賛成です。しかし、この変更は互換性、
さらにはセキュリティ上の問題も発生しかねないので、PHP_5_2への適用は
反対です。
HEADおよびPHP_5_3ブランチに適用、で良いのではないでしょうか。
--
Yasuo Ohgaki
>
> On Sun, 10 Feb 2008 17:30:52 +0900
> komura <komura @ ma9.seikyou.ne.jp> wrote:
>
>> komura です。
>>
>> 最近、mbstring の挙動について調べていたのですが、一部の関数でバグかも
>> しれないと考えられるようなものがいくつか見つかりました。
>>
>> どれも致命的なものではないため、修正する必要があるかは分からないのですが、
>> 参考までに、PHP 5.2.5 に対する Patch を添付します。
>>
>> 1.に関してだけは修正した方が良いのではないかというのが個人的な意見です。
>>
>>
>> 1. "auto" の内部で扱われるエンコーディングリストがリクエストごとに初期化
>> されない
>>
>> Apache モジュール版の PHP の問題です。
>> 再現コードは次の通りです。 php.ini の mbstring の設定を
>> mbstring.language = Japanese にして試してください。
>>
>> <?php
>> mb_detect_order( 'auto' );
>> echo implode( ', ', mb_get_info( 'detect_order' ) ); // (*1)
>> mb_language( 'Russian' );
>> mb_detect_order( 'auto' );
>> echo implode( ', ', mb_get_info( 'detect_order' ) ); // (*2)
>> ?>
>>
>> 初回のアクセス時(Apache 起動後)には、以下のようになります。
>> (*1) : ASCII, JIS, UTF-8, EUC-JP, SJIS
>> (*2) : ASCII, UTF-8, KOI8-R, Windows-1251, CP866
>>
>> 何度かアクセスすると、結果が以下のように変わります。
>> (*1) : ASCII, UTF-8, KOI8-R, Windows-1251, CP866
>> (*2) : ASCII, UTF-8, KOI8-R, Windows-1251, CP866
>>
>> スクリプト側で毎回 mb_language() 関数を実行していれば問題は出ませんが、
>> php.ini の設定に頼っていると、意図しない動作になる可能性があります。
>>
>> Patch では、リクエストごとに初期化を行う処理を追加しました。
>> (php_5_2_5_mbstring_auto.patch)
>>
>>
>> 2. mb_send_mail() 関数の第1引数(to)の改行に "\n" を指定すると、改行が
>> スペースに置き換えられる
>>
>> To: に "\n" による改行を指定すると、スペースに置き換えられ、改行がなく
>> なります。"\r\n" を指定すれば、正しく改行されます。第4引数の追加ヘッダは
>> 改行がスペースに置き換えられるようなことはありません。
>>
>> Subject: は "\n" による改行を行っていますので、To: もそれに合わせて "\n"
>> のみにしたいところですが、現在ではそれができなくなっています。
>>
>> 再現コードは以下のとおりです。
>>
>> <?php
>> mb_language( 'Japanese' );
>> mb_internal_encoding( 'UTF-8' );
>> $to_name = 'あああああああああああああああああ';
>> $to_addr = 'to @ example.com';
>> $from_name = 'いいいいいいいいいいいいいいいいい';
>> $from_addr = 'from @ exaple.com';
>> $subject = 'ううううううううううううううううう';
>> $body = 'test';
>> $to = mb_encode_mimeheader( $to_name, 'ISO-2022-JP', 'B',
>> "\n", strlen( 'To: ' ) ) . "\n <" . $to_addr . '>';
>> $from = mb_encode_mimeheader( $from_name, 'ISO-2022-JP', 'B',
>> "\n", strlen( 'From: ' ) ) . "\n <" . $from_addr . '>';
>> $extra = 'From: ' . $from;
>> mb_send_mail( $to, $subject, $body, $extra );
>> ?>
>>
>> 上のスクリプトを mailtest.php というファイルに保存し、以下のように実行
>> することで確認できます。
>>
>> $ php -d sendmail_path="cat -" mailtest.php
>>
>> 結果は以下のようになります。
>>
>> To: =?ISO-2022-JP?B?GyRCJCIkIiQiJCIkIiQiJCIkIiQiJCIkIiQiJCIkIiQiJCIbKEI=?= =?ISO-2022-JP?B?GyRCJCIbKEI=?= <to @ example.com>
>> Subject: =?ISO-2022-JP?B?GyRCJCYkJiQmJCYkJiQmJCYbKEI=?=
>> =?ISO-2022-JP?B?GyRCJCYkJiQmJCYkJiQmJCYkJiQmJCYbKEI=?=
>> From: =?ISO-2022-JP?B?GyRCJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkGyhC?=
>> =?ISO-2022-JP?B?GyRCJCQkJBsoQg==?=
>> <from @ exaple.com>
>> Mime-Version: 1.0
>> Content-Type: text/plain; charset=ISO-2022-JP
>> Content-Transfer-Encoding: 7bit
>>
>> test
>>
>> この問題は、To: に任意のメールヘッダを埋め込めるという問題に対処した
>> バージョンから起きることを確認しています。
>> mail() 関数も同様の挙動であるため、修正する必要があるのかについては
>> よく分かりません。
>>
>> PHP マニュアルの mail() 関数の説明で、以下のように説明されています
>> ので、PHP での仕様として例のスクリプトのように To: のメールアドレスの
>> 前に名前を入れるのは止めておいた方が良いのかもしれません。
>>
>> "to 引数には "Something <someone @ example.com>" 形式の メールアドレス
>> を与えることはできません。 MTA と通信する際に mail コマンドはこれを
>> 適切にパースできません。"
>>
>> おそらく不要だと思うのですが、Patch では、"\n" の場合でも、改行する
>> ように処理を追加しました。
>> (php_5_2_5_mbstring_mb_send_mail.patch)
>>
>>
>> 3. マルチバイト正規表現関数と正規表現関数の非互換
>>
>> ereg* 関数では、最長一致(longest matching)を行うように実装されています
>> が、mb_ereg* 関数のデフォルト状態では最長一致にはなっていません
>> (オプションで最長一致を行うようにはできます)。
>>
>> 問題としては、関数オーバーロードの機能を使用している場合、結果が異なる
>> 可能性が出てきます。再現コードは以下の通りです。
>>
>> <?php
>> $str = 'abb';
>> $regex = 'a(b|bb)';
>> ereg( $regex, $str, $m );
>> echo 'ereg : ' . $m[0] . "\n";
>> mb_ereg( $regex, $str, $m );
>> echo 'mb_ereg : ' . $m[0] . "\n";
>> ?>
>>
>> 結果は以下のとおりです。
>>
>> ereg : abb
>> mb_ereg : ab
>>
>> ereg* 関数のオーバーロードを行った場合、結果は以下のとおりになります。
>>
>> ereg : ab
>> mb_ereg : ab
>>
>> 個人的には、これが問題になることは、ほとんどないと思いますし、性能の
>> 問題(最長一致にすると性能が落ちます)もありますので、現在のままでも問題
>> ないと思います。
>>
>> ereg* 関数をオーバーロードする設定になっていて、ereg* 関数を使用した
>> 場合のみ、最長一致を行うようにできれば問題ないのかもしれません。
>>
>> この件に関しては Patch は作成していません。
>>
>>
>> 4. mb_language() 関数にアルメニア語を指定するには "Armenian " とする必要
>> がある
>>
>> 意図して後ろにをスペース入れているとは思えませんので、おそらく Typo
>> だと思います。
>> Patch では定義部分のスペースを削除しました。
>> (php_5_2_5_mbstring_armenian.patch)
>>
>> --
>> komura <komura @ ma9.seikyou.ne.jp>
>
PHP-dev メーリングリストの案内