質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

CGI

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

Q&A

解決済

2回答

1453閲覧

PerlでMariaDBからデータを入れてhtml出力すると文字化けします

snow2021

総合スコア12

Perl

Perlは多目的に使用される実用性が高い動的プログラミング言語のひとつです。

CGI

CGI(Common Gateway Interface)とは、Webサーバー上でユーザプログラム動作させる仕組みのこと。また、動かす前提のプログラムをCGIと呼ぶこともあります。HTMLなどの静的な情報に限らず、プログラムの処理結果をベースにした動的情報の提供が可能です。

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

MariaDB

MariaDBは、MySQL派生のオープンソースなリレーショナルデータベースシステムです。 また、MySQLとほぼ同じデータベースエンジンに対応しています。

0グッド

0クリップ

投稿2022/03/07 21:04

編集2022/03/07 23:32

CGIをPerlで書いて、MariaDBからデータを抽出して、HTML出力した場合、なぜか文字化けします。
CGIファイルは、UTF-8です。

MariaDBに対して、「show variables like 'char%'」を打つと、下のようになります。
character_set_client : utf8mb4
character_set_connection : utf8mb4
character_set_database : utf8mb4
character_set_filesystem : binary
character_set_results : utf8mb4
character_set_server : utf8mb4
character_set_system : utf8
character_sets_dir : /usr/share/mysql/charsets/

character_set_filesystem 以外、utf8の方がよさそうですが、インターネットのサーバー上にあるため、my.iniファイルが変更する方法がわかりません。

クライアント側の環境:Windows11
サーバー側の環境: Linux
サーバの種類 : MariaDB
サーバのバージョン: 10.5.13-MariaDB-log - MariaDB Server
プロトコル バージョン : 10
ウェブサーバ : Apache
データベースクライアントのバージョン: libmysql - 10.1.48-MariaDB

CGIはHTMLファイルのテンプレートを読み込んで、データを埋め込む形にしています。
エラーとしては、「[sample.cgi:206:warn] Wide character in print at sample.cgi line 206.」とWeb上で表示されています。
206行目は、HTMLタグにデータを埋め込んだ変数をprintしています。

なお、DBのデータだけでなく、data.plファイルをrequireしてsample.cgiの変数に格納してHTML出力していますが、こちらの文字列も文字化けしています。data.plファイルも、UTF-8です。
plファイルの中身は、設定ファイルになっており、web siteの名前とか、site管理者の名前などがハッシュに格納されています。
大体が、「ブログ」という感じで表示されています。

+------+------------+----+----+-------+----------------+
|Field -|Type -------|Null| Key|Default| Extra |
+------+------------+----+----+-------+----------------+
|id |int(6): | NO | PRI| NULL | auto_increment|
+------+------------+----+----+-------+----------------+
|t_bi |datetime | NO | | NULL | |
+------+------------+----+----+-------+----------------+
|ca_no |int(2) | NO | | NULL | |
+------+------------+----+----+-------+----------------+
|title |varchar(400)| NO | | NULL | |
+------+------------+----+----+-------+----------------+
|kizi |text | NO | | NULL | |
+------+------------+----+----+-------+----------------+
|k_bi |datetime |YES | | NULL | |
+------+------------+----+----+-------+----------------+
|iine |int(10) | NO | | 0 | |
+------+------------+----+----+-------+----------------+
|user |varchar(100)| NO | | NULL | |
+------+------------+----+----+-------+----------------+

perl

1use strict; 2use DBI; 3 4require 'data.pl'; 5require 'db.pl'; 6my %out = &out_set; 7my %in = &parse_deco; 8 9my $data_source = $out{"data_source"}; 10my $username = $out{"username"}; 11my $password = $out{"password"}; 12my $user_nm = $in{"user_name"}; 13my $categpry = 1; 14 15# DB接続 16my $dbh = DBI->connect($data_source, $username, $password,{mysql_enable_utf8 => 1}) or die $DBI::errstr; 17 18my $sth = $dbh->prepare(qq{ 19 SELECT * FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' ORDER BY id DESC LIMIT 1 20}); 21 22$sth->execute; 23my %row; 24my $i = 0; 25while (my $ary_ref = $sth->fetchrow_arrayref){ 26 ($row{"id_$i"},$row{"t_bi_$i"},$row{"ca_no_$i"},$row{"title_$i"},$row{"kizi_$i"},$row{"k_bi_$i"},$row{"iine_$i"},$row{"user_$i"}) = @$ary_ref; 27 $i++; 28} 29$sth->finish; 30 31my $sth2 = $dbh->prepare(qq{ 32 SELECT t_bi FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' 33}); 34$sth2->execute; 35 36my @tourokubi = (); 37my $t = 0; 38while (my $ary_ref = $sth2->fetchrow_arrayref){ 39 ($tourokubi[$t]) = @$ary_ref; 40 $t++; 41} 42$sth2->finish; 43 44my $sth3; 45my ($yaer,$month); 46my %month; 47foreach(@tourokubi){ 48 $_ =~ /(\d\d\d\d)-(\d\d)-(\d\d)/; 49 $yaer = $1; 50 $month = $2; 51 $sth3 = $dbh->prepare(qq{ 52 SELECT COUNT(*) FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' AND t_bi LIKE '%$yaer-$month%' 53 }); 54 $sth3->execute; 55 while (my $ary_ref = $sth3->fetchrow_arrayref){ 56 ($month{"$yaer-$month"}) = @$ary_ref; 57 $t++; 58 } 59 $sth3->finish; 60 $sth3 = ""; 61} 62 63 64 65 66# DB切断 67$dbh->disconnect; 68 69# HTML表示 70 71 print <<"TAG"; 72Content-type:text/html 73 74<html> 75<head> 76 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 77 <title>DB test</title> 78</head> 79<body> 80TAG 81 82my $key; 83foreach $key( keys %row){ 84 print qq|$key = $row{"$key"}<br>\n|; 85} 86 87my $key2; 88my $yyyymm; 89foreach $key2( sort keys %month){ 90 $yyyymm = $key2; 91 $yyyymm =~ s/(\d\d\d\d)-(\d\d)/$1年$2月/; 92 print "$yyyymm($month{$key2})<br>\n"; # count 93} 94 95 96 97 print <<"TAG2"; 98</body> 99</html> 100TAG2 101 102exit;

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2022/03/07 21:12

