[PHP-users 1634] Re: addslashes関数でエンコード

php-users@php.gr.jp php-users@php.gr.jp
Wed, 29 Aug 2001 03:19:52 +0900


たけです。
佐川さん、たびたびご教授ありがとうございます。

まとめてみました。

<内部コードがSJISで、magic_quotes_gpc=offの場合>
データーベースにクエリ文を送る場合、変数に対しaddslashesでエンコードが必要だが、
―⊇そソЫ綾噂化浬棺欺興圭現構砂蚕悉十晶申製曾遜箪捗貼峠能判表塀暴冥予僚禄
の文字に関しては、Shift_JISの2バイト目にエスケープの対象となる文字なので、

$str="本能";
$str=addslashes("$str");
$str="本能\";

となってしまい、
$query="INSERT INTO  test1 (str) VALUES('本能\')";
$result = mysql_query($query);
となってしまって
1064: You have an error in your SQL syntax near ''能\')' at line 1
のエラーとなってしまう。


これを改善する為には、
(1) Shift_JISでソースを書かない
(2) 一時的にEUC-jpやUTF-8などのコードに変換する
(3) 自作のaddslashesを作成する
(3') addslashesしたあとに自作関数で取り除く
の方法があり、

(2)の場合(私は結果的にこちらを選びました。)

function addslashes_sjis($sjis) {
	$euc=mb_convert_encoding($sjis,EUC,SJIS);
	$euc=addslashes($euc);
	$sjis=mb_convert_encoding($euc,SJIS,EUC);
	return $sjis;
}

(3') の場合(佐川さんの作られた関数)
function addslashes_ext3($sjis) {
  /*
   * 機能: 区切り文字(\xff)を入れて、ASCIIのみをaddslashesする。
   * 警告: 区切り文字が$sjisに含まれていた場合の動作は保証外。
   * 注意: ereg_replaceは\x00をサポートしていないことがあるので、
   *       \xffを使う。preg_replaceは、\x00をサポートしている。
   */

  // 文字コードの範囲
  $sjis_high = "[\x81-\x9f\xe0-\xfc]";
  $sjis_low  = "[\x40-\x7e\x80-\xfc]";
  $ank       = "[\x01-\x7f\xa0-\xdf]";

  // とりあえず、addslashesしちゃう
  $escaped = addslashes($sjis);

  // 問題が発生する文字列があるか調べる
  if (ereg("($sjis_high\\\\)\\\\", $escaped)) {
    // 問題がありそう。一文字ずつに分解する。
    $raw_char =
    $esc_char = explode("\xff",
                        ereg_replace("(${sjis_high}${sjis_low}|$ank)",
                                     "\\1\xff", $sjis));
    // 一文字ずつしらべる
    for($i=0; $i<count($raw_char); $i++)
      if (strlen($raw_char[$i]) == 1)
        $esc_char[$i] = addslashes($raw_char[$i]); // ASCIIのときはaddslashes
    // くっつける
    $escaped = implode("", $esc_char);
  }
  return $escaped;
}

PHPの言語解析器では、理解できないエスケープ記号は、そのまま出力するので
$str=addslashes_sjis("東十条");
//$str="東十条";
$query="INSERT INTO test.test1 (str) VALUES('$str')";
でもかまわないが、


一方 他の言語(例えばPerl)の言語解析器では、
英数字の前についた\は、特殊な意味を持ち、
記号の前の \ はその文字をエスケープしている...と解釈され
$str="東十\条";
$query="INSERT INTO test.test1 (str) VALUES('$str')";
でないと正しくINSERTされない。


間違いがあればご指摘下さい。


J-SKY研究所
http://www.j-ken.ne.jp
j-ken/take <take@j-ken.com>