PHP实现密钥与支付状态双条件校验时SQL查询报非对象错误
联合校验逻辑报错的原因与调整方案
原代码的核心问题
- 最直接的报错根源:因为PHP运算符优先级规则,写在同一行的
$result = $conn->query($sql) && $result1 = $conn->query($eql);执行逻辑完全偏离预期。&&的运算优先级远高于赋值号=,这行代码实际等价于把整个逻辑与判断的布尔结果(true/false)赋值给$result,$result根本没有拿到数据库查询返回的结果集对象。后续代码试图读取$result->num_rows时,操作的是布尔值而非对象,自然触发“在非对象上获取属性”的报错。 - 支付状态校验逻辑完全脱钩:原支付查询
SELECT payment FROM new_keys WHERE payment =1是统计全表所有已支付的记录,没有把支付状态和当前用户输入的密钥做绑定。哪怕任意一个无关用户的密钥处于已支付状态,校验都会通过,完全不符合“对应用户输入的密钥本身已支付”的业务要求。 - 校验条件逻辑错误:判断支付状态的条件写的
num_rows > 1不符合约定,只要对应当前密钥存在1条已支付的记录就满足要求,大于1的判断逻辑会出现单条已支付记录被漏判的问题。 - 缺失结果合法性校验:没有判断数据库查询是否成功返回了合法的结果集对象,一旦查询执行报错返回false,直接读取结果属性就会触发非对象类报错。
可运行的调整方案
调整原则
- 每个数据库查询单独执行、单独赋值,绝不把查询赋值和逻辑判断写在同一行
- 查询支付状态时必须绑定当前用户输入的密钥,不做全表无关联扫描
- 读取结果属性前先校验结果是否为合法的结果集对象
- 校验条件匹配业务约定:存在1条匹配的有效记录即通过校验
方案1:payment字段与密钥存储在同一张表(推荐,性能最优)
如果原来存software_key、decrypt_key的表本身就有payment字段,不需要拆分两个查询,直接把校验条件拼接在单条SQL里即可:
// 单条SQL同时匹配密钥有效、已支付两个条件 $sql = "SELECT decrypt_key FROM keys WHERE software_key = '" . $software_key_encoded . "' AND payment = 1"; $result = $conn->query($sql); // 先校验查询返回合法结果集,再判断是否有匹配记录 if ($result && $result->num_rows > 0) { while($row = $result->fetch_assoc()) { echo $row["decrypt_key"]; } } else { echo "Failed"; } $conn->close();
方案2:payment字段存储在独立的new_keys表,通过software_key关联
如果支付状态确实存在独立的数据表,必须给支付查询加上当前密钥的关联条件,分开执行两个查询:
// 原有密钥校验查询,单独执行赋值 $sql = "SELECT decrypt_key FROM keys WHERE software_key='" . $software_key_encoded . "'"; $result = $conn->query($sql); // 支付状态查询,必须绑定当前输入的密钥,筛选已支付的记录 $eql = "SELECT payment FROM new_keys WHERE software_key = '" . $software_key_encoded . "' AND payment = 1"; $result1 = $conn->query($eql); // 同时校验两个结果集合法、都有匹配的有效记录 if ($result instanceof mysqli_result && $result->num_rows > 0 && $result1 instanceof mysqli_result && $result1->num_rows > 0) { while($row = $result->fetch_assoc()) { echo $row["decrypt_key"]; } } else { echo "Failed"; } $conn->close();
额外安全提示:现有代码直接将$software_key_encoded拼接到SQL字符串中存在SQL注入风险,长期使用建议替换为预处理语句的绑定参数写法,该优化不影响当前功能的正常运行。
内容的提问来源于stack exchange,提问作者Linken Eight
相关产品推荐
相关产品推荐

