[PHP-dev 1392] mbstring関連での微妙な挙動について

Seiji Masugata s.masugata @ digicom.dnp.co.jp
2008年 3月 10日 (月) 16:03:50 JST


こんにちわ、桝形です。

mbstring関連で、いくつか微妙な挙動に遭遇したので報告しておきます。
どちらもファイルアップロード絡みです。

--------------------------------------------------------------------
(1)

例えば c:\test\hoge\huga.txt というファイルをアップロードした場合
PHP的に色々と処理を行った結果、最終的には huga.txt と、
ファイル名だけになり、$_FILES 配列の ['name'] 項目に格納されます。

http://jp.php.net/fileupload

この時、アップロードしたファイル名(フルパス)に特定のマルチバイトが
含まれている、かつmbstringの設定状況によっては、hoge\huga.txt と
ファイル名だけではなくて、一部のディレクトリ名も付与された形で
$_FILES 配列の ['name'] 項目に格納されてしまいます(主にIEで発生)。


mbstring.language = Japanese
mbstring.internal_encoding = EUC-JP
mbstring.encoding_translation = On
mbstring.http_input = pass
mbstring.script_encoding = SJIS


ちょっと調べてみたところ、--enable-zend-multibyte を有効にして
この機能を使っている場合、かつ mbstring.http_input が pass 設定
(入力の自動変換を無効)になっていると、このような挙動になるようです。



中途半端な例で恐縮ですが、SJIS のマルチバイト文字列をEUC-JP と
仮定して処理してしまっているようで、この為、正しく処理ができて
いないようです。


/php-src/main/rfc1867.c の中身を確認したところ、文字コード変換を
行う・行わないの判定は php_mb_encoding_translation関数で行って
いるようですが、この関数の中身が、

/* {{{ MBSTRING_API int php_mb_encoding_translation() */
MBSTRING_API int php_mb_encoding_translation(TSRMLS_D) 
{
	return MBSTRG(encoding_translation);
}
/* }}} */


mbstring.encoding_translationディレクティブしか見ていないようです。
以下のパッチは安直かもしれませんが、期待する結果になりました。


--- php5.2-200803050130,orig/ext/mbstring/mbstring.c	2008-02-17 12:33:27.000000000 +0900
+++ php5.2-200803050130/ext/mbstring/mbstring.c	2008-03-05 15:52:54.000000000 +0900
@@ -4104,7 +4104,11 @@
 /* {{{ MBSTRING_API int php_mb_encoding_translation() */
 MBSTRING_API int php_mb_encoding_translation(TSRMLS_D) 
 {
-	return MBSTRG(encoding_translation);
+	if( MBSTRG(encoding_translation) && MBSTRG(http_input_list_size) > 0 && MBSTRG(http_input_list)[0] != mbfl_no_encoding_pass ) {
+		return 1;
+	} else {
+		return 0;
+	}
 }
 /* }}} */



--------------------------------------------------------------------
(2)

http://jp.php.net/mbstring
--------------------------------------------------------------
注意: PHP 4.3.3 以降、HTML フォームの enctype が 
multipart/form-data に設定され、かつ、 php.ini において 
mbstring.encoding_translation に On が指定されている場合、 
POST データの変数とアップロードされたファイルの名前の
文字エンコーディングは、 内部文字エンコーディングに変換
されます。
--------------------------------------------------------------

PHPマニュアルには、このように記載されていますが、5.2.5では
ファイルアップロード時に内部コードに変換されないケースが
あるようです。


mbstring.language = Japanese
mbstring.internal_encoding = EUC-JP
mbstring.encoding_translation = On
mbstring.http_input = SJIS


/php-src/main/rfc1867.c の中身を確認したところ、filter 拡張
モジュールをコンパイル・オプションで有効にしていた場合、
内部コードへ変換を行う関数を経由していないようです。

filter 拡張モジュールをコンパイル・オプションで無効にしていた
場合は期待した結果になります。


この位置で正しいのか若干疑問は残りますが、以下のパッチを
適用したところ、期待する結果になりました。


--- php5.2-200803050130,orig/main/rfc1867.c	2007-12-31 16:33:36.000000000 +0900
+++ php5.2-200803050130/main/rfc1867.c	2008-03-05 15:53:01.000000000 +0900
@@ -961,6 +961,13 @@
 					php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
 				}
 
+#if HAVE_MBSTRING && !defined(COMPILE_DL_MBSTRING)
+					if (php_mb_encoding_translation(TSRMLS_C)) {
+						php_mb_gpc_stack_variable(param, value, &val_list, &len_list, 
+												  &num_vars, &num_vars_max TSRMLS_CC);
+					}
+#endif
+
 				if (!strcasecmp(param, "MAX_FILE_SIZE")) {
 					max_file_size = atol(value);
 				}


--------------------------------------------------------------------


(1)については、差し支えないようであれば、こちらで作業しようと
思いますが、(2)については 残念ながら karmaを持っていません。。。

この為、現在のメンテナにお願いをしないといけません。
ただ、実装が問題ないようであれば、こちらでお願いをしようと思います。



確認して頂けると幸いです。
長文失礼しました。

-- 
Seiji Masugata <s.masugata @ digicom.dnp.co.jp>



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