テーブル定義も提示してください。 あと、コードも。
snow2021

2022/03/07 21:43

テーブル定義とコード無しですみませんでした。 テーブル定義は、下のようになっています。 +------+------------+----+----+-------+----------------+ |Field |Type |Null| Key|Default| Extra | +------+------------+----+----+-------+----------------+ |id |int(6): | NO | PRI| NULL | auto_increment| +------+------------+----+----+-------+----------------+ |t_bi |datetime | NO | | NULL | | +------+------------+----+----+-------+----------------+ |ca_no |int(2) | NO | | NULL | | +------+------------+----+----+-------+----------------+ |title |varchar(400)| NO | | NULL | | +------+------------+----+----+-------+----------------+ |kizi |text | NO | | NULL | | +------+------------+----+----+-------+----------------+ |k_bi |datetime |YES | | NULL | | +------+------------+----+----+-------+----------------+ |iine |int(10) | NO | | 0 | | +------+------------+----+----+-------+----------------+ |user |varchar(100)| NO | | NULL | | +------+------------+----+----+-------+----------------+ コードは、以下のようになります。 use strict; #use KCatch; use DBI; require 'data.pl'; require 'db_setuzoku.pl'; my %out = &out_set; my %in = &parse_deco; my $data_source = $out{"data_source"}; my $username = $out{"username"}; my $password = $out{"password"}; my $user_nm = $in{"user_name"}; my $categpry = 1; # DB接続 my $dbh = DBI->connect($data_source, $username, $password,{mysql_enable_utf8 => 1}) or die $DBI::errstr; # SELECT * FROM blog WHERE user = $user_nm, ca_no = $categpry, t_bi LIKE '%2021-04-23 %' # SELECT * FROM blog WHERE`ca_no`='1' AND `user`='snow' ORDER BY `id` DESC LIMIT 1 my $sth = $dbh->prepare(qq{ SELECT * FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' ORDER BY id DESC LIMIT 1 }); $sth->execute; my %row; my $i = 0; while (my $ary_ref = $sth->fetchrow_arrayref){ ($row{"id_$i"},$row{"t_bi_$i"},$row{"ca_no_$i"},$row{"title_$i"},$row{"kizi_$i"},$row{"k_bi_$i"},$row{"iine_$i"},$row{"user_$i"}) = @$ary_ref; $i++; } $sth->finish; my $sth2 = $dbh->prepare(qq{ SELECT t_bi FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' }); $sth2->execute; my @tourokubi = (); my $t = 0; while (my $ary_ref = $sth2->fetchrow_arrayref){ ($tourokubi[$t]) = @$ary_ref; $t++; } $sth2->finish; my $sth3; my ($yaer,$month); my %month; foreach(@tourokubi){ $_ =~ /(\d\d\d\d)-(\d\d)-(\d\d)/; $yaer = $1; $month = $2; $sth3 = $dbh->prepare(qq{ SELECT COUNT(*) FROM blog WHERE user = '$user_nm' AND ca_no = '$categpry' AND t_bi LIKE '%$yaer-$month%' }); $sth3->execute; while (my $ary_ref = $sth3->fetchrow_arrayref){ ($month{"$yaer-$month"}) = @$ary_ref; $t++; } $sth3->finish; $sth3 = ""; } # DB切断 $dbh->disconnect; # HTML表示 print <<"TAG"; Content-type:text/html <html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>DB test</title> </head> <body> TAG my $key; foreach $key( keys %row){ print qq|$key = $row{"$key"}<br>\n|; } my $key2; my $yyyymm; foreach $key2( sort keys %month){ $yyyymm = $key2; $yyyymm =~ s/(\d\d\d\d)-(\d\d)/$1年$2月/; print "$yyyymm($month{$key2})<br>\n"; # count } print <<"TAG2"; </body> </html> TAG2 exit;
m.ts10806

