[PHP-dev 1390] mbstring のいくつかの関数の挙動について

komura komura @ ma9.seikyou.ne.jp
2008年 2月 10日 (日) 17:30:52 JST


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>
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: php_5_2_5_mbstring_auto.patch
型:         text/x-patch
サイズ:     573 バイト
説明:       無し
URL:        http://ml.php.gr.jp/pipermail/php-dev/attachments/20080210/db7d379d/attachment.bin 
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: php_5_2_5_mbstring_mb_send_mail.patch
型:         text/x-patch
サイズ:     634 バイト
説明:       無し
URL:        http://ml.php.gr.jp/pipermail/php-dev/attachments/20080210/db7d379d/attachment-0001.bin 
-------------- next part --------------
テキスト形式以外の添付ファイルを保管しました...
ファイル名: php_5_2_5_mbstring_armenian.patch
型:         text/x-patch
サイズ:     448 バイト
説明:       無し
URL:        http://ml.php.gr.jp/pipermail/php-dev/attachments/20080210/db7d379d/attachment-0002.bin 


PHP-dev メーリングリストの案内