けんとのブログ

ぼやき&開発メモ

MySQLの文字コードutf8の扱いについて

2009年01月29日 13時36分55秒 | MySQL
MySQLの文字コード設定全てutf8の状態では、
windowsでMySQLコマンドラインから日本語データの格納はできない。→エラーが出る。

ただし、CSEから、CSEの文字コード設定をcp932にしておくと格納できる。→CSEで日本語データとして表示もできる。
この格納したデータをMySQLコマンドラインで表示すると文字化けした状態で表示される。

MySQLコマンドラインから格納、MySQLコマンドラインで表示するには、
クライアントの文字コードと、結果の文字コードをsjisに設定する。

SET character_set_client = sjis;
SET character_set_results = sjis;

これで、OK。
sjisで渡された日本語を内部的にはutf8で格納し、表示させる際にはsjisとして表示するので、
格納も、表示も日本語が正常に扱えるようになる。

※前述の「MySQLインストール」でも文字コードについて語っています。

MySQL格納データの暗号化

2009年01月28日 16時09分17秒 | MySQL
CREATE DATABASE test

--バイナリデータ用のBOLB型でテーブル作成。MySQLリファレンス推奨型。
CREATE TABLE login_tb (no BOLB,id BLOB,pass BLOB);
--※BOLB型だとデータ取り出し時に文字化けしたのでVARCHARAに変更。
--16進数文字列が入るのでサイズ大きめで。
CREATE TABLE login_tb (no VARCHARA(500),id VARCHARA(500),pass VARCHARA(500));

--AES_ENCRYPT('暗号化前のデータ', '暗号を解くキー')で、暗号化前のデータが暗号化(バイナリデータ化)されて格納される。
--しかし!このままでは文字化けした状態で表示される。
INSERT INTO login_tb(no,id,pass) VALUES(1, AES_ENCRYPT('aaa', 'id_key'), AES_ENCRYPT('111', 'pass_key'));

--そこで暗号化された物を、HEX()関数で16進数に変換する。これで16進数アルファベット文字として表示される。
INSERT INTO login_tb(no,id,pass) VALUES(1, HEX(AES_ENCRYPT('aa', 'key')), HEX(AES_ENCRYPT('11', 'key')));
INSERT INTO login_tb(no,id,pass) VALUES(2, HEX(AES_ENCRYPT('bb', 'key')), HEX(AES_ENCRYPT('22', 'key')));
INSERT INTO login_tb(no,id,pass) VALUES(2, HEX(AES_ENCRYPT('cc', 'key')), HEX(AES_ENCRYPT('33', 'key')));
INSERT INTO login_tb(no,id,pass) VALUES(4, HEX(AES_ENCRYPT('bb', 'key')), HEX(AES_ENCRYPT('44', 'key')));
追加していく・・・

--注意点。キーをバラバラに設定するとややこしくなる。キーは全部同じものでいい。(必要であれば管理できる範囲で設定)
INSERT INTO login_tb(no,id,pass) VALUES(2, HEX(AES_ENCRYPT('aa', 'id_key')), HEX(AES_ENCRYPT('11', 'pass_key')));

--暗号化とは関係ない。普通の条件指定select文。
SELECT * FROM login_tb WHERE no=1;

--16進数の文字列でselect。結果。(id='EF85045714A54BAEEECC87285BE529BA'のカラム&レコード。)
SELECT * FROM login_tb WHERE id='EF85045714A54BAEEECC87285BE529BA';

--暗号化前の元の文字列でselect。結果。(id='EF85045714A54BAEEECC87285BE529BA'のカラム&レコード。)結果は上記と同じ
SELECT * FROM login_tb WHERE id= HEX(AES_ENCRYPT('bb', 'key'));

--16進数文字列でselect。元の文字列で表示。結果(bb)
SELECT AES_DECRYPT(UNHEX('EF85045714A54BAEEECC87285BE529BA'), 'key') AS new_column;

--idカラムを暗号化前の文字列で表示。
SELECT AES_DECRYPT(UNHEX(id), 'key') AS new_column FROM login_tb;

--idカラムとpassカラムを暗号化前の文字列で表示。
SELECT AES_DECRYPT(UNHEX(id), 'key'), AES_DECRYPT(UNHEX(pass), 'key') FROM login_tb ;

--暗号化前の元の文字列でselectし、元の文字列で表示。結果(aa)
SELECT AES_DECRYPT(UNHEX(id), 'key') AS new_tb FROM login_tb WHERE id= HEX(AES_ENCRYPT('aa', 'key'));


