PHP MySQLi开发服务器申请表单,提交后正常跳转但未生成数据库记录
问题定位与修复方案
核心异常触发原因
当前代码的逻辑判定存在明显缺口:仅对prepare()预处理的成功性做了判断,没有覆盖后续参数绑定、SQL执行环节的错误捕获。只要预处理语句能正常生成,无论后续写入是否实际失败,都会直接设置“提交成功”的提示并跳转页面,因此才会出现前端提示成功、数据库无记录的异常。
具体的代码漏洞包括:
- 两个switch分支的判断逻辑仅校验了
prepare()的返回值,没有检查bind_param()的参数匹配度、execute()的实际写入结果。当SQL因为字段非空约束、值类型不匹配、字段长度超限等原因执行失败时,代码不会进入错误提示分支。 - 游戏服务器(type=1)分支中,
$stmt->close()语句写在了exit跳转逻辑的后方,完全无法执行到,会导致数据库连接没有正常释放,长期运行后可能出现连接耗尽引发的写入失败。 - 表单端的下拉项没有做联动禁用处理,当用户选择某一类服务器类型时,隐藏的对应下拉框(比如选择游戏服务器时的操作系统下拉、vServer配置下拉)依然会随表单提交空值,极易触发数据库表的非空字段约束报错。
修复实现
首先在数据库连接阶段开启mysqli的错误报告模式,方便定位具体执行错误:
连接配置参考代码:
// 开启mysqli错误上报 mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT); $con = mysqli_connect($DATABASE_HOST, $DATABASE_USER, $DATABASE_PASS, $DATABASE_NAME); if (mysqli_connect_errno()) { exit('MySQL连接失败: ' . mysqli_connect_error()); }
然后重构提交逻辑,去掉重复的预处理代码,对全流程的执行结果做校验:
重构后的处理逻辑:
$type = intval($_POST['applyservertype']); $none = 'none'; try { // 两个分支的INSERT语句结构完全一致,只需预处理一次 $stmt = $con->prepare('INSERT INTO serverapply (username, servertype, operatingsystem, game, system, serverdescription) VALUES (?, ?, ?, ?, ?, ?)'); switch ($type) { case 1: // 游戏服务器类型绑定参数 $stmt->bind_param( 'ssssss', $_SESSION['name'], $_POST['applyservertype'], $none, $_POST['servergame'], $_POST['servergamesystem'], $_POST['description'] ); break; case 2: // vServer类型绑定参数 $stmt->bind_param( 'ssssss', $_SESSION['name'], $_POST['applyservertype'], $_POST['serveroperatingsystem'], $none, $_POST['serversystem'], $_POST['description'] ); break; default: throw new Exception('无效的服务器类型选择'); } // 实际执行写入,无报错才判定为成功 $stmt->execute(); $stmt->close(); $_SESSION['notification'] = "server-successful"; } catch (Throwable $e) { // 记录实际错误到服务端日志,不暴露给前端 error_log('服务器申请提交失败:' . $e->getMessage()); $_SESSION['notification'] = "server-error"; } // 统一跳转回提交页 header('Location: ' . $_SERVER['HTTP_REFERER']); exit;
额外补充的校验逻辑:
- 前端做表单联动,当切换服务器类型时,给不需要展示的下拉框加
disabled属性,避免无效值随表单提交。 - 提交前校验用户是否选择了对应展示的下拉项,禁止空值提交,从源头减少数据库约束报错的概率。
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

