MySQLに格納される文字列の標準エンコード形式はUTF-8になっている(MySQL 4.1以降、RHELではutf8がデフォルト)。
Perlでプログラムを作成する時に、UTF-8文字列を扱う方法をリストアップする。
(1)まず、MySQLの文字コードのシステム設定を調べる
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
サーバやDBの文字コードはUTF-8である。(なぜかクライアント側設定がlatinになっている…)
クライアント側の文字コードは、使用しているターミナルの文字コードにあわせないと、英数字以外表示できない状態になっている。試しに、ターミナルでの表示状態を見てみる。
mysql> select idx,name from felica_auth_tbl;
+-----+-------+
| idx | name |
+-----+-------+
| 1 | ??? | ← 日本語の部分が異常
| 2 | Suica |
+-----+-------+
2 rows in set (0.00 sec)
mysql> set names utf8;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
mysql> select idx,name from felica_auth_tbl;
+-----+-----------+
| idx | name |
+-----+-----------+
| 1 | 八達通 | ← 正常に表示
| 2 | Suica |
+-----+-----------+
2 rows in set (0.00 sec)
(2)PerlスクリプトをSJISで記述する場合
#!/usr/bin/perl
use strict;
use CGI;
use DBI;
use Encode;
# MySQL接続用変数
my $strSqlDsn = 'DBI:mysql:database=auth_db;host=localhost;port=3306';
my $strSqlUser = 'authuser';
my $strSqlPassword = 'authpassword';
# MySQL接続
my $dbh = DBI->connect($strSqlDsn, $strSqlUser, $strSqlPassword);
if(!$dbh) { die('DB connection error'); }
# クライアント側文字コードの指定
$dbh->do("set names sjis");
# SQLクエリ文
my $sth = $dbh->prepare("SELECT name FROM felica_auth_tbl WHERE idm_pmm = '01020304'");
# SQLクエリ実行
if(!$sth->execute())
{
$dbh->disconnect();
die('DB Query Error');
}
# 読み出されたデータ数が1であることをチェック
my $nRows = $sth->rows;
if($nRows != 1)
{
$sth->finish();
$dbh->disconnect();
die('DB data count is not 1');
}
# 1個目のデータを取り出す
my $arrayData = $sth->fetchrow_arrayref;
my ($strUserName) = @$arrayData;
# MySQL切断
$sth->finish();
$dbh->disconnect();
print "ユーザ名: " . $strUserName;
(3)PerlスクリプトをUTF-8Nで記述する場合
(2)のプログラムの、MySQL文字コード指定部分のみ変更すればよい。以下、プログラムの変更部分の抜粋
~ 略 ~
# MySQL接続
my $dbh = DBI->connect($strSqlDsn, $strSqlUser, $strSqlPassword);
if(!$dbh) { die('DB connection error'); }
# クライアント側文字コードの指定
$dbh->do("set names utf8");
~ 略 ~
(4)PerlスクリプトをUTF-8Nで記述するが、MySQLのクライアント文字コードをSJISにする場合
この場合は、Encode::from_to関数で文字コードを変換します。
~ 略 ~
# MySQL接続
my $dbh = DBI->connect($strSqlDsn, $strSqlUser, $strSqlPassword);
if(!$dbh) { die('DB connection error'); }
# クライアント側文字コードの指定
$dbh->do("set names sjis");
~ 略 ~
Encode::from_to($strUserName, 'sjis', 'utf8');
print "ユーザ名: " . $strUserName;
(5)PerlスクリプトをUTF-8Nで記述し、use utf8; 宣言を行う場合
外部からやってきた文字列には、たとえそれがUTF-8エンコードされていたとしても、UTF-8フラグを強制的に立ててやる必要がある。
※ 『 use encoding 'utf8'; 』 の場合は、フラグを立てる処理は必要が無い。
#!/usr/bin/perl
use strict;
use CGI;
use DBI;
use Encode;
use utf8;
~ 略 ~
# クライアント側文字コードの指定
$dbh->do("set names utf8");
~ 略 ~
print "ユーザ名: " . Encode::decode('utf8', $strUserName);
(6)その他、UTF-8関連で不具合出そうなもの
スクリプト先頭で 『 use encoding 'utf8'; 』 を行った場合でも、MySQLから返される文字列がSJISの場合は、Encode::from_to関数で変換すれば問題ない。 『 use utf8; 』 を指定した場合は、SJISの文字列は正しく扱われない。
参考リンク