PHP数据库重复分类检测代码咨询:是否存在遗漏?
代码问题分析与修正方案
Hey there, let's walk through the issues in your code and fix them up—there are some critical security and functionality gaps here:
1. 严重的SQL注入漏洞
直接将用户输入的$_POST['Add_category']拼接进SQL语句是极高风险的操作,攻击者可以通过构造恶意输入来篡改你的数据库(比如删除表、窃取数据)。必须使用参数化查询来避免这个问题,sqlsrv完全支持参数绑定。
2. 错误处理语法错误
你把OR die(sqlsrv_errors())写在了SQL字符串的末尾,这是语法错误——$query1是一个字符串,不能直接跟OR die()。错误处理应该放在sqlsrv_query调用之后,判断查询是否执行失败。
3. sqlsrv_num_rows无法正确获取行数(默认游标限制)
sqlsrv默认使用SQLSRV_CURSOR_FORWARD游标,这种游标不支持获取行数(sqlsrv_num_rows会返回false)。你需要在查询时指定支持行数统计的游标类型,比如SQLSRV_CURSOR_STATIC。
4. 逻辑顺序不合理
你先执行了数据库查询,再检查$newcategory是否为空。应该先做客户端的输入校验,避免不必要的数据库请求。
5. 错误处理不完整
当sqlsrv_query执行失败返回false时,后续的sqlsrv_num_rows($statement1)会触发新的错误,因为你不能对false调用这个函数。必须先判断查询成功,再处理结果。
修正后的完整代码
<?php if (isset($_POST['create_new_category'])) { $newcategory = trim($_POST['Add_category']); // 先去除首尾空格 // 第一步:先检查输入是否为空 if (empty($newcategory)) { echo "请输入分类名称"; exit; // 终止后续执行 } // 第二步:参数化查询检查分类是否存在 $query1 = "SELECT 1 FROM JobAdCategories WHERE jacat_title = ?"; $params1 = array($newcategory); $options = array("Scrollable" => SQLSRV_CURSOR_STATIC); // 指定支持行数的游标 $statement1 = sqlsrv_query($connection, $query1, $params1, $options); if ($statement1 === false) { echo "查询错误 (sqlsrv_query): " . print_r(sqlsrv_errors(), true); exit; } $count = sqlsrv_num_rows($statement1); sqlsrv_free_stmt($statement1); // 释放语句资源 if ($count == 0) { // 第三步:参数化插入新分类 $query2 = "INSERT INTO JobAdCategories (jacat_title) VALUES (?)"; $params2 = array($newcategory); $statement2 = sqlsrv_query($connection, $query2, $params2); if ($statement2 === false) { echo "插入错误 (sqlsrv_query2): " . print_r(sqlsrv_errors(), true); } else { echo "新分类已成功添加"; sqlsrv_free_stmt($statement2); } } else { echo "该分类已存在"; } } ?>
额外优化点
- 添加了
trim()去除输入的首尾空格,避免用户输入空字符串或全空格的无效分类 - 使用
SELECT 1代替SELECT *,只需要判断存在性,不需要返回全表数据,提升查询效率 - 每次查询后调用
sqlsrv_free_stmt()释放资源,避免内存泄漏 - 用
exit终止后续代码执行,避免错误后继续执行不必要的逻辑
内容的提问来源于stack exchange,提问作者Legend Whirlwind
相关产品推荐
相关产品推荐

