CGI-BBS > CGI > Perl > 文字の消失


カレッヂ
カレッヂ


質問者 ひろ  投稿日 2/19(月) 21:31:46
「プロセス番号の意味」のスレッドにてお世話になりました。
処理の流れ等はそちらと同じですので、詳しい背景は省略されて頂きます。

以下の状態で、どんな原因が考えられるのかを教えて頂きたいと思います。

入力フォームから送られてきたデータを、CGI(A)にてテキストファイルに書き出します。
この時点でのテキストファイルにはデータの欠損は認められません。
(この時点のデータを別ファイルに書き出して確認しました)

このテキストファイルをCGI(B)にて読み出し、配列に格納してsendmailしています。
この時にデータ内の文字が「消失している事」がありました。
いつもではありません。
現在確認できたのは漢字の「助」(人名の一部です)と
カタカナの「カ」の文字です。
これまで同じスクリプトで処理を行ってきましたが、
こういった「消失」はありませんでした。
(1)読み込んで配列に格納する所と、(2)その配列を書き出す所の
スクリプトを下に載せておきますのでお願い致します。

データの内容は、住所・氏名・電話番号・メールアドレス等
注文する際に必要となる項目です。
また、CGI(A)からCGI(B)への間に特に処理はあてていません。

---------------------
require 'jcode.pl';
-------(1)---------
open (FILE,"data.txt");
    while (<FILE>) {
        chomp if /\n$/;
        ($name, $value) = split(/=/);
        $value =~ tr/+/ /;
        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
        $name =~ tr/+/ /;
        $name =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
        
        &jcode'convert(*name,'sjis'); &jcode'convert(*value,'sjis');
        
            $name =~ s/\s*//g;
            $value =~ s/\s*//g;
        
        if ($value =~ /\r\n/) { $value =~ s/\r\n//g; }
            elsif ($value =~ /\r/) { $value =~ s/\r/\n/g; }            
        
        if ($name =~ /^email/i || $name =~ /^e\-mail/i) {

                $value =~ s/ / /g;
                if ($value =~ / / || $value =~ /;/) { $value = ""; }

                $email = $value;
                }
        
        push(@DATA_N,$name); push(@DATA_V,$value);
    }
    close(FILE);

--------(2)----------
sub sendmail {

if (!(open(OUT,"| $sendmail -t"))) { &error('システム異常','申し訳ありませんが何らかの原因で処理できません.'); }

$count = @DATA_N;
foreach (0..$count-1) {

if ($DATA_V[$_] =~ /\n/) { &jis("$DATA_N[$_] =\n\n$DATA_V[$_]\n");
print OUT "$msg\n"; }
else { &jis("$DATA_N[$_] = $DATA_V[$_]"); print OUT "$msg\n"; }
}
close(OUT);
------------------
sub jis { $msg = $_[0]; &jcode'convert(*msg, 'jis'); }
------------------

何故文字が消えたり消えなかったりするのでしょうか?
どこかおかしいですか?

回答者 さくら  [削除]  投稿日 2/20(火) 02:48:52
コードの一部を拝見しました。
やや冗長な感じも致しますが、それはさておき今回の質問についてですが、
文字が失われたしまうようなコードは、特に無いように感じます。

一つづつ確認して見る必要が有るのではないでしょうか。

1. 同じデータを送った場合、常にデータが失われるのか?
(確認されている 助とカについては失われたときと同じデータを送って確認して見る)
2. jcode.plのコード変換時について確認して見る
3. コードブロックを終了する度に、print して見る、できれば、ファイルに書き出す

このような手順で確認していくのはどうでしょうか。

1.についてですが
 はっきり、データが失われる事を確認しないと、テストを繰り返すたびに結果が異なるのでは、コードをいじっても、完全に修正されたか確認が難しい。

2.についてですが
 jcode.plを疑うわけではないのですが、バージョンを確認して見ましょう
 必ず最新のものを使おう。現在はv2.13です。
 s-jisに変換していますが、s-jis の2バイト目はasciiと重なる事も覚えておこう。
 この程度の事でjcode.plが混乱するとは思えないが、入力された文字コードを
 指定する事によってより確実なコード変換が行なえることもある。
 (jcode.plにある getcode() というメソッドで送信された文字コードを取得できる)
 
 私自身は、下記のようにして送信データを処理しています。
 たぶん、最も確実だと思われる方法で行なっている(私が勝手に思っているのですが)
 送信されたデータは必ずeucに変換している、そして必要に応じてjis s-jisに変換する 事にしている。

 まず、form に追加する
 <input type="hidden" name="code" value="日">
これは、送信されたデータの文字コードを確実に識別する為に使う。
 スクリプト中で、"日" を $code に代入したとする。

 $code = jcode::getcode(\$code);   #perl5ではこう書ける。
 これで左辺の$codeには、文字コードが格納された(jis,s-jis,euc など)
 
 jcode::convert(\$value, 'euc', $code, 'z');
 これは、$valueの値をeucに変換する、元の文字コードは$codeである、
 'z'オプションおつけると半角カナを全角カナに変換する。
 (半角カナは1バイトで、非常に厄介な存在なので私は必ず、全角に変換している)
 
 sendmail に渡す前にjisに変換しているところも上記のように使える。
 又は、UNIXユーティリティのnkfがあれば、nkfにパイプすれば良い。
 open (OUT, "| $nkf -j | $sendmail -t")
こうすると、nkfでjisに変換されて、sendmail に送られる。($nkfにnkfのパスが入っているものとする。)

3.について
 urlデコードや、文字コード変換等は、CGI(A)に移して見る等も有効かもしれない。
 つまり、デコードして、文字コード変換してからファイルに書きこみすることによって
 そこまでの処理が正しく行なわれているか確認できる。
 CGI(B)で行なわなければいけない所は、しょうがないので、途中に別のファイルを作成 して書き込みしてみる。
  こうして、原因の場所を特定して行く事になる。

jcode.plの関係をたくさん書いたのですが、なんとなく文字消失とjcode.plの処理に
何らかの関係があるような気がしたものですから。
ちがったらゴメンナサイ!
最後にjcode.pl の使い方について日本語で解説しているページのurlを掲載しておきます。
http://www.mikeneko.ne.jp/~lab/kcode/jcode.html

 
質問者 ひろ  [削除]  投稿日 2/20(火) 14:33:03
さくらさんありがとうございます。

え〜、現在もまだ原因解析中なんですが途中経過と判明した事を。
jcode.plのバージョンですが、これまで使用していたものを確認してみたところ

$rcsid = q$Id: jcode.pl,v 2.8 1998/09/23 17:22:55 utashiro Exp $;

と書かれたものでした。v2.8? なにやら変ですね・・・
現在は最新版(?)の v 2.13 2000/09/29 16:10:05 にて試験を行っています。

再度書きますが、CGI(A)にて入力フォームからのデータをデコードし、
data.txtへ書き出します。
この時点でのデータ内容は正常です。
ちなみにデータは name = あああああ\n address = いいいいいい\n
といった形で格納されています。

このファイルをCGI(B)で読込み、上記のスクリプトで「もう一度」デコードを
かけている事により、内容がおかしくなっている事が確認されました。
「助」「カ」を含む、同じデータを何度送ってもそこだけおかしくなります。
新たに「朝」という漢字が「ト」に変換されてしまうのも見つかりました。

という事で引き続き解析を行います。


質問者 ひろ  [削除]  投稿日 2/20(火) 17:02:55
引き続き途中経過です。

CGI(B)にて、data.txtを開いて読み込み、
そのまま別のファイルに書出した時にはデータは完全なままでした。

ところが
($name, $value) = split(/=/);
して
print FILE "$name$value\n";
と書き出してみると

name          ○○ 大●
釶辣煖瘤a          タナカ ○○○○

となってしまいました。●部分が「助」です。
splitの使い方間違ってますか?
質問者 ひろ  [削除]  投稿日 2/20(火) 18:56:51
すみません。
結局理由は分からなかったのですが、
変にsplit等の処理をせずにファイル内容をそのままsendmailに出力する事で
解決しました。

さくらさん、それでも私の知識が増えましたのでお礼申し上げます。

このページは終了したので返信(回答)は書きこめません

Web裏技