PHP Conference Japan 2024

mysqli::real_escape_string

mysqli_real_escape_string

(PHP 5, PHP 7, PHP 8)

mysqli::real_escape_string -- mysqli_real_escape_string转义字符串中用于 SQL 语句的特殊字符,并考虑连接的当前字符集

描述

面向对象风格

public mysqli::real_escape_string(string $string): string

过程式风格

mysqli_real_escape_string(mysqli $mysql, string $string): string

此函数用于创建可以在 SQL 语句中使用的合法 SQL 字符串。给定的字符串被编码以生成转义的 SQL 字符串,并考虑连接的当前字符集。

注意

安全:默认字符集

必须在服务器级别或使用 API 函数 mysqli_set_charset() 设置字符集,才能使其影响 mysqli_real_escape_string()。有关更多信息,请参阅关于 字符集 的概念部分。

参数

mysql

仅过程式风格:由 mysqli_connect()mysqli_init() 返回的 mysqli 对象

string

要转义的字符串。

编码的字符为 NUL (ASCII 0)\n\r\'"CTRL+Z

返回值

返回一个转义的字符串。

示例

示例 #1 mysqli::real_escape_string() 示例

面向对象风格

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = new mysqli("localhost", "my_user", "my_password", "world");

$city = "'s-Hertogenbosch";

/* 使用转义的 $city 的此查询将有效 */
$query = sprintf("SELECT CountryCode FROM City WHERE name='%s'",
$mysqli->real_escape_string($city));
$result = $mysqli->query($query);
printf("Select returned %d rows.\n", $result->num_rows);

/* 此查询将失败,因为我们没有转义 $city */
$query = sprintf("SELECT CountryCode FROM City WHERE name='%s'", $city);
$result = $mysqli->query($query);

过程式风格

<?php

mysqli_report
(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli = mysqli_connect("localhost", "my_user", "my_password", "world");

$city = "'s-Hertogenbosch";

/* 使用转义的 $city 的此查询将有效 */
$query = sprintf("SELECT CountryCode FROM City WHERE name='%s'",
mysqli_real_escape_string($mysqli, $city));
$result = mysqli_query($mysqli, $query);
printf("Select returned %d rows.\n", mysqli_num_rows($result));

/* 此查询将失败,因为我们没有转义 $city */
$query = sprintf("SELECT CountryCode FROM City WHERE name='%s'", $city);
$result = mysqli_query($mysqli, $query);

以上示例将输出类似以下内容

Select returned 1 rows.

Fatal error: Uncaught mysqli_sql_exception: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's-Hertogenbosch'' at line 1 in...

参见

添加注释

用户贡献的注释 6 条注释

60
dave at mausner.us
13 年前
如果您使用 prepare() 和 bind_param() 作为在 SQL 语句中放置任意字符串值的替代方法,则可以避免所有字符转义问题(在 PHP 端)。这是因为绑定参数值不会通过 SQL 语句语法传递。
52
Josef Toman
14 年前
对于百分号和下划线,我使用以下方法
<?php
$more_escaped
= addcslashes($escaped, '%_');
?>
39
arnoud at procurios dot nl
20 年前
请注意,此函数不会转义 _(下划线)和 %(百分号)符号,它们在 LIKE 子句中具有特殊含义。

据我所知,没有函数可以执行此操作,因此您必须通过在它们前面添加反斜杠来自己转义它们。
22
therselman at gmail dot com
7 年前
提供几个支持 UTF-8/多字节的转义函数。

这些函数可以替代 mysqli::real_escape_string,只要您的数据库连接和多字节扩展使用相同的字符集(UTF-8),它们将通过转义与 mysqli::real_escape_string 相同的字符来产生相同的结果。

这是基于我为我的 SQL 查询构建器类所做的研究。
https://github.com/twister-php/sql

<?php
/**
* 返回一个字符串,在需要转义的字符前添加反斜杠。
* 满足 MySQL 要求,适用于多字节字符集
* 转义的字符为 NUL(ASCII 0)、\n、\r、\、'、" 和 ctrl-Z。
*
* @param string $string 要添加反斜杠的字符串
* @return 添加了 `\` 到保留字符前的 $string
*
* @author Trevor Herselman
*/
if (function_exists('mb_ereg_replace'))
{
function
mb_escape(string $string)
{
return
mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x27\x5C]', '\\\0', $string);
}
} else {
function
mb_escape(string $string)
{
return
preg_replace('~[\x00\x0A\x0D\x1A\x22\x27\x5C]~u', '\\\$0', $string);
}
}