2022/03/07 22:52

質問は編集できますし、コメントではマークダウンの機能が使えませんので、質問本文に移行してください。 ※あとコードはそのまま提示ではなくマークダウンのcodeを利用してください。https://teratail.com/questions/238564
snow2021

2022/03/07 23:10

重ね重ねすみません。 質問の本文に加筆しました。 これでよいでしょうか?
guest

回答2

0

perlで「日本語」のテキストを弄るには、

  • 取り込んだデータを「内部コード」化(デコード)
  • 全ての操作は内部コード化したデータについてのみ実行
  • 出力の間際にUTF-8なりshift-JISなりにエンコード

これを徹底しなければなりません。

さしあたり、スクリプトの中に などの文字が入っているので、これをデコードして取り扱うために冒頭にuse utf8;が必要です。

DBからデータを取り込む段階で、デコードのステップを付け加える必要があります。たぶん

while (my $ary_ref = $sth->fetchrow_arrayref){ ($row{"id_$i"},$row{"t_bi_$i"},$row{"ca_no_$i"},$row{"title_$i"},$row{"kizi_$i"},$row{"k_bi_$i"},$row{"iine_$i"},$row{"user_$i"}) = map {decode('UTF-8',$_)} @$ary_ref; ...

とかそんな感じ。

出力を標準出力に出すなら、これをエンコードする処理が必要です。スクリプト冒頭に

binmode(STDOUT, ':utf8');

と書けば、以降は全部エンコードされた上で出力されます。

参考:
perl jsonで日本語文字化け

投稿2022/03/08 07:57

KojiDoi

総合スコア13671

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

snow2021

2022/03/08 08:41

色々回答をありがとうございます。 こちらでも、色々試行錯誤して、 use open IO => ":utf8"; と先にuseしてみました。それから、 my $sample = Encode::decode('utf-8', $sample); と、デコードしてみました。 でも、変数に対して、イチイチデコードするのも大変ですから、 binmode(STDOUT, ':utf8'); で、よかったのかもしれません。
snow2021

2022/03/08 08:43

追記で、大概は文字化けが治りました。 が、まだ、「Wide character in print at..」というエラーは出ています。 ですから、 binmode(STDOUT, ':utf8'); で試そうかと思います。
guest

0

ベストアンサー

エラーとしては、「[sample.cgi:206:warn] Wide character in print at sample.cgi line 206.」とWeb上で表示されています。

有名なエラーだから検索するといろいろ出てくるような気がしますが、

perl で UTF-8 を使うときによく紹介される

perl

1use utf8; 2binmode(STDOUT, ':utf8');

を追加するとどうなるでしょうか。

投稿2022/03/08 04:35

CHERRY

総合スコア25171

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

snow2021

2022/03/08 09:23

use utf8; binmode(STDOUT, ':utf8'); と、書き足してみましたら、文字化けしてしまうので、 use utf8; を削除してみたら、問題なく文字化けが直りました。ただし、 my $sample = Encode::decode('utf-8', $sample); は必要なようです。 結果は、DBのデータは文字化けすることなく抽出することができました。 問題は、データ設定ファイルの読み出しで、文字化けしていたようです。 全てのファイルはUTF-8で保存していたのですが、Perl(CGI)上になると、 文字化けしていました。 回答をありがとうございました。
snow2021

2022/03/08 09:33

すみません、ちょっと変でしたね。蛇足ですが、 my $sample = Encode::decode('utf-8', $in{"sample"}); こんな感じで書いていました。
KojiDoi

2022/03/08 12:24

> use utf8; を削除してみたら、問題なく文字化けが直りました。 そういう対症療法的な対処を繰り返していると、どこかでどうしても治らない文字化けが出てきて辛いことになりますよ。 スクリプトの中に漢字を直接書いている以上は、use utf8はマストです。 binmode(STDOUT, ':utf8')して出力が化けるとしたら、おそらくどこかで既にエンコードしたものを二重にエンコードしようとしています。その手順を見直すべきです。
snow2021

2022/03/12 00:07

> スクリプトの中に漢字を直接書いている以上は、use utf8はマストです。 とのことなんですが、UTF-8で保存されたCGIファイルも、useの必要があるんですね? UTF-8で保存されたCGIファイルに、さらにuse utf8をしたら、文字化けしそうなイメージがあるのですが、 その辺はどうなんでしょうか? インターネットで調べても、あまりUTF-8で保存されたファイルに対してのuse utf8とは明記していないようで、 ちょっとわかりにくくて困っています。
KojiDoi

2022/04/11 04:03

use utf8は、厳密性を脇に置いてざっくり言うと、「コードの中に書いてある全角文字は全部デコードして扱うよ」という宣言です。ですから、「UTF-8で保存されたCGIファイルに、さらにuse utf8をしたら、文字化け」などということはあり得ません。必ずuse utf8は書くべきです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問