[PHP-users 6362] Re: mb_convert_encoding() での JIS->EUC-JP変換

HAYAKAWA Hiroshi php-users@php.gr.jp
Wed, 20 Mar 2002 21:28:39 +0900


早川@名古屋です。

今日は一日外出しておりました。

on 02.3.19 7:19 PM, LastTom at lasttom@ra2.so-net.ne.jp wrote:

> 松川@出張中です。
> 
> JISなテキストファイルを用意してWindows上でやってみたのですが、\マーク
> 以降切れるとか、?に化けるとかはないですねぇ。Linux上では試していないので
> すが...
> 
> で、当てずっぽうですが、
> 
>> ;mbstring.http_input = auto
> 
>> 
> mbstring.http_input = pass
> 
> とするとどうなりますう?

変化ありませんでした。
HTTP入力ではないので、このオプションは影響しないのではないでしょうか。
密かに影響したりしていると怖いですが、
「HTTP入力において」という説明がありますので。


で、友人の協力を得て問題の原因を探ったところ、
「PHP4のマルチバイト関数の仕様」じゃないかという感じなのですが、
どうなのでしょうか?>詳しい方

・ASCIIのbackslash(0x5c)とtilde(0x7e)の位置には
 各国の文字集合毎に任意の文字を割り当てていいことになっている。
・日本語版のASCIIであるJIS X 0201-1976には、
 この二つの位置に半角円マークと半角オーバーラインが割り当てられている。
・ISO-2022-JPはASCIIとJIS X 0201-1976の二つの文字集合を両方ともサポートし、
 ASCIIのbackslashとtilde、JIS X 0201-1976の半角円マークと
 半角オーバーラインをそれぞれ切り替えて使うことができる。
・EUC-JPは文字集合的にはASCII + JIS X 0208-1983という組合せで、
 JIS X 0201-1976の半角円マークと半角オーバーラインは表現できない。

で、テストメールのサブジェクト「これは\マークと~のテスト」が
ASCIIのbackslashとtildeではなく、
JIS X 0201-1976の半角円マークと半角オーバーラインとして
エンコードされていることを確認した上で、
MIMEデコードにmb_decode_mimeheader()ではなく、
nkf1.7を使用してみたところ、
?マークになることなくデコードされました。

MIMEエンコードされたサブジェクト
=?ISO-2022-JP?B?GyRCJDMkbCRPGyhKXBskQiVeITwlLyRIGyhKfhskQiROJUYlOSVIGyhK?=

$decoded_subject=mb_decode_mimeheader($subject_header[1]);
    ↓
$decoded_subject=exec("echo '$subject_header[1]' | nkf -m -e");

つまるところ、

・ISO-2022-JPからEUC-JPやShift_JISに変換するときに、
 ASCIIとJIS X 0201-1976の2文字分の違いをどうするかは実装依存らしい。
・nkf1.7はJIS X 0201-1976をASCIIと同一視して扱っている模様。
・PHP4のマルチバイト関数は問題の2文字を「変換不能な文字」と見なして
 ?に置き換えている。

のではないかと。
また本文については、

This is testmail.
 !"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
`abcdefghijklmno
pqrstuvwxyz{|}~
これはテストメールです。
 !"#$%&'()*+,-./
0123456789:;<=>?
@ABCDEFGHIJKLMNO
PQRSTUVWXYZ[\]^_
`abcdefghijklmno
pqrstuvwxyz{|}~
テストメールの最後の行です。

をMicrosoft Entaurageから送信した場合、

8行目の頭でJIS X 0208-1983を指示するESC $ B
8行目の最後でJIS X 0201ローマ文字を指示するESC ( J
15行目頭でJIS X 0208-1983を指示するESC $ B
15行目の最後でJIS X 0201ローマ文字を指示するESC ( J

となっています。
PHP4のマルチバイト関数は、
ASCIIにおけるbackslash(0x5c)とtilde(0x7e)はそのまま、
JIS X 0201ローマ文字における半角円マークと半角オーバーラインは
(EUC-JPには変換先となる文字がないので)
厳密な解釈をして「変換不能な文字」として?に置き換える、
というポリシーになっているのではないかと。

松川さんのとこではどのようになっていますでしょうか?


変換ポリシーをゆるやかにしてくれるオプションがあればとは思うのですが、
(知らないだけでしたらご指摘くださいませ)
とりあえず、対応策として現時点では以下の3案を考えています。

・JIS->SJIS->EUC変換をさせて、
 半角円マークと半角オーバーラインは全角にしてしまう

・mb_convert_encodingを使わず、
 nkfを使ってJIS->EUC変換をさせてテンポラリファイルを生成し、
 そのファイルを再度読み込んで利用する

・PHP,PostgreSQLとも内部コードをUTF-8にする
 (ただし他の部分も含めてうまくいくかどうかは未調査)


-----
>>>  With your dreaming,           ☆彡  Hayakawa,Hiroshi          <<<
>>>          with your smile.    ☆彡    hayakawa@sam.hi-ho.ne.jp  <<<
>>>                            ☆彡      Nagoya,Aichi,JAPAN        <<<