アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

「Navicat For MySQL」で起こる文字化け回避

こんにちは、牧野です。
今日も前回に続いてMySQLの話題で、「Navicat For MySQL」についてです。
使ったことのある方、今使っているという方もいるかもしれませんが、このソフトはMySQLGUIで管理できるアプリケーションです。
データ検索、更新はもちろん、データベースのバックアップ、リストア、ExcelAccessデータベースといった各種ファイル形式へのエクスポート、インポート等が行え、誰でも簡単にデータベース操作が行えるというソフトです。有料ソフトですが試用期間が1ヶ月あって、その間は全ての機能を無料で使うことができます。

このソフト、なかなか便利なのですが、欠点もあります。
その1つが、UTF-8変換時に発生する文字化けです。
データベースの文字コードがujis、sjisだったり、データベースがutf8でもデータを表示する時にujisやsjisにしてデータを取得している場合、Navicatで特定の文字を登録するとその文字が化けてしまうのです。Navicatで見ている分には正しくデータ更新されたように見えても、そのデータをWEBページから見てみると化けていたりします。
中でも特に使用頻度が高く、化けて困るのが「~」です。
これは簡単に説明すると、UTF-8で本来「~」という波線記号が割り当てられるべきコードに、逆の波線記号「」が割り当てられてしまい、Shift_JIS等でこのUTF-8のコードに対応する文字を全角チルダにしたのがそもそもの発端です。
Navicatに限った問題ではないのですが、このままでは使いどころが限られてしまいます。

このバグを自力で回避する方法には、文字コードを全部UTF-8に統一する等データベース関連の文字コードにujis、sjisを使わないようにすればよいのですが、それが大変な時に使えるもう1つの方法が、HTTPトンネル機能です。
HTTPトンネルを設定すると、データベースとのデータやりとりの際に、ウェブサーバに設置したデータベースアクセス用のPHPプログラムを介して行うことができます。
Navicatのプログラムフォルダ内にあるntunnel_mysql.phpがHTTPトンネル用のプログラムなのですが、これをちょっと変更してウェブサーバに設置します。
NavicatではデータをUTF-8でやり取りしており、「~」を入力すると、データベースには波が逆になった「」が入ります。なので、データベースに送られるデータに「」があったら「~」に変換します。逆に、データベースのデータをNavicatに渡す際には「~」を「」に変換します。

以下、ntunnel_mysql.phpの抜粋です。



…
} elseif($_POST["actn"] == "Q") {
  for($i=0;$i<count($_POST["q"]);$i++) {
    $query = $_POST["q"][$i];
    if($query == "") continue;
    if(get_magic_quotes_gpc())
      $query = stripslashes($query);

    $res = mysql_query($query, $conn); 
    $errno = mysql_errno();
    $affectedrows = mysql_affected_rows($conn);
    $insertid = mysql_insert_id($conn);
    $numfields = mysql_num_fields($res);
    $numrows = mysql_num_rows($res);
    EchoResultSetHeader($errno, $affectedrows, $insertid, $numfields, $numrows);
    if($errno > 0)
      echo GetBlock(mysql_error());
    else {  
      if($numfields > 0) {
        EchoFieldsHeader($res, $numfields);
        EchoData($res, $numfields, $numrows);
      } else {
        if(phpversion_int() >= 40300)
          echo GetBlock(mysql_info($conn));
        else    
          echo GetBlock("");
      }
    }
    if($i<(count($_POST["q"])-1))
      echo "\x01"; 
    else    
      echo "\x00"; 
    mysql_free_result($res);
  }
}


上記プログラムの9行目(実際のプログラムでは190行目あたり)にあるmysql_query関数の引数$queryをいじって、


$res = mysql_query(str_replace('(~の逆の文字)', '~', $contn);

とします。(プログラム内の~の逆の文字の部分には、実際には文字の「」が入ります。)
これでデータベースに送られるデータはOKです。
続いて、表示用のデータを取得するのがEchoData関数なので、この部分も修正します。


function EchoData($res, $numfields, $numrows)
{   
  for( $i = 0; $i < $numrows; $i++ ) { 
    $str = "";
    $row = mysql_fetch_row( $res );
    for( $j = 0; $j < $numfields; $j++ ){
      if( is_null($row[$j]) ) { 
        $str .= "\xFF";
      } else {
        //次の1行を追加
        $row[$j] = str_replace('~', '(~の逆の文字)', $row[$j]);
        $str .= GetBlock($row[$j]);
      }
    }
    echo $str;
  }
}


このように修正してウェブサーバに設置し、Navicatの接続設定で「HTTP」タブの「HTTPトンネルを使用する」とトンネルのURLを設定すれば完成です。
上のプログラムでは、「~」の変換しか行っていませんが、他の文字についても同じような変換で回避できるはずです。
最後に注意ですが、HTTPトンネル用プログラムの設置場所にはくれぐれも気をつけましょう。

…と、Navicatのバグ回避について書いてきましたが、このソフト、どれくらい使われているのかな。。。