Do You PHP はてブロ

Do You PHPはてなからはてブロに移動しました

PHP5.2.6で「multipart/form-data使ってアップロード」の続き

しつこいようですが、今度はPHP5.2.6で先日の件の続きです。

まずは、先ほどのPHP4.4.8のように

$ ./configure ... --enable-zend-multibyte --enable-mbstring ...

とmbstring拡張を組み込みでbuildして確認してみました。すると、

  • $_FILESの内容は変換される
  • $_POSTの内容は変換されない

という結果でした。

で、先日のエントリに対するid:t_komuraさんのコメント


以前、枡形さんが PHP-dev メーリングリストで投稿しておられたものと現象が同じような気がします。
以下のメールの(2)です。
http://ml.php.gr.jp/pipermail/php-dev/2008-March/001393.html

私の環境(Apache 1.3.41+PHP 5.2.5)でもこの問題は再現しましたが、Patch を当てて再度コンパイルし直したところ、正しく処理されるようになりました。

を見て、メーリングリストの過去ログを確認しました。。。って、見た事ありました。やっぱり orz

早速パッチを当てて再build(mbstring拡張は組み込みで)したところ、$_POSTも変換されるようになりました。おー!id:masugata++!!

パッチの内容とmain/rfc1867.cを見比べると、確かに特定の場合のみphp_mb_gpc_stack_variable()php_mb_encoding_translation(TSRMLS_C)が呼び出されてません。これがエンコーディング変換してる部分なんですかね。。。以下、PHP5.2.6のmain/rfc1867.cの抜粋です。

            /* Normal form variable, safe to read all data into memory */
            if (!filename && param) {
                unsigned int value_len;
                char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);
                unsigned int new_val_len; /* Dummy variable */

                if (!value) {
                    value = estrdup("");
                }

                if (sapi_module.input_filter(PARSE_POST, param, &value, value_len, &new_val_len TSRMLS_CC)) {
                    if (php_rfc1867_callback != NULL) {
                        multipart_event_formdata event_formdata;
                        size_t newlength = 0;

                        event_formdata.post_bytes_processed = SG(read_post_bytes);
                        event_formdata.name = param;
                        event_formdata.value = &value;
                        event_formdata.length = new_val_len;
                        event_formdata.newlength = &newlength;
                        if (php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC) == FAILURE) {
                            efree(param);
                            efree(value);
                            continue;
                        }
                        new_val_len = newlength;
                    }

#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);
                    } else {
                        safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
                    }
#else
                    safe_php_register_variable(param, value, new_val_len, array_ptr, 0 TSRMLS_CC);
#endif
                } else if (php_rfc1867_callback != NULL) {
                    multipart_event_formdata event_formdata;

                    event_formdata.post_bytes_processed = SG(read_post_bytes);
                    event_formdata.name = param;
                    event_formdata.value = &value;
                    event_formdata.length = value_len;
                    event_formdata.newlength = NULL;
                    php_rfc1867_callback(MULTIPART_EVENT_FORMDATA, &event_formdata, &event_extra_data TSRMLS_CC);
                }

                if (!strcasecmp(param, "MAX_FILE_SIZE")) {
                    max_file_size = atol(value);
                }

                efree(param);
                efree(value);
                continue;
            }

うー。。。「!defined(COMPILE_DL_MBSTRING)」なので、mbstring拡張は組み込みにしなきゃダメですね。。。実際にsharedにするとダメでした。

ちなみに、PHP4.4.8の場合、当該箇所は

            /* Normal form variable, safe to read all data into memory */
            if (!filename && param) {
                unsigned int value_len; 
                char *value = multipart_buffer_read_body(mbuff, &value_len TSRMLS_CC);

                if (!value) {
                    value = estrdup("");
                }

#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);
                } else {
                    safe_php_register_variable(param, value, value_len, array_ptr, 0 TSRMLS_CC);
                }
#else
                safe_php_register_variable(param, value, value_len, array_ptr, 0 TSRMLS_CC);
#endif
                if (!strcasecmp(param, "MAX_FILE_SIZE")) {
                    max_file_size = atol(value);
                }

                efree(param);
                efree(value);
                continue;
            }

となっていて、mbstring拡張を組み込みでbuildされていればphp_mb_gpc_stack_variable()php_mb_encoding_translation(TSRMLS_C)が呼び出されるようになっているようなので、先ほどのエントリの件も納得いきます。


ということで、mbstring.encoding_translation=onにしたい場合(すべてのエンコーディングを統一できないなど)は、

  • PHP4.4.8ではmbstring拡張を組み込みでbuildする
  • PHP5.2.xではパッチを当ててmbstring拡張を組み込みでbuildする

とする必要がありそうです。


そういえば、rpmで提供されているPHPって、こういうことってないんですかね?まあ、すべてのエンコーディングを統一する、そうでない場合はmultipart/form-dataでPOSTした際にエンコーディング変換してやればOKなんですけど。。。


あー。すっきりしたw