UTF-8のCSVファイルを文字化けなくエクセルで開く

エクセルの仕様なのか、何も考えずにUTF-8のファイルエクセルで開くと、標準文字コードで開くため、だいたいの確率で文字化けします。

ちなみにShift JISであれば、問題なく開けます。

対策としては、適当なテキストエディタなどで開いて、UTF-8(BOM付き)で一度保存すれば、次からはエクセルでも文字化けせず問題なく開くことが出来ます。

このことから、コンテンツの最初にBOMをつけてやれば、ダウンロード後すぐにエクセルで文字化けなく開くことが出来ます。

動的出力するCSVファイルであれば、対策は簡単です。以下はPerlでの例です。

たったこれだけです。

なお、他サイトなどで、BOMは”0xFE 0xFF”などと紹介しているところがありますが、”0xFE 0xFF”はUTF-16のBEエイディアンのBOMであり、UTF-8のBOMは”0xEF 0xBB 0xBF”ですのでご注意ください。

テキストエディタだと”0xFE 0xFF”をつけてもちゃんと解釈してくれることがありますが、エクセルの場合は”0xEF 0xBB 0xBF”を付けないとダメ見たいです。

参考サイト)

 

MySQLで最後にINSERTしたAutoIncrementのidを取得する

生のSQLで取得する場合は、

で取得できます。

DBIを使用している場合は、以下のようにステートメントハンドルから取得できます。

 

参考URL)

 

WHERE句のINでプレースホルダを使う際の注意点

DBIモジュールでは、プレースホルダを使う場合、基本的な記述は下記のようになる。

んで、SQL分にWHERE句を含んでいる場合で、条件をINで複数指定している場合、

でいけると思いきや、値の最初の要素(カンマで区切った一番最初の値=「あ」)のみプレースホルダに代入されて処理されてしまう。つまり、

と同じ結果となってしまう。

どうやらカンマで連結した文字列を渡しても、配列要素とみなされるようだ。

なので、条件の数分だけ、プレースホルダを作り指定してやる必要がある。

単純に書くと、

てな感じ。

現実的にはINの条件数は動的になると思うので、うちでは下記のような感じで処理している。

・DB処理用ファイル(database.pl)

・呼び出し元

PHPでもフレームワークによってここの処理が違ったりするので注意が必要。

 

濁点(゛)と半濁点(゜)を含む日本語のメール文字化け対応

JIS(≒ISO-2022-JP)で定義されていない文字コードは、UTF8から変換しても、もちろん正常に表示されません。

しかし日本語のUTF8には、実は、濁点と半濁点をふくむ文字に2パターンの表示方法があります。

たとえば「が」というひらがなですが、普通は、

xE3x81x8C

となります。

しかし、UTF8の決まりでは、

xE3x81x8B + xE3x82x99 (「か」+「 ○゛」)

でもOKなのです。

 

うちでは日本語文字コードの変換にUnicode::Japaneseを使ってます。非常に多くの変換パターンが実現できるので便利なのですが、上記の後者の場合(「か」+「 ○゛」の場合)に、UTF8→JISなどの変換に失敗します。

失敗というか、厳密にはxE3x82x99( ○゛)とxE3x82x9A( ○゜)が未定義状態のようで、「が」は「が」のように変換されてしまいます。

エンコーダを変えればいいのかもしれませんが、やはりバグが怖いので、下記のようにJISへの変換前にコードを統一することで対応してます。

 

ご自由にコピペどうぞ。

 

 

参考サイト)

http://d.hatena.ne.jp/kamosawa/20151015

http://www.seiai.ed.jp/sys/text/java/utf8table.html

http://webmastertool.jp/other/utf.html

http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/u3040.html

MySQLのクエリログの出力方法

/etc/my.cnfを開く。

[mysqld]ディレクティブにログの種類と出力場所を指定。

代表的なものは下記。

(エラーログ)※これはたぶん最初から書いてある
log_error=”/var/log/mysqld.log”
log_warnings=1

(一般クエリログ)
log=”/var/log/sql.log”

(バイナリログ)
log_bin=”/var/log/mysqlbin.log”
log_bin_index=”/var/log/mysqlbin.list”
max_binlog_size=1M
expire_logs_days=1

(スロークエリログ)
slow_query_log=1
slow_query_log_file=”/var/log/slowquery.log”
log_queries_not_using_indexes
log_slow_admin_statements

設定を書いて保存したら、出力ファイルを作成し、所有者をmysqlに変更しておく。

(一般クエリログの場合)
# touch /var/log/sql.log
# chown mysql:mysql /var/log/sql.log

最後にmysqldを再起動。
# service mysqld restart

一般クエリログの出力例
——————————-
  :
18 Connect ****@localhost on dbname
18 Query set autocommit=1
18 Query SET NAMES utf8
18 Query SELECT * FROM tbl1
18 Query SELECT * FROM tbl2
WHERE id = ‘*****’
18 Query UPDATE tbl2
SET clm1 = UNIX_TIMESTAMP()
WHERE id = ‘*****’
18 Query SELECT * FROM tbl3 WHERE id=’****’
17 Quit
  :
——————————-

ちなみにSQLインジェクション攻撃を受けている場合のログの例
——————————-
  :
1019 Connect ****@localhost on dbname
1019 Query set autocommit=1
1019 Query SET NAMES utf8
1019 Query SELECT * FROM tbl1 WHERE id=’-2353′ OR ORD(MID((SELECT IFNULL(CAST(clm1 AS CHAR),0x20) FROM tbl2 LIMIT 1328,1),12,1))>112#’ AND clm2=’abcdefg’
1019 Query SELECT * FROM tbl3
1019 Quit
  :
——————————-

ちなみに、
# tail -f /var/log/sql.log
とすれば発行クエリがリアルタイムでチェック可能。

DBI使って開発段階で生のSQLをチェックしたい時かあると思いますが、DBIx::QueryLogとか使うよりこっちのほうがアナログで簡単そう。