

CGIモジュールを利用して、フォームを作成しているのですが、入力画面からフォームの内容を受け取る際、utf8プラグマを付けると  
受け取った内容の一部が 文字化けます。

以下のようにパラメーターを取得しています。  
どうしたらよいでしょうか  
現象はLaten-1の文字コードが表示されてしまいます。

[code]

    #!/usr/bin/perl
    use strict;
    use Encode;
    use Encode::Guess;
    use Encode::EUCJPMS;
    #use Jcode;
    use CGI;
    use utf8;
    my $cgi = new CGI;
    require 'mimew.pl';        # jcode($subject)->mime_encode が動かないとき
    #エラーメッセージをブラウザに表示
    use CGI::Carp qw(fatalsToBrowser);
    use Data::Dumper;
    ###################################
    print "Content-Type: text/html; charset=utf-8\n\n";
    # 項目名
    my @item_names = ();
    # 項目の日本語表示名
    my %item_disp = ();
    # 項目の値
    my %item_value = ();
    # 項目の必須有無
    my %item_need = ();
    # フォームパラメータ
    my %fm_param = ();
    my $cgi_url = $cgi->url();# このCGIのURL
    
    #######################################################################
    # 入力文字コード判定
    #######################################################################
    my $input_value = '';
    my $name;
    my $value;
    my @values;
    foreach $name ($cgi->param) {
    if ($name !~ /^submit$/i) {# 項目('submit'は除く)
    @values = $cgi->param($name);
    $value = join(',', @values);
    if($cgi->param('fm_command') eq 'confsend') {# 確認フォームからのときデコード
        $value = pack_param($value);
    }
    $input_value .= $value;
    }
    }
    #エラーメッセージ配列
    my @err_namelist = ();
    
    #送信データがなければエラーとする
    if (0 == length($input_value)) {
    push(@err_namelist, '呼び出しエラーです。管理者にお問い合わせ下さい。');
    print_input_error(@err_namelist);
    exit;
    }
    
    #$input_jcode = Jcode::getcode($input_value);
    my $guess = guess_encoding($input_value, qw/euc-jp shiftjis 7bit-jis/);
    my $guess_encode = ($guess->name eq 'euc-jp') ? 'eucJP-ms' : $guess->name;
    
    #######################################################################
    # パラメータ読み込み
    #######################################################################
    
    my @checkboxes_array;
    
    foreach $name ($cgi->param) {
    if ($name =~ /^fm_/) {# フォームパラメータ
    $value = $cgi->param($name);
    if($cgi->param('fm_command') eq 'confsend') {# 確認フォームからのときデコード
        $value = pack_param($value);
    }
    #$value = jcode($value, $input_jcode)->sjis;
    $value = ($guess->name ne 'shiftjis') ? encode('utf8', decode($guess_encode, $value)) : $value;
    $fm_param{$name} = $value;
    if($name =~ /^fm_disp_(\w+)/) {# 項目の日本語表示名
        $item_disp{$1} = $value;
        if(!defined $item_value{$1}) {
        push(@item_names, $1);
        $item_disp{$name} = ($guess->name ne 'shiftjis') ? encode('utf8', decode($guess_encode, $value)) : $value;
    
        $item_value{$1} = '';
    
        }
    } elsif($name =~ /^fm_need_(\w+)/) {# 項目の入力必須
        $item_need{$1} = $value;
    }
    } elsif($name !~ /^submit$/i) {# 項目('submit'は除く)
    if(!defined $item_value{$name}) {
        push(@item_names, $name);
    }
    @values = $cgi->param($name);
    
    my $len = @values;
    if ($len > 1) {
        logger($name . 'はチェックボックスなのです！で項目数は' . $len . 'なのです！(ただし複数選択可能なselectタグかもしれない・・・けど項目の上限を決めておけばいい($lenが上限以下ならselectでも項目をCSVに出す等))');
        for (my $k=0; $k<$len; $k++) {
        logger(@values[$k]);
        }
        #MEMO:
        #確認画面で項目数がここでわかったので、後ろの画面に$nameは$len項目ですと渡せばcsvでいい感じにできるのです！
        #実際の処理には現状確認画面でスペース？区切りか何かにされてしまっているため、項目数がうまくは取れないと思われる(確認画面のhiddenタグ参照の事)
        my $object = {
        name => $name,
        len => $len,
        #values => @values,
        values => [],
        };
        for (my $k=0; $k<$len; $k++) {
        logger(@values[$k]);
        push(@{$object->{values}}, @values[$k]);
        }
        push(@checkboxes_array, $object);
    }
    
    $value = join(',', @values);
    if($cgi->param('fm_command') eq 'confsend') {# 確認フォームからのときデコード
        $value = pack_param($value);
    }
    
    #$item_value{$name} = jcode($value, $input_jcode)->sjis;
    $item_value{$name} = ($guess->name ne 'shiftjis') ? encode('utf8', decode($guess_encode, $value)) : $value;
    if($item_disp{$name} eq '') {
        $item_disp{$name} = $name;
    
    }
    }
    }
    
    my $len = @checkboxes_array;
    if ($len > 0) {
    logger('新規オブジェクト配列は' . $len);
    for (my $i=0; $i<$len; $i++) {
    logger(@checkboxes_array[$i]->{name});
    logger(Dumper @checkboxes_array[$i]);
    }
    }
    
    
    $value= decode('utf-8', $value);
    foreach  my  $key (@item_names) {
    #print $item_disp{$_} .':'.$item_value{$_};
    $name = conv_html($item_disp{$key});
    $value = conv_html($item_value{$key});
    
    }
    exit;
    
    ### csvに書けるように変換
    sub conv_csv {
    my ($str) = @_;
    #$str =~ s/</&lt;/g;
    #$str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    $str =~ s/\n//g;
    $str =~ s/\,/"\,\"/g;
    #$str =~ s/"/""/g;
    return '"' . $str . '"';
    #return '' . $str . '';
    }
    sub conv_tsv {
    my ($str) = @_;
    #$str =~ s/</&lt;/g;
    #$str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    $str =~ s/\n//g;
    $str =~ s/\,/"\t\"/g;
    #$str =~ s/"/""/g;
    return '"' . $str . '"';
    #return '' . $str . '';
    }
    
    ### htmlで表示できるように変換
    sub conv_html {
    my ($str) = @_;
    
    $str =~ s/</&lt;/g;
    $str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    $str =~ s/\,/&nbsp;/g;
    $str =~ s/\n/<br>\n/g;
    
    return $str;
    }
    
    ### htmlで表示できるように変換
    sub conv_html2 {
    my ($str) = @_;
    
    $str =~ s/</&lt;/g;
    $str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    #$str =~ s/\,/&nbsp;/g;
    $str =~ s/\n/<br>\n/g;
    
    return $str;
    }
    sub conv_mail {
    my ($str) = @_;
    #$str =~ s/</&lt;/g;
    #$str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    $str =~ s/\n//g;
    $str =~ s/\,/"\t\"/g;
    #$str =~ s/"/""/g;
    return '"' . $str . '"';
    #return '' . $str . '';
    }
    
    ### hiddenパラメータに格納できるようにエンコード
    sub unpack_param {
    my ($str) = @_;
    
    $str =~ s/([^\w.\/\-@ ])/'%'.unpack('H2',$1)/eg;
    
    return $str;
    }
    
    ### エンコードしたhiddenパラメータをデコード
    sub pack_param {
    my ($str) = @_;
    
    $str =~ s/%([A-Fa-f0-9]{2})/pack('H2', $1)/eg;
    
    return $str;
    }
    
    sub conv_ahtml {
    my ($str) = @_;
    #$str =~ s/</&lt;/g;
    #$str =~ s/>/&gt;/g;
    $str =~ s/\t//g;
    $str =~ s/\r//g;
    $str =~ s/\n/<br>\n/g;
    
    return $str;
    }
    
