PHP 字符串转义、转码与特殊字符处理实战指南
在处理用户输入和数据库交互时,正确的字符串转义与编码是防止 SQL 注入和 XSS 攻击的关键。本文梳理了 PHP 中常用的转义函数(如 addslashes、htmlspecialchars)及其历史配置项,提供数组递归转义的代码实现,并详细解析 \n、\0 等特殊字符的处理逻辑。
核心转义函数对比与应用
PHP 提供了多种针对不同场景的转义机制。理解它们的区别能避免常见安全漏洞。
第一步:识别环境与基础转义
目的:了解全局配置对转义的影响,掌握基础的字符过滤函数。
- magic_quotes_gpc:此配置曾自动为 GET、POST、COOKIE 数据添加反斜杠。但在 PHP 5.3.0+ 版本中已废弃,PHP 7 已完全移除。因此,现代开发不应依赖它,而应手动处理。
- addslashes():在预定义字符前添加反斜杠。预定义字符包括单引号 (
')、双引号 (")、反斜线 (\\) 与 NUL 字符。注意:它并非通用的 SQL 转义函数,因为它不区分数据库字符集。 - stripslashes():删除由
addslashes()添加的反斜杠。
复制代码
// 如果 magic_quotes_gpc 未开启,手动进行递归转义
if(!get_magic_quotes_gpc()) {
$_GET = daddslashes($_GET);
$_POST = daddslashes($_POST);
$_COOKIE = daddslashes($_COOKIE);
}
function daddslashes($string, $force = 1) {
if(is_array($string)) {
foreach($string as $key => $val) {
unset($string[$key]);
$string[addslashes($key)] = daddslashes($val, $force);
}
} else {
$string = addslashes($string);
}
return $string;
}
第二步:针对 SQL 查询的转义
目的:安全地将数据插入数据库。
- mysql_escape_string():转义 SQL 语句中的特殊字符,包括 \x00、\n、\r、\\、'、"、\x1a。
注意:mysql_*系列函数已在 PHP 5.5 中被废弃,并在 PHP 7.0 中移除。强烈建议迁移至mysqli_real_escape_string()或更推荐的 PDO 预处理语句(Prepared Statements)。 - addcslashes():C 语言风格的转义。当对字符 0, a, b, f, n, r, t, v 转义时,会转换为 \0, \a 等格式。主要用于控制字符的特定表示。
第三步:防止 XSS 的 HTML 实体编码
目的:在输出到浏览器前,将可能被视为 HTML 标签的字符转为实体。
- htmlspecialchars():将预定义的 HTML 特殊字符转换为实体:
& → &
" → "
' → ' (若 flags 包含 ENT_QUOTES)
< → <
> → > - htmlentities():转换所有 HTML 实体,不仅是预定义的几个。
- 逆向操作:
htmlspecialchars_decode()和html_entity_decode()用于将实体还原为原始字符。
PHP 字符串中的特殊字符与转义序列
除了内置函数,理解 PHP 字符串字面量本身支持的转义序列对于调试和处理二进制数据至关重要。
第四步:单引号与双引号字符串的差异
- 单引号 (''):
支持\'和\\。
其他转义序列如\n会被原样输出,不会解释为换行符。 - 双引号 ("):
支持更多转义序列:
-\n: 换行 (LF)
-\r: 回车 (CR)
-\t: 水平制表符
-\\: 反斜线
-\$: 美元符号
-\": 双引号
-\[0-7]{1,3}: 八进制 ASCII 码
-\x[0-9A-Fa-f]{1,2}: 十六进制 ASCII 码
第五步:特殊字符的检测与替换实战
目的:处理包含空字节或其他控制字符的脏数据。
1. \0 (NUL 字符) 处理
复制代码
$str = "ffff\0ffff";
echo strlen($str); // 输出: 9 (包含 \0)
echo "\n";
// 替换 \0 为空字符串
$str = str_replace("\x0", "", $str);
// 或者使用 octal: str_replace("\0", "", $str);
// 或者使用 chr: str_replace(chr(0), "", $str);
echo strlen($str); // 输出: 8
2. 八进制 ASCII 码序列
在双引号字符串中,符合 [0-7]{1,3} 模式的序列会被解析为对应的 ASCII 字符。不符合范围的数字(如 \8)会被保留原样(即 \ 和 8)。
复制代码
$str = "\0\01\02\3\7\10\011\08\8";
// \8 未被识别为八进制,变为 \\8 (ASCII 92 和 56)
// 最终长度: 11
3. 十六进制 ASCII 码序列
\x 后跟 1-2 位十六进制数会被解析。
复制代码
$str = "\x0\x1\x2\x3\x7\x8\x9\x10\x11\xff";
// 输出各字符的 ord 值分别为: 0, 1, 2, 3, 7, 8, 9, 16, 17, 255
总结与最佳实践
- 弃用旧配置:不再使用
set_magic_quotes_runtime(),应在代码初始化或服务器配置中确保其为关闭状态。 - SQL 安全:放弃
mysql_escape_string,优先使用 PDO 预处理语句。若必须使用原生函数,请使用mysqli_real_escape_string()。 - XSS 防护:在输出 HTML 之前,务必使用
htmlspecialchars($str, ENT_QUOTES | ENT_HTML5, 'UTF-8')进行编码。 - 递归处理:对于数组形式的输入(如 POST 数据),需编写递归函数对键值和值同时进行转义。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













