PHP插入数据最常见问题是误用已移除的mysql_*函数及未预处理导致SQL注入;必须改用PDO或面向对象mysqli,并严格使用prepare/execute绑定参数,检查rowCount或异常,注意字段类型与PHP数据匹配及字符集统一。

PHP 插入数据最常出问题的不是语法写错,而是 mysql_connect 已被彻底移除、mysql_query 不再可用,且未使用预处理语句导致 SQL 注入——这是初学者踩得最多、后果最严重的坑。
用 PDO 或 mysqli,别碰 mysql_* 函数
PHP 7.0 起已完全删除所有 mysql_* 函数(如 mysql_connect、mysql_query),强行调用会直接报 Fatal error: Uncaught Error: Call to undefined function mysql_connect()。
必须改用:
-
PDO:跨数据库兼容好,推荐初学者从它入手 -
mysqli(面向对象风格):原生支持 MySQL 特性,性能略优
不要用 mysqli_*() 过程式写法(如 mysqli_query($conn, $sql)),容易漏关连接、难复用;优先选面向对象写法或 PDO 预处理。
立即学习“PHP免费学习笔记(深入)”;
插入前必须用预处理(prepare + execute)
拼接字符串插数据(如 "INSERT INTO user VALUES ('" . $_POST['name'] . "')" )等于把数据库大门钥匙交给用户——任意输入 ' OR '1'='1 就能绕过验证、删库跑路。
正确做法是用占位符 + 绑定参数:
try {
$pdo = new PDO("mysql:host=localhost;dbname=test", $user, $pass);
$stmt = $pdo->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->execute([$_POST['name'], $_POST['email']]);
} catch (PDOException $e) {
error_log($e->getMessage());
}
注意点:
- 问号
?占位符不能加引号,否则会被当字面量处理 - 数值型字段不用手动转
int,PDO/MySQLi 会按参数类型自动绑定 - 批量插入用
execute()多次调用,别在一个 SQL 里堆几十个VALUES——易超包大小、难调试
检查 INSERT 是否成功不能只看 if ($stmt)
$stmt 对象只要准备成功就恒为真,哪怕 execute() 因唯一键冲突、字段超长、NULL 插非空字段而失败,也不会抛异常(默认设置下)。
必须主动判断影响行数或捕获异常:
- PDO:开启异常模式
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION),或执行后查$stmt->rowCount() === 1 -
mysqli:用
$mysqli->affected_rows > 0或$stmt->errno判断错误码
常见失败原因:
-
SQLSTATE[23000]: Integrity constraint violation:主键/唯一索引重复 -
Data too long for column:字符串超VARCHAR(20)限制 -
Field 'xxx' doesn't have a default value:非空字段没传值且无默认值
表字段类型和 PHP 数据要对得上
MySQL 的 TINYINT(1) 常被当布尔用,但 PHP 的 true 直接 bind 会变成 1,false 变成 0——看似可行,但若字段定义为 TINYINT(1) UNSIGNED,-1 就会溢出变 255;DATETIME 字段不能直接 bind time() 时间戳,得用 date('Y-m-d H:i:s') 格式化。
稳妥做法:
- 日期时间统一用
DateTime对象或 ISO8601 字符串(Y-m-d H:i:s) - 布尔值明确转
(int)$bool再 bind,避免依赖隐式转换 - JSON 字段(
JSON类型)不要存json_encode($arr)后的字符串,应直接 bind 关联数组(PDO 默认支持)或确保字段类型是JSON且 MySQL ≥ 5.7
字符集不一致也会静默截断,确保建表时指定 CHARSET=utf8mb4,PDO DSN 加 ;charset=utf8mb4,否则 emoji 和部分生僻字会变 ???。