?>

转义的字符是(与 mysqli::real_escape_string 相同)

00 = \0 (NUL)
0A = \n
0D = \r
1A = ctl-Z
22 = "
27 = '
5C = \

注意:preg_replace() 处于 PCRE_UTF8(UTF-8)模式(`u`)。

增强版

当为 `LIKE` 语法转义字符串时,请记住您还需要转义特殊字符 _ 和 %。

因此,这是一个更可靠的版本(即使与 mysqli::real_escape_string 相比也是如此,因为用户输入中的 % 字符会导致意外结果,甚至可以通过 LIKE 语句中的 SQL 注入导致安全违规)。

<?php

/**
* 返回一个字符串,在需要转义的字符前添加反斜杠。
* 满足 MySQL 要求,适用于多字节字符集
* 转义的字符为 NUL(ASCII 0)、\n、\r、\、'、" 和 ctrl-Z。
* 此外,还转义了特殊控制字符 % 和 _,
* 适用于所有语句,但尤其适用于 `LIKE`。
*
* @param string $string 要添加反斜杠的字符串
* @return 添加了 `\` 到保留字符前的 $string
*
* @author Trevor Herselman
*/
if (function_exists('mb_ereg_replace'))
{
function
mb_escape(string $string)
{
return
mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]', '\\\0', $string);
}
} else {
function
mb_escape(string $string)
{
return
preg_replace('~[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]~u', '\\\$0', $string);
}
}

?>

额外转义的字符

25 = %
5F = _

额外函数

原始的 MySQL `utf8` 字符集(用于表和字段)仅支持 3 字节序列。
4 字节字符并不常见,但我遇到过查询因 4 字节 UTF-8 字符而无法执行的情况,因此您应尽可能使用 `utf8mb4`。

但是,如果您仍然想使用 `utf8`,则可以使用以下函数替换所有 4 字节序列。

<?php
// 修改自:https://stackoverflow.com/a/24672780/2726557
function mysql_utf8_sanitizer(string $str)
{
return
preg_replace('/[\x{10000}-\x{10FFFF}]/u', "\xEF\xBF\xBD", $str);
}
?>

选择你想要的,并自行承担风险!
16
匿名用户
9 年前
如果您想知道为什么(除了 \, ' 和 ")NUL(ASCII 0)、\n、\r 和 Control-Z 会被转义:这并非为了防止 SQL 注入,而是为了防止您的 SQL 日志文件变得不可读。
4
ASchmidt at Anamera dot net
3 年前
在转义 % 和 _ 通配符字符时要小心。根据以下网址底部经常被忽视的说明

https://dev.mysqlserver.cn/doc/refman/5.7/en/string-literals.html#character-escape-sequences

转义序列 \% 和 \_ 仅在 LIKE 中才会被解释为 % 和 _。(MySQL 8.0 也是如此)

在常规字符串文字中,转义序列 \% 和 \_ 被视为这两个字符对。因此,如果这些转义序列出现在 WHERE "=" 中而不是 WHERE LIKE 中,则它们将无法匹配单个 % 或 _ 字符!

因此,必须使用两个“转义”函数:用于常规字符串文字的 real-escape-string(或等效函数),以及仅用于打算在 LIKE 中使用的字符串文字的修改后的转义函数。
To Top