• 締切済み

perl5.8のエンコードで悩んでます

perl5.8のエンコードで悩んでいます。 5.6環境下でjcodeなどを使用したいろいろな処理は普通にできるのですが、そろそろ5.8での文字処理もちゃんとできないとあぶないかなと思い、練習していましたが…なんとも挙動が解らないときがあります…。 よければご教授いただけると幸いです。 まず基本的な練習として、POSTされた文字データを受領するものを作ってみました。 <<送信元 post1.html>> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <p>POST実験</p> <form id="form1" method="get" action="post2.cgi"> <p>data1 <input name="data1" type="text" /> </p> <p>data2 <input name="data2" type="text" /> </p> <p> <input type="submit" name="button" value="送信" /> </p> </form> </body> </html> <<受領部 post2.cgi>> #!/usr/bin/perl #モジュール利用宣言 use CGI; #CGIモジュール use strict; #表記の正規化を強制 use warnings; #警告表示 use CGI::Carp qw(fatalsToBrowser); #エラー報告有効 #エンコーディングの指定 #use utf8; #この部分を有効にすると入力内容が文字化け #use encoding 'UTF-8';#これも同様に入力内容が文字化け #データの受領と変数名整理 my $input_data = new CGI; my $in_data1 = $input_data->param('data1'); my $in_data2 = $input_data->param('data2'); #入力チェック my $message_data = ""; #変数初期化 if($in_data1 eq "" && $in_data2 eq ""){$message_data = "入力部に空欄があります";} else{$message_data = 'Data1は'.$in_data1.'Data2は'.$in_data2.'です';} #ヘッダ発行 print "Content-type: text/html\n\n"; #html表示 print <<END_OF_HTML; <!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=utf-8" /> </head> <body> <p>サシスセソはSJISで化けるカタカナ。<br>入力内容は${message_data}</p> </body></html> END_OF_HTML exit; 両ファイルともTeraPadを利用して、文字コードはUTF-8N、改行はLFにしています。 しかし、use utf8;と書くと、入力文字が化けてしまいます。 (コメントアウトすると普通に表示されます) ちょっと漠然としていて申し訳ないのですが、なぜ化けるんでしょう…。 いろいろ調べてみたんですが、binmode STDOUT, ":encoding(utf-8)";とかをつけても特に変化がありません…。 しかし変わりすぎてキツい…でも今は5.8仕様の文字処理ができないとあぶないのかなぁ…。

  • Perl
  • 回答数3
  • ありがとう数4

みんなの回答

  • Werner
  • ベストアンサー率53% (395/735)
回答No.3

> ↓はPOSTされ、CGI.pmで受領したデータを、現在のperlスクリプトが使用するutf8形式にデコードする。と考えてよろしいでしょうか? > my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更 意味合いとしては、utf8の文字列を内部形式(uft8)にデコードしてます。 しかし実際には、UTF-8フラグが付くだけです。 私も前に答えたときは確信がなかったので言いませんでしたが、 文字化けする原因は$in_data1や$in_data2にUTF-8フラグが付いていないことです。 たとえば、以下のコードのようにわざとUTF-8フラグを落とすと 最後のprintで出力されたテキストはutf8としても読めないものになってしまいます。 #-----------------------------------------------------------# use strict; use utf8; use open ":utf8"; use open ":std"; #標準入出力にutf8を指定。 my $data="こんにちは"; #use utf8してるのでUTF-8フラグが付いている utf8::encode($data); #わざとUTF8フラグを落とす #↑は$data = Encode::encode('utf8',$data); と同じ。 print $data; #正しく出力されない # UTF8フラグが落ちてるので、出力時に$dataの内容がLatin 1と見なされて # 強引にUTF8に変換(upgrade)されてしまい文字化けする。 #-----------------------------------------------------------# あなたが最初に提示しているコードの場合、 文字化けはUTF8フラグが立っている文字列と UTF8フラグが立っていない文字列を連結したときに起こっています。 このときもUTF8フラグが立っていない文字列がupgradeされるので 文字化けしてしまいます。 Encode::decode('utf8', $data); はutf8をutf8(内部形式)に変換しており一見無意味なようですが、 この処理をしないとperlは$dataがutf8だと言うことが分かりません。 なのでちゃんと教えてあげないと、perlは不適切なupgradeをしてしまうのです。 [参考] Perl 5.8 以降においての Unicode 文字列の扱い方 : NDO::Weblog http://naoya.dyndns.org/~naoya/mt/archives/000611.html Perl 5.8.x Unicode関連 http://www.rwds.net/kuroita/program/Perl_unicode.html > もし元の文字コードがわからなかったら Encode::Guessなどで推測は可能ですが、 推測は失敗することもあります。 普通は送り側も自分で書きますから 送られてくる文字コードが不明と言うことは普通はないのではないかと思います。 > binmode(STDIN,":encoding(sjis)") ; ブラウザはgetやpostでデータを送るときに 「%A4%B3%A4%F3%A4%CB%A4%C1%A4%CF」のようにエンコードしてから送るので、 たとえ漢字やひらがなを送ったとしても実際に送られてくるのはASCII文字だけです。 (CGI.pmが元に戻しているので気づいていないかもしれませんが。) なのでエンコード指定は無意味なきがします。 あと、postの場合はSTDINからデータが得られますが、 getの場合は環境変数から取得するのでSTDINのモードを変更しても影響ないでしょう。

  • Werner
  • ベストアンサー率53% (395/735)
