人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHPのmysqli_real_escape_string()は、エスケープ時にMySQLに接続する必要があるため、この処理を自前で実装し接続不要で同等の処理を行いたいのですが、どのような処理になりますでしょうか?

mysqli_real_escape_string:
http://jp2.php.net/manual/ja/mysqli.real-escape-string.php

上記マニュアルによると、

- NUL (ASCII 0), \n, \r, \, ', ", および Control-Zの文字をエスケープ

- 接続先MySQLの文字セットの考慮(?) ※具体的に思いつかない

の2つの処理で済みそうですが、それ以外に必要な処理があれば教えてください。

ちなみに自前で実装する場合、MySQLの文字セットとエスケープ対象の文字列はどちらもutf8mb4で固定になります。

具体的なソースがあると分かりやすくて有り難いです。
宜しくお願いします。

●質問者: wankodon
●カテゴリ:コンピュータ ウェブ制作
○ 状態 :終了
└ 回答数 : 1/1件

▽最新の回答へ

1 ● a-kuma3
●100ポイント ベストアンサー

本物を見るのが一番早いと思います。

PHP の Mysqli は、Mysql の関数を呼び出しているだけです。
MySQL-5.6.14 から実装を抜き出しました。

mysql_real_escape_string() の実装は libmysql/libmysql.c にあります。

/*
 Add escape characters to a string (blob?) to make it suitable for a insert
 to should at least have place for length*2+1 chars
 Returns the length of the to string
 */

ulong STDCALL
mysql_escape_string(char *to,const char *from,ulong length)
{
 return (uint) escape_string_for_mysql(default_charset_info, to, 0, from, length);
}

ulong STDCALL
mysql_real_escape_string(MYSQL *mysql, char *to,const char *from,
 ulong length)
{
 if (mysql->server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES)
 return (uint) escape_quotes_for_mysql(mysql->charset, to, 0, from, length);
 return (uint) escape_string_for_mysql(mysql->charset, to, 0, from, length);
}

実装は、この二つの関数になっています。

後者は、クォーテーションのエスケープだけを行います。


escape_string_for_mysql() の実装は mysys/charset.c にあります。

size_t escape_string_for_mysql(const CHARSET_INFO *charset_info,
 char *to, size_t to_length,
 const char *from, size_t length)
{
 const char *to_start= to;
 const char *end, *to_end=to_start + (to_length ? to_length-1 : 2*length);
 my_bool overflow= FALSE;
#ifdef USE_MB
 my_bool use_mb_flag= use_mb(charset_info);
#endif
 for (end= from + length; from < end; from++)
 {
 char escape= 0;
#ifdef USE_MB
 int tmp_length;
 if (use_mb_flag && (tmp_length= my_ismbchar(charset_info, from, end)))
 {
 if (to + tmp_length > to_end)
 {
 overflow= TRUE;
 break;
 }
 while (tmp_length--)
 *to++= *from++;
 from--;
 continue;
 }
 /*
 If the next character appears to begin a multi-byte character, we
 escape that first byte of that apparent multi-byte character. (The
 character just looks like a multi-byte character -- if it were actually
 a multi-byte character, it would have been passed through in the test
 above.)

 Without this check, we can create a problem by converting an invalid
 multi-byte character into a valid one. For example, 0xbf27 is not
 a valid GBK character, but 0xbf5c is. (0x27 = ', 0x5c = \)
 */
 if (use_mb_flag && (tmp_length= my_mbcharlen(charset_info, *from)) > 1)
 escape= *from;
 else
#endif
 switch (*from) {
 case 0: /* Must be escaped for 'mysql' */
 escape= '0';
 break;
 case '\n': /* Must be escaped for logs */
 escape= 'n';
 break;
 case '\r':
 escape= 'r';
 break;
 case '\\':
 escape= '\\';
 break;
 case '\'':
 escape= '\'';
 break;
 case '"': /* Better safe than sorry */
 escape= '"';
 break;
 case '\032': /* This gives problems on Win32 */
 escape= 'Z';
 break;
 }
 if (escape)
 {
 if (to + 2 > to_end)
 {
 overflow= TRUE;
 break;
 }
 *to++= '\\';
 *to++= escape;
 }
 else
 {
 if (to + 1 > to_end)
 {
 overflow= TRUE;
 break;
 }
 *to++= *from;
 }
 }
 *to= 0;
 return overflow ? (size_t) -1 : (size_t) (to - to_start);
}

ざっと見た感じ、マニュアルに書いた以上のことはやってません(当たり前か)。

escape_quotes_for_mysql() の実装も mysys/charset.c にあります。
省略しますが、escape_string_for_mysql() から、シングルクォートのエスケープだけを抜き出したような実装になってます。


wankodonさんのコメント
遅れましたが回答有り難うございます。 ソースを見る発想は全くありませんでした。 非常に参考になります!ありがとうございます!
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