必须同时满足mysqli扩展启用、连接字符集正确设置、参数类型绑定无误,三者缺一不可,否则预处理会静默失败或宽字节注入复活。

直接上结论:不能只改SQL写法,必须先确认mysqli扩展已启用、连接字符集已正确设置、参数类型绑定无误——三者缺一不可,否则预处理会静默失败或宽字节注入复活。
检查mysqli扩展是否真可用,别信phpinfo()单点结果
旧项目常卡在“以为启用了mysqli,其实没启”这一步。mysql_*函数废弃后,mysqli_*不是自动替代品,它得手动开。
-
extension_loaded('mysqli')返回true仅表示扩展加载成功,不等于能用 - CLI 和 Web 环境的
php.ini完全独立:php -m | grep mysqli和网页中phpinfo()必须都验证 - 常见错误名是
mysql或mysqlnd—— 正确扩展名只有<code>mysqli</code>,拼错就白查 - 若返回
false,别急着写代码,先去php.ini解开<code>extension=mysqli</code>(Windows 下是php_mysqli.dll,Linux 下是mysqli.so)
mysqli_connect()之后必须立刻调用mysqli_set_charset()
mysqli_connect() 默认用 latin1 连接,哪怕数据库是 utf8mb4 或 gbk,只要不显式设字符集,就可能触发宽字节注入。
- 错误写法:
mysqli_query($conn, "SET NAMES utf8mb4")—— 在 PHP 5.6 某些版本下无效,且不保证连接层编码同步 - 正确写法:
mysqli_set_charset($conn, 'utf8mb4')(若旧库是gbk,则填<code>gbk</code>) - 字符集不匹配时,
mysqli_prepare()可能返回false,但不报错;你查$stmt === false才能捕获 - 如果表字段用的是
utf8mb4_unicode_ci,而连接设成utf8,emoji 插入会截断,查不到也插不进
mysqli_stmt::bind_param() 的类型字符串不能省、不能错
PHP 5.6 对 bind_param() 类型校验严格:漏写 "s"、把字符串当整数写 "i"、顺序错位,都会导致查询空结果或执行失败。
立即学习“PHP免费学习笔记(深入)”;
- 类型标识必须与变量实际类型一致:
-
<code>s</code>→ 字符串(含数字字符串如"123") -
<code>i</code>→ 真正的整型(is_int($val)为true) -
<code>d</code>→ float/double
-
- 示例错误:
$stmt = mysqli_prepare($conn, "INSERT INTO users (name, age) VALUES (?, ?)"); $stmt->bind_param("si", $name, $age); // ✅ 正确 $stmt->bind_param("ss", $name, $age); // ❌ $age 是 int,强转成 string 可能被截断或报错 $stmt->bind_param("i", $age); // ❌ 少一个参数,数量不匹配,执行必挂 - 绑定前建议加类型判断:
if (!is_string($name)) $name = (string)$name;
不要用mysqli_real_escape_string()假装安全
有人图快,把旧代码的拼接改成 <code>mysqli_real_escape_string($conn, $_POST['user'])</code> 就交差——这是危险幻觉。
-
mysqli_real_escape_string()依赖当前连接字符集,若<code>mysqli_set_charset()</code>没设,它按latin1转义,%df%5c还是能绕过 - 它无法防御数字型注入(如
id = $_GET['id']),因为is_numeric()检查可被1 OR 1=1绕过 - 它不解决逻辑耦合问题:SQL 结构和数据仍混在一起,后续加字段、改条件极易出错
真正该做的,是把所有 $_GET/$_POST 入参统一走 <code>mysqli_prepare()</code> + <code>bind_param()</code>,哪怕只改一个查询,也要配齐三件套:扩展启用、字符集设置、类型绑定。
最易被忽略的一点:预处理不是“写了就安全”,而是“连通了、设对了、绑准了”才真正生效。 否则你调试半天发现 $stmt->execute() 返回 false,却不知是字符集没设,还是类型写错,或是扩展根本没加载。



















