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 预处理。
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->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION),或执行后查 $stmt->rowCount() === 1

$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:非空字段没传值且无默认值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_encode($arr) 后的字符串,应直接 bind 关联数组(PDO 默认支持)或确保字段类型是 JSON 且 MySQL ≥ 5.7字符集不一致也会静默截断,确保建表时指定 CHARSET=utf8mb4,PDO DSN 加 ;charset=utf8mb4,否则 emoji 和部分生僻字会变 ???。