- ベストアンサー
$_POSTのインデックスについて教えて下さい。
よろしくお願いします。 shift-jis で以下を書いて実行すると、$_POST のインデックスのみ\x5b が \x5f に変換されてしまいます。 <?php if ( !mb_internal_encoding('sjis') ) { die(); } ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift-jis"> <title>test</title> <style type="text/css"> table { border:1px solid #AAA; } th {padding:10px; border:1px solid #AAA; background-color:#EEE; } td {padding:10px; border:1px solid #AAA; } </style> </head> <body> <table summary=""> <tr> <th>KEY</th> <th>VALUE</th> </tr> <?php foreach ( $_POST as $key => $val ) { echo '<tr>', '<td>', $key, ' => ', bin2hex($key), '</td>', '<td>', $val, ' => ', bin2hex($val), '</td>', '</tr>'; } ?> </table> <form action="" method="post"> <input type="text" name="a" value="a" > <input type="text" name="あ" value="あ" > <input type="text" name="ー" value="ー" > <input type="text" name="ゼ" value="ゼ" > <input type="submit" value="send"> </form> </body> </html> なぜそうなるのか分からないのですが、説明のある所をご存知ないでしょうか? ちなみに、 windows + XAMPP + PHP5.3(ローカル) linux 系 + apache2.x + PHP5.?? (レンタルサーバー) 両方そうなりました。 検索の仕方が悪いのかうまく情報を探し出す事ができませんでした。 そのほかにも変換されてしまう文字等あったら、あわせて教えて下さい。 よろしくお願いいたします。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
>「HTML では name 属性に全角文字を使ってはいけない」 http://www.w3.org/TR/html4/types.html#type-id
その他の回答 (3)
- yuu_x
- ベストアンサー率52% (106/202)
> 前にも書きましたが、HTTP の通信をサーバーが受け取り、それを PHP が解釈して $_POST に値を設定するまでの流れを ... 斜め読みですが、件の核となる部分は main/php_variables.c の 98 行目辺り(PHP 5.3.1) 以下抜粋 ================================================================== PHPAPI void php_register_variable_ex(char *var_name, zval *val, zval *track_vars_array TSRMLS_DC) { ~ for (p = var; *p; p++) { if (*p == ' ' || *p == '.') { *p='_'; } else if (*p == '[') { // 前方検索して、'['を見つけた時点で配列と判定。 is_array = 1; ip = p; *p = 0; break; } } var_len = p - var; ~ ip++; index_s = ip; if (isspace(*ip)) { ip++; } if (*ip==']') { index_s = NULL; } else { ip = strchr(ip, ']'); // ']'の位置を検索 if (!ip) { // 件では、当然 ']' はないので、以下を実行。 /* PHP variables cannot contain '[' in their names, so we replace the character with a '_' */ // ここにどうなるか書いてありますね。 *(index_s - 1) = '_'; index_len = 0; if (index) { index_len = strlen(index); } goto plain_var; return; } *ip = 0; new_idx_len = strlen(index_s); } ================================================================== > 少しほかの文字でも試してみましたが、name 属性(インデックス名)の末尾についている制御文字の様な文字は削除されて、 [ のみ(対になっていない)場合は _ に変換されてしまう様です。 予想は正しいようです。ただ、将来的に変更されないとも限らないので、前提での対処はやめたほうがいいでしょう。 ================================================================== > スクリプトの冒頭で $_POST のインデックス名と値を UTF-8 に変換する必要がありますが、 #2 さんもおっしゃってるとおり、受け取った後では遅いでしょう。 > 事情がありまして、できれば、全角文字でのやり取りでやりたいと考えています。 不可能ってわけでもないですよ。 1. form accept-charset="UTF-8" 実際にUTF-8で送ってくれるかどうかは 環境依存。携帯では変換されないと思っておいたほうがいいでしょう。 2. mbstring.encoding_translation http://www.php.net/manual/ja/mbstring.configuration.php#ini.mbstring.encoding-translation 3. > post 送信のなまのデータの取り出し方は、私もちょっと解りません。 http://www.php.net/manual/ja/reserved.variables.httprawpostdata.php http://www.php.net/manual/ja/ini.core.php#ini.always-populate-raw-post-data parse_str してしまうと元の木阿弥なので、自前で解析して下さい。 ...
お礼
どこに書けば良いか迷ったのですが、ここに書きます。 別な用件で時間が取れずにおりました、遅くなりまして申し訳ありません。 必要に応じて以下の様な処理を行うことで現在の所は何とか動いております。 (実際に動かしているコードとは若干違いますが筋は一緒です) file_get_contents("php://input") がマルチパートの場合には使えないということで やはり正規表現で置換する方法も併用するしかない感じです。 実際の運用に使うかは、今後もう少し調べた後、様子を見て考えます。 if ( $input = file_get_contents("php://input") ) { //初期化 $_POST = array(); foreach ( explode('&', $input) as $str ) { list($key, $val) = explode('=', $str); $key = mb_convert_encoding(urldecode($key), 'UTF-8', 'sjis-win'); $val = mb_convert_encoding(urldecode($val), 'UTF-8', 'sjis-win'); if ( substr($key, -2,2) == '[]' ) { $_POST[rtrim($key, '[]')][] = $val; } else { $_POST[$key] = $val; } } } else { foreach ( $_POST as $key => $val ) { $key = mb_convert_encoding(preg_replace('/([\x81-\x9f\xe0-\xee])_/', '$1[', $key), 'UTF-8', 'sjis-win'); //追加 $_POST[$key] = mb_convert_encoding($val, 'UTF-8', 'sjis-win'); } } 知らない事が多く、今回教えて頂いた事が色々と勉強になりました。 ご回答下さった方々にはお世話になりました。 ありがとうございます。 しばらくしましたら、この質問を閉めます。
- hrm_mmm
- ベストアンサー率63% (292/459)
どうやらname属性に多バイト文字が入ってる可能性は全く考慮されてないようです。 mb_convert_variables もハッシュ配列のキーについては、変換してくれませんし。 manualに記載がないのも、考えもしないからとしか思えないような。 とりあえず、マルチバイトの危険性に絡んで、以下のページもご参照ください。 http://gihyo.jp/admin/serial/01/charcode get送信なら、$_SERVER['QUERY_STRING'] を自前で分解して、逐一文字コード変換すれば、なんとかなるけど、$_POST は、おっしゃるとおり既に不良変換後(sjis で '['=0x5b を含むと多次元配列として展開されてしまう)なので、戻せません。 post 送信のなまのデータの取り出し方は、私もちょっと解りません。 ページの文字コードが、utf-8 とかeuc-jpなら、まだ救いはあるんですが(誤展開されてなければ後からでも、キーの文字列を変換できる)、Shift_JISはだめですね。携帯用ですか。 「ページをShift_JISで出力しないとならないから、name属性の多バイト文字禁止」というのが最大理由となりそう。
お礼
ご回答ありがとうございます。 >ページをShift_JISで出力しないとならないから、name属性の多バイト文字禁止 やはりそうするしかないでしょうか。 >get送信なら、$_SERVER['QUERY_STRING'] を自前で分解して、… 確かに GET なら何とかなりそうな気がしてきました。 後は送信できるデータの量の問題だけでしょうか。 少し試してみます、ありがとうございます。 また、ページのご紹介もありがとうございます。参考にさせて頂きます。 とりあえずお礼だけ。
- yuu_x
- ベストアンサー率52% (106/202)
FORM 番ダメ文字って感じですね。 「ー」だけでなく「ゼ」含めその他もろもろでも同じ現象になると思います。 コピペして実行してみてください、理由がわかると思います。 <input type="text" name="ー‐" value="ー"> <input type="text" name="ゼゾ" value="ゼ"> <?php echo '<pre>'; var_dump($_POST); echo '</pre>'; ?> # JIS でやるともっと面白いことになりそうですね。 value は仕方ないにしても、識別子に全角はやめたほうがいいですね。 文字コードに対してもう少し危機感のようなものを持ったほうがいいと思います。
お礼
ご回答ありがとうございます。 >value は仕方ないにしても、識別子に全角はやめたほうがいいですね。 はい、おっしゃる事はわかります。 がしかし、フォームを含め、HTMLを書くのは別の人間でして、 私はUTF-8で書かれたをれを読み込んで shift-jis に変換後出力しなければなりません。 「HTML では name 属性に全角文字を使ってはいけない」もしくは、 「name 属性に全角文字を使っていると、PHPで受け取る事ができない」 といった事がどこかに明記してあれば、 そうお願いする所なんですが、それを見つけられません。 自分でPHPのソースを読む技量もないので、 全角文字を使うとよくないと明記してあるサイト等ありましたら、 教えて頂けると助かります。
補足
少しほかの文字でも試してみましたが、name 属性(インデックス名)の末尾についている制御文字の様な文字は削除されて、 [ のみ(対になっていない)場合は _ に変換されてしまう様です。 []の場合は削除されて $_POST['インデックス名'] を配列として利用できるのはご承知の通りです。 はっきりした事はまだ分かっていませんが、現在の所、そういう感じです。 そのあたりの PHP の振る舞いについて日本語で詳しく書かれているサイトをご存知でしたら、紹介して頂けるとありがたいです。 表示されているページは、携帯電話用に shift-jis に変換して出力していますが、 スクリプトは全て UTF-8 で書いておりますので、携帯電話からの POST の場合 スクリプトの冒頭で $_POST のインデックス名と値を UTF-8 に変換する必要がありますが、 その変換前に /([\x81-\x9f\xe0-\xee])_/ を "$1]" に無理やり置換してしまえば今のところ何とか動いています。 しかし、PHPの振る舞いが分かっていない状況では運用には向かないと思っています。 事情がありまして、できれば、全角文字でのやり取りでやりたいと考えています。 また、携帯電話向けのページは shift-jis で表示する事になっており変更できません。 前にも書きましたが、HTTP の通信をサーバーが受け取り、それを PHP が解釈して $_POST に値を設定するまでの流れを 見てみようとPHPのソースをダウンロードするまではしてみましたが、やはり読むことはできませんでした。 PHP の振る舞いが分かっていれば何とか対処できるような気がして、それを知りたいといった状況です。 最終的には全角文字を利用しないで要件を満たす別な方法を探す事になりそうな予感はしておりますが、 どうぞよろしくお願いいたします。
お礼
度々ありがとうございます。 >斜め読みですが、件の核となる部分は main/php_variables.c の 98 行目辺り(PHP 5.3.1) ソースまで見て頂きまして、お手数おかけして申し訳ありません。 場所が分かっていれば何とか読めるかもしれませんので今から見てみます。本当に助かります。 またご紹介頂いたページに書かれていた $HTTP_RAW_POST_DATA と <?php $postdata = file_get_contents("php://input"); ?> これらについては全く知りませんでした。 今から試してみます。 とりあえずのお礼だけで失礼いたします。
補足
もう誰も見ることはないと思いますが… かなり恥ずかしい感じですが、正規表現では元に戻す事が不可能な事に今頃気がつきました。 気が付いた後もしばらく悪あがきしてみましたが無理でした。 何も考えずに name 属性に全角文字を利用する事は無理っぽいですね、 いくらかの制限つきなら可能かも知れませんが、そういった事をやってると後がグダグダになってきたりしますし。 おかげさまで勉強になりました、ありがとうございました。