[/code]


CC BY-SA 3.0
2015-12-16T01:28:09.010
20046
2016-10-30T14:35:29.300
2015-12-17T11:21:10.260
12324
12324
question
perl
utf8プラグマを付けると 受け取った内容の一部が文字化けます。


Perlで「UTF-8」というとき、外部とやりとりする文字コードとしてのUTF-8を指す場合と、Perlの内部文字コードとしてのUTF-8を指す場合があります。まぎらわしいですが、両者はいっしょにできない別物です。Perlの文字列として見た場合、前者はバイト列、後者は内部コード列になります。

上のコードをざっと見た限りでは、日本語文字列をバイト列として扱っているように見えます。いっぽう、utf8プラグマは、文字列を内部文字コード列として扱う宣言です。

そのため、utf8プラグマを付けないか（バイト列ベース）、入ってくる文字列をdecodeして出ていく文字列をencodeするよう全体を変更するか（内部文字コード列ベース）、どちらか合わせることになると思います。


CC BY-SA 3.0
2015-12-16T11:43:37.470
20072
2015-12-16T11:43:37.470
4010
20046
answer


最後の出力の前に、`utf8::decode($value)`を行ってみてください。

詳しい理由は、下記サイトを参照してください。

一部引用：

> use utf8 とは、
> このCGIスクリプト内で扱う全角文字は文字コードがUTF-8であり、且つ、扱う全角文字データ全てにutf8フラグ（目印みたいなもの／以下単に「フラグ」と呼称）を付けてあるのでそのつもりで処理してね、とPerl側に教えてやる宣言のこと。

PerlのCGIのutf-8改造で文字化けしたときの処方箋  
<http://mycc.s33.xrea.com/data/pc/perl_use_utf8.html>


CC BY-SA 3.0
2015-12-16T13:12:47.717
20080
2015-12-16T13:12:47.717
6150
20046
answer