回答No.2

問題があると言ったけど、 CGI.pmはデコードまで責任を持たないと考えれば これはこれで良い気もしてきた。 もし、post1.htmlをEUC-JPで書いた場合は、 #-------------------------------------------------- my $in_data1 = Encode::decode('euc-jp', $input_data->param('data1')); my $in_data2 = Encode::decode('euc-jp', $input_data->param('data2')); #-------------------------------------------------- とする必要があるわけだし、 内部コードに変換するために必ずこれが必要になったと思えば良いのかな。

  • Werner
  • ベストアンサー率53% (395/735)
回答No.1

どうやら、CGI.pmの実装に問題があるようですね。 (私も基本的にuse utf8してますが、 CGI.pm使わずにpostデータを解析してるのでこの問題は今初めて知りました。) とりあえず以下のような変更をすればちゃんと表示されると思います。 #-------------------------------------------------- use utf8; use Encode; #追加 my $input_data = new CGI; my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更 my $in_data2 = Encode::decode('utf8', $input_data->param('data2')); #変更 #-------------------------------------------------- #参考 CGI.pmとUTF8 flag : blog.nomadscafe.jp http://blog.nomadscafe.jp/archives/000491.html

tokiqa_id
質問者

お礼

ご指摘のように修正しましたら、ちゃんと動くようになりました。 バグではないとは言え、CGI.pmに起因する問題だったのですね。 ありがとうございます。 できましたら少しばかり追加質問なのですが…、 ↓はPOSTされ、CGI.pmで受領したデータを、現在のperlスクリプトが使用するutf8形式にデコードする。と考えてよろしいでしょうか? my $in_data1 = Encode::decode('utf8', $input_data->param('data1')); #変更 (…もし元の文字コードがわからなかったら…いやでも最近はhtml側でもキャラセット指定が入るし、大丈夫なのかな) と言うことはつまり、perl5.8で「use utf8;」を使用するということは、スクリプトファイル自体の文字コードを宣言することと同時に、スクリプトが動作するときに、どのような文字コード体系で文字を扱うかを指定する…と考えても良いのかな…。 従来は特に指示しない場合、スクリプトファイル自体の文字コードで処理していたと思うのですが…しっかり指定しないといけないのか…。 ちなみに携帯とかではSJISを使うことになりますが、この場合は下のようになるのでしょうか? use utf8; binmode(STDIN,":encoding(sjis)") ; binmode(STDOUT,":encoding(sjis)") ; …でも、調べてみるとbinmodeはファイルの取り扱いについて指定するとあるので、POSTデータには作用しないのかな…。いやそもそもCGI.pmを使う以上、ご指摘いただいたように全データをデコード、エンコードし直す…ことになるのかな…。 ううむ…むずかしい…。ちょっと今はスクリプトに触れないのですが、後日自分でも試してみます。