---暗号化とは関係ない・・・---
--カラム型変換
--ALTER TABLE テーブル名 MODIFY カラム名 新しいデータ型;
ALTER TABLE member ALTER COLUMN name BOLB;
ALTER TABLE member MODIFY name BLOB;
ALTER TABLE users MODIFY password VARCHAR(500);
--テーブル内データ削除
DELETE FROM member;
---ここまで関係ない----


--上記方法でもよいが、ストアドファンクションを使わないと、取り出す際、日本語が文字化けする。
--また、ソースに暗号化のキーがもろに登場するので、セキュリティ上よくない。

--functionをいじると、そのfunctionを使ったプログラム全てに影響が出るため、root権限者しかいじれない(作れない)様になっている。
--下記処理は全てのユーザがfunctionをいじれる様にする為の処理。
--こいつもrootで接続して実行しないと、rootでないと設定権限がないよー!とエラー!!
--また、この設定をしないとcreate functionで権限がないよー!とエラー。
MySQLコマンド
SET GLOBAL log_bin_trust_function_creators = 1;
を実行し、functionを作成。
functionを作ったら元に戻す。

SET GLOBAL log_bin_trust_function_creators = 0;

--上記処理に関して
MySQL5.0.16から導入されました。
この値はバイナリログが有効のときに適用されます。
Stored Function(以下関数)を作成できるユーザが、
信用できない関数を作成する可能性があるかどうかを制御します。
関数の内容によっては、
危険な状況を引き起こすようなバイナリログへの書き込みがなされる事があります。

この値を0(デフォルト)にすると、
SUPER および CREATE ROUTINE(ALTER ROUTINE) 権限を持たないユーザは
関数を作成(更新)することを許可されません。
0にすることはまた、関数を
DETERMINISTIC / READS SQL DATA / NO SQL のいずれかの特性を持った
形で作らなければならないという事を意味します。
この値を1にすると、そのような制限は課せられません。


--簡単なストアドファンクションの例。hello()という関数をつくる。concat()は元々MySQLに登録されている文字連結関数。
CREATE FUNCTION hello(input VARCHAR(200)) RETURNS VARCHAR(100) RETURN concat('Hello, ', input, '!');
--hello()に引数'ttttttttttt'を渡して実行。(表示)
SELECT hello('tttttttttttt');
--結果(Hello,ttttttttttt!)

--同じ名前のファンクションは作れないので間違ったときは一旦削除。
DROP FUNCTION hello ;
DROP FUNCTION decodes ;

--同様に暗号化の為のdecodes関数を作成。格納できる文字数は必要に応じて設定。
CREATE FUNCTION decodes(input VARCHAR(500)) RETURNS VARCHAR(64) RETURN AES_DECRYPT(UNHEX(input) ,'key');

SELECT decodes(引数);


MySQLインストール

2008年11月30日 14時31分58秒 | MySQL
日本語ページの本家「http://www-jp.mysql.com/」からダウンロード
※前はユーザ登録はなかったが、現在はユーザ登録しないとダウンロードさせてくれない。
※ユーザ登録の項目に「ZIP/Postal Code」というのがある。
これは国際的な郵便番号らしい。
日本は「81」、東京は「3」、大阪は「6」、名古屋は「52」、福岡は「92」らしい。
とりあえず「81」とだけ入力したらokだった。
参考HP「http://www.embassyworld.com/data/Zip_Codes.html」

mysql-5.0.67を使用

インストール設定
参考HP「http://www.aiosl-tec.co.jp/java-start/chap11.html」
デフォルト文字コードは「utf8」、passwordは「root」で設定。ユーザ名は自動で「root」になる。
※root権限のユーザが作成される。
※セキュリティ上、新しくユーザを作った方がいい。

MySQLをインストールすると、自動的にrootという特殊なユーザが作成されます。
rootは、UNIX系OSなどで管理ユーザのアカウント名として使われていますが、
MySQLのユーザアカウントはOSのユーザアカウントとは別のものです。
ただし、MySQLへのログイン時にユーザ名が指定されていないときは、
現在のログインしているユーザ名をMySQLのユーザー名としてログインを試みてくれます。

ログインパスワードを設定する場合
参考HP「http://www.rfs.jp/server/mysql/02/01.html」

JDBCドライバ
JAVAからMySQLに接続するにはJDBCドライバが必要。
参考HP「http://www.hellohiro.com/jdbcmysql.htm」
本家「http://dev.mysql.com/downloads/connector/」からDL。とくにインストールはない。
mysql-connector-java-5.1.7使用。
解凍したフォルダを任意のフォルダに置いておく。
eclipseでDBに接続する際、プロジェクトに任意のフォルダを作成(「jarとか」)し、
JDBCフォルダ内のmysql-connector-java-5.1.6-bin.jarをコピペし、ビルドパスに追加する。
これでOK。

インストール時文字コードは「utf8」で設定したが、
日本語をINSERTできない問題が発生した。
以前linuxにutf8でINSERTした際は日本語も問題なかったが、今回自宅windowsではどうしてもうまくいかない。
色々試したことを書いておく。

文字コードを調べるコマンド「status;」
もっと細かな表示は「show variables like '%char%';」

インストール段階で全てutf8になっていた。
でdbもテーブルもutf8の状態で作って、日本語をINSERTすると、
「ERROR 1366 (HY000): Incorrect string value: 'x83x89x830.....」
こんな感じのエラーがでる。
日本語のとこが文字化けして、おかしな値だよってな感じ。
「SET character_set_client = sjis;」コマンドで、入力文字コードをsjisにすると、
日本語もINSERTできる。
しかし、SELECT表示すると文字化けした状態で表示される。
「SET character_set_results = sjis;」コマンドで、結果文字コードをsjisにすると、
SELECT表示も正常に表示される。
しかし、CSEの文字コードをutf8に設定して表示してみると文字化け(表示されないだっけな・・)

あとDB全てutf8状態で、日本語をサクラエディタでutf8に変換し(文字化けした状態)てINSERTはできるが、
SELECT表示も文字化けする。
同じような感じで、サクラutf8状態で日本語INSERT文を書いて、DBにコピペしても、同じエラーとなる。
この文のファイルをCSEでファイル一括実行すると、出来るが、SELECT表示はやっぱり文字化けする。

こんな感じで断念・・・
windowsだとクライアント入力文字コードがutf8でも、日本語はsjisと判断され、INSERT時にsjis→utf8の変換が
行われ、INSERT文の日本語が化けしまうのかな・・・

参考「http://pugiemonn.blog6.fc2.com/?tag=1366」
「http://blog.goo.ne.jp/nokonoko2006/e/7aa4126c0693fe8840e68176dffb6849」
ここのHPではクライアント入力文字モードのみsjisとして日本語入力している。
取り出し時はcharacter_set_resultsの文字コードに変換されるとある。
SELECT表示が文字化け状態なのを気にしなければ、これで格納、utf8で取り出し、
ブラウザをutf8設定にすることで文字化けから正常に変換されて、ちゃんと表示されるかも
「http://www.takeash.net/wiki/?MySQL」←このHPには
「注意) MySQL 5.0.37 / ODBC Driver 3.51.12 / Windows の構成では文字化けする。」とある。
「http://okilab.jp/blog/2008/04/mysqlutf8.html」ここのも良さそうだが良く分からず出来なかった。
「http://wota.jp/ac/?date=20061011」ここも文字コード設定について分かりやすい。

あとmy.cnf(my.ini)ファイルでの文字モコード設定はいろいろ書いてあるが、まとめておく。
MySQL5系ではmy.iniしかない。これを編集する。

[client]
port=3306
default-character-set = sjis

[mysql]
default-character-set = sjis

[mysqld]
default-character-set = sjis
skip-character-set-client-handshake

上記は全部sjis状態。全部utf8にすると、character_set_system以外utf8になる。

[文字コード設定の意味]
character_set_client †
クライアントの使用する文字セットです。サーバへのSQL文はこの文字セットで送信します。

character_set_connection †
サーバーはクライアントからのSQL文をcharacter_set_clientからcharacter_set_connectionに変換します。

character_set_database †
デフォルトデータベースの文字セットです。USE文などでデフォルトデータベースを変更するとこの変数の値も変わります。
データベースの文字セットについては以下を参照して下さい。

character_set_results †
サーバからクライアントに返される検索結果などに使用される文字セットです。

character_set_server †
サーバの文字セットです。上のcharacter_set_databaseで説明したように、
この文字セットは、データベース作成時の暗黙の文字セットとして使用されます。
この変数はサーバ起動時のオプションとして初期設定できます。
本編では、サーバオプションファイル(my.ini)の[mysqld]セクションで、

default-character-set=utf8

として設定しています。

character_set_system †
システムの使用する文字セットで常にutf8が使用されています

ということで、character_set_systemは常にutf8らしい、「SET character_set_system = sjis;」はエラーになるし、
「set names sjis;」でもcharacter_set_systemはutf8のまま。このままでいっか。
[mysqld]はちょい下になるし、[mysqld]とdefault-character-set = sjisの間には
コメントアウトの文字が数行あるから見落とさないように。

今回自宅開発ではとりあえず全てsjisでいく。

MySQLコマンドプロンプトで直接日本語を入力するときは「Alt+半角/全角」でできる。

MySQLはPC起動時にバックグラウンドで起動している為、設定ファイルを変更したときは、
PCを再起動させるか、コンパネ→管理ツール→サービス→MySQLで停止→開始をしないと設定が反映されないので注意する。