先检查$_SERVER['CONTENT_TYPE']是否为application/json等有效类型,再用file_get_contents('php://input')读取,若返回空且$_POST、$_GET均为空则报错;解析后必须用json_last_error()校验。

怎么确认 file_get_contents('php://input') 拿到的是完整数据
PHP 8.1 默认启用 always_populate_raw_post_data 关闭,且对 php://input 的读取更严格——它只在 Content-Type 不是 application/x-www-form-urlencoded 或 multipart/form-data 时才可读。如果接口接收 JSON,但前端发请求时没设 Content-Type: application/json,file_get_contents('php://input') 就会返回空字符串,后续 json_decode() 必然失败。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 先检查请求头:
var_dump($_SERVER['CONTENT_TYPE'] ?? 'missing'); - 再读原始体:
$raw = file_get_contents('php://input');,紧接着加判断:if ($raw === '' && empty($_POST) && empty($_GET)) { die('No raw input received'); } - JSON 解析后必须校验:
if (json_last_error() !== JSON_ERROR_NONE) { error_log('JSON parse error: ' . json_last_error_msg()); die('Invalid JSON'); }
filter_var 验证失败却没报错?PHP 8.1 的隐性返回变化
PHP 8.1 起,FILTER_VALIDATE_INT、FILTER_VALIDATE_FLOAT 等验证器对 null 输入统一返回 false(旧版部分返回 null),且不再接受科学计数法字符串(如 "1e2")。如果你的导入字段是可选的、可能为 null,直接传给 filter_var($x, FILTER_VALIDATE_INT) 会静默返回 false,容易被当成“校验不通过”而丢弃合法数据。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 显式过滤前先判空:
$age = $_POST['age'] ?? ''; if ($age === '') { /* 跳过或设默认值 */ } - 整数校验务必加
options:filter_var($age, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0]]) - 邮箱验证别只信
FILTER_VALIDATE_EMAIL:它允许a@b@c.com这种明显非法格式,应额外加长度限制和正则粗筛:strlen($email)
数据库写入后怎么确认导入成功——别只看 execute() 返回值
PDO 的 $stmt->execute() 返回 true 只代表语句执行无语法错误,不代表行被插入或更新了。比如唯一键冲突、外键失败、字段超长截断,都可能让 execute() 成功但实际没写入任何数据。PHP 8.1 默认开启 PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,但很多老项目仍用 PDO::ERRMODE_SILENT,这就导致错误完全沉默。
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 强制开启异常模式:
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); - 写入后立刻查影响行数:
if ($stmt->rowCount() === 0) { throw new RuntimeException('No row affected — check constraints or duplicate keys'); } - 批量导入时,每 100 条做一次
commit()并记录日志,避免单次事务过大失败后无法定位哪条出错
为什么日志里显示“导入完成”,但数据库里少了几条
最常见原因是字符编码不一致:PHP 文件保存为 UTF-8 无 BOM,但 MySQL 表/列的 CHARSET 是 latin1,或者连接未指定 charset=utf8mb4。PHP 8.1 对多字节字符更敏感,遇到乱码字段时,json_decode() 可能返回 null,或 PDO 插入时静默截断,甚至触发 mbstring.strict_detection=On 报错(该配置 PHP 8.1 默认启用)。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 建表时显式指定:
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci - PDO DSN 加
;charset=utf8mb4,例如:mysql:host=localhost;dbname=test;charset=utf8mb4 - 导入前统一清理不可见字符:
$clean = mb_ereg_replace('[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]', '', $input);
真正难调试的不是“导入失败”,而是“看似成功却漏数据”——这种问题往往跨编码、跨协议、跨配置层,必须从原始输入、中间处理、存储约束三端同时核对,不能只盯一个环节。


