関連するQ&A

  • なぜ文字化けしないのでしょうか?

    Windows Me(shift_jis)とFedoraCore4(utf-8)のPCのブラウザに以下のFedoraCoreのPCに配置してあるgomi.php(utf-8で記載)を表示させて 入力欄に「お元気ですか。」と日本語を入れてもその応答が文字化けしません FC4はutf-8なのでshift_jisのWindows Meでは文字化けするはずですがしませんがどうしてでしょうか? gomi.php -------------------------------------------------------- <?php $in=isset($_POST['in'])?$_POST['in']:'bad'; echo '<?xml version="1.0" encoding="utf-8"?>'; ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja"> <head> <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8"/> <title>test</title> </head><body> <p><?= $in ?></p> <form method="post" action="<?= $_SERVER['PHP_SELF'] ?>"> <input type="text" name="in"/> <input type="submit" value="送信"/> </form> </body></html>

    • ベストアンサー
    • PHP
  • 初歩的な質問で恐縮ですが、教えてください。

    すみませんが、教えてください。 入力フォームでデータが送れなくて、困っています。 下のコードに問題点はあるのでしょうか? 自分では、分からないので、よろしくお願いいたします。 test1.php------------------- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> </head> <body> <form method="post" enctype="multipart/form-data" action="./test2.php"> <input type="text" name="fmTitle" ><br /> <input type="submit" value="次へ" > </form> </body> test2.php-------------------------- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> </head> <body> <?= $fmTitle . "<br />" ?> </body>

    • ベストアンサー
    • PHP
  • 前後の全角スペースを削除すると文字化けする

    PHP初心者です。 trimファンクションを使って前後の全角スペースを削除したいのですが $test = " 左右に全角スペースがある文字列 "; echo trim ( $test , " " ); だと問題なく表示されるのですが以下のようにテキストボックスに入力した文字の 前後の全角スペースを削除しようとすると最初の1文字目が文字化けします。 ●test_input.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>前後の全角スペースを削除する</title> </head> <body> <form action="test.php" method="get"> <dl> <dt>文字を入力してください。</dt> <dd><input type="text" name="test" size="50" maxlength="50" id="test" /> </dd> </dl> <input type="submit" value="送信する" /> </form> </body> </html> ●test.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>前後の全角スペースを削除する</title> </head> <body> <p>入力文字</p> <?php $test = ($_REQUEST['test']); echo ($test); ?> <br /> <br /> <p>trim ( $test , " " )</p> <?php echo trim ( $test , " " ); ?> </body> </html> どこがいけないのでしょうか? よろしくお願いします。

    • ベストアンサー
    • PHP
  • phpのフォーム入力で

    phpの勉強初日なのですが、さっそくつまづいてしまいました。 買った本に沿って、簡単なフォーム入力のhtmlファイルと、 その処理のphpファイルを下記のように作ってみたのですが、上手く行きません。 htmlのフォームからのpostは出来ているようなのですが、 phpファイルがコールされると、phpファイルのソースがそのまま表示されてしまって、 postした文字列がechoされません。。。 初日でつまづいてしまっていきなり挫折しそうです。。。 どなたかお詳しい方、お教えいただけると幸いです。 ■input.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>input</title> </head> <body> <form action="inputphp.php" method="post"> <label for="my_name">お名前:</label> <input id="my_name" type="text" name="my_name" size="15" maxlengh="255" value=""/> <input type="submit" value="送信"/> </form> </body> </html> ■inputphp.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>inputphp.php</title> </head> <body> <?php print($_REQUEST['my_name']); ?> </body> </html>

    • ベストアンサー
    • PHP
  • 多言語ページのエンコード記述が分かりません

    友人に頼まれてサイトの挨拶文のようなページを、英語バージョンと中国語バージョンで作っています。 ナビゲーションなどは日本語のままで、メインのコンテンツエリアのみ英語や中国語を書くので2つの言語が交じるページとなります。 文字化けを防ぐためのエンコードがいまいち分かりません… 分からないなりに書いては見たものの、これであっているのかも分かりません。 (確認する方法はあるのでしょうか) コードを書いてみました。 添削やアドバイスをお願いします。 ───────────────────────── 【英語と日本語のページ】 ※エンコードをUTF-8にしただけです。 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Style-Type" content="text/css"> <title>△△△</title> <link href="◯◯◯.css" rel="stylesheet" type="text/css" media="all" /> </head> ───────────────────────── 【中国語と日本語のページ】 ※ネットで検索してcharset=bg2312、 lang="ja,zh" xml:lang="ja,zh"を書きましたがこれでいいんでしょうか? <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="ja,zh" xml:lang="ja,zh"> <head> <meta http-equiv="Content-Type" content="text/html; charset=bg2312" /> <meta http-equiv="Content-Style-Type" content="text/css"> <title>△△△</title> <link href="◯◯◯.css" rel="stylesheet" type="text/css" media="all" /> </head> ───────────────────────── また、友人のサイトを見てみるとその他すべてのページはShift_JISで作られています。 これは海外の人が開くと文字化けしてしまうということなのでしょうか? 日本語の表示のままでいいのですが、UTF-8にしたほうがいいのでしょうか? わからない事だらけでスミマセン(;_;) よろしくお願いします。。

  • utf-8 文字化け

    メモ帳でhtmlページを作成してたのですが、日本語を入力してIEで確認したら文字化けになります 原因がわからず困っていました よろしくお願いします IE10 IE 表示 エンコードはutf-8 自動選択にすると日本語表示になります <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>ABC</title> <style type="text/css"> </style> </head> <body> <h1>ようこそ</h1> <p></p> </body>

  • charsetとフォーム入力文字

    Htmlファイルの先頭が <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> ・・・ で始まります。 このファイルのフォームに入力した文字はUTF-8で送られるのでしょうか。 それともOSの文字コードに依存するのでしょうか?

    • ベストアンサー
    • HTML
  • html →perlへフォームを渡そうとしてますが

    独学でmacでパールを勉強しています。 始めてからまだ1週間すこしくらい。 教科書読みながら、 CGIへフォームを渡す所の段階まで進んできました。 現段階で、htmlからperlへフォームを渡そうとしているのですが、 上手く行きません。 状況としては、htmlのフォームを入力して、登録を押す。 成功であれば→実行結果が表示されるはずなのですが、 現段階ではFinderがその実行htmlの場所を開くだけという形になっています。 下記は実験用に使っているソースです。 ーーーーーーーーーーー htmlは <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <title>test</title> <style type="text/css"> </style> </head> <body> <h1>メンバーズリスト</h1> <form method="post" action="form.cgi"> <p> 名前:<br/> <input type="text" name="name"/> </p> <p> 性別: <input type="radio" name="sex" value="male" checked>男 <input type="radio" name="sex" value="female">女 </p> <input type="checkbox" name="megane">メガネを付けてる </p> <p> <select name="kankei"> <option value="yuujin">友人 <option value="kaisya">会社関係 <option value="sonota">その他 </select> </p> <p> 住所: <textarea name="jyusyo" rows="5" cols="40" ></textarea> </p> <p> <input type="submit" value="登録"/><input type="reset" value="クリア"/> </p> </form> </body> </html> ーーーーーーーーーーーーーーーーー perlは #!/usr/bin/perl require 'cgi-lib.pl'; &ReadParse(*form); $name = $form{'name'}; $sex = $form{'sex'}; $megane = $form{'megane'}; $kankei= $form{'kankei'}; $jyusyo = $form{'jyusyo'}; print "Content-type: text/html\n\n"; print "<HTML>\n"; print "<HEAD><TITLE>情報受け取り</TITLE></HEAD>\n"; print " <BODY>\n"; print "<H1>情報受け取り</H1><HR>\n"; print "名前:${name}<BR>\n"; print "性別:${sex}<BR>\n"; print "めがね:${megane}<BR>\n"; print "関係:${kankei}<BR>\n"; print "住所${jyusyo}<BR>\n"; print "</BODY>\n"; print "</HTML>\n"; __END__ です。 ちなみに localhost上で同一ファイルに入れて、 動かしてます。 ご確認の上、ご助言ください、 perlの教科書に書いてあった構文は、 htmlの学習をするために使ってきたものと全く違ったため、 要点だけ残す形で、再度書いたものです。 htmlの文章がおかしいのか、perlがおかしいのか、 頭が変になりそうです。お助けください。

    • ベストアンサー
    • Perl
  • Firefoxで参照ボタンのURL入力欄をCSSで装飾出来ない。(formで設定したfile入力欄をCSSで制御する方法)

    以下の記述(inputタグの枠線を赤で表示)をしているのですが、inputタグのファイル送信欄だけ装飾されません。 IEではちゃんと表示されました。 どこが問題なのでしょうか? お分かりの方いらっしゃいましたら回答よろしくお願いします。 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>test page</title> <style type="text/css"> form { background:#99FF99; } input { border:5px solid #FF0000; } </style> </head> <body> <form action="test.php" method="post" enctype="multipart/form-data"> テキストの入力欄 <input type="text" name="test_text" /> <br /><br /> ファイル送信欄 <input type="file" name="test_file" /> <br /><br /> <input type="submit" value="送信する" /> </form> </body> </html>

    • ベストアンサー
    • HTML
  • $error配列がUndefined indexに

    簡単な入力フォームを初心者用の本に沿って作成しているのですが、 入力フォームのチェックで$error配列を使う部分で、 nameがblankかどうか確認する部分で、なぜかnameがNotice: Undefined indexとなってしまいます。 お詳しい方、下記のコードを見て何か原因をお分かりになりますでしょうか? <?php session_start(); if(!empty($_POST)){ if($_POST['name']==''){ $error['name']='blank'; } } ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Upload</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <p>次のフォームに必要事項をご記入下さい。</p> <dl> <dt>ニックネーム<span class="required">必須</span></dt> <dd><input type="text" name="name" size="35" maxlength="255" value="<?php echo htmlspecialchars($_POST['name'], ENT_QUOTES, 'UTF-8'); ?>" /> <?php if ($error['name'] == 'blank'): ?> <p class="error">* ニックネームを入力してください</p> <?php endif; ?> </dd> </dl> </form> </body> </html>

    • 締切済み
    • PHP