返回列表 发帖
查看: 59|回复: 3

[求助] 使用原生DELET语句无空格时无法删除数据的问题

1

主题

5

回帖

16

积分

初学乍练

贡献
0 点
金币
10 个
发表于 5 小时前 |北京| 查看全部 |阅读模式

1. 问题:

我使用DELETE语句删除数据的时候,如果引号内两侧不留空的时候,删除就不会执行,比如,下面这样就可以成功从数据库中删除: delpsqlf="DELETEFROMdatatable WHERE sid = sid";DB::query(delpsqlf); 而下面这样,显示已执行,但数据库中的数据并未删除,数据库也无报错: delpsqlf="DELETEFROMdatatable WHERE sid = sid";DB::query(delpsqlf);

2. 千问的回答:

针对上述问题,我将discuz_database.php发给千问,给的结果为:
通过分析您提供的PHP类代码,我发现问题出在Discuz框架的SQL安全检查机制上。让我为您详细解释:
问题根源
问题主要出现在discuz_database_safecheck::checkquery()方法中,这个方法负责SQL语句的安全检查。关键代码如下:
$cmd = strtoupper(substr(trim($sql), 0, 3)); if(isset(self::$checkcmd[$cmd])) { $check = self::_do_query_safe($sql); }
这里self::$checkcmd定义为:
protected static $checkcmd = array('SEL'=>1, 'UPD'=>1, 'INS'=>1, 'REP'=>1, 'DEL'=>1);
具体分析
当SQL语句有前后空格时(" DELETE FROM table WHERE sid = sid"trim(sql)会移除前后空格,得到"DELETE FROM table WHERE sid = sid"substr(trim(sql), 0, 3)返回"DEL" "DEL"在checkcmdSQL"DELETEFROMtableWHEREsid=sid"): 同样经过trim()处理,理论上应该得到相同结果 但在_do_query_safe()方法中,正则清理逻辑对格式高度敏感:
$clean = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($clean));
这个复杂的清理逻辑可能因缺少空格而导致清理后的SQL字符串不包含"del"关键字 最终安全检查失败,但框架没有抛出异常,而是静默失败

3. 智普的回答:

针对上述问题,我将discuz_database.php发给千问,给的结果为:
这个问题出在 DB::query 方法中提取 SQL 命令类型的逻辑上。
问题分析
当你在 SQL 语句字符串($delpsqlf)的开头(引号内侧)添加空格时,DB::query 中的代码逻辑会导致返回值类型不一致,从而影响你的业务逻辑判断(例如 if(DB::query(...)))。 请看 discuz_database 类中的 query 方法:
public static function query($sql, $arg = array(), $silent = false, $unbuffered = false) { // ... 前面的代码省略 ... // 执行 SQL 查询 $ret = self::$db->query($sql, $silent, $unbuffered); if (!$unbuffered && $ret) { // 【问题出在这里】 // 使用 strpos 查找第一个空格的位置来截取命令名称(如 DELETE, SELECT 等) $cmd = trim(strtoupper(substr($sql, 0, strpos($sql, ' ')))); if ($cmd === 'SELECT') { // ... } elseif ($cmd === 'UPDATE' || $cmd === 'DELETE') { // 如果命令是 UPDATE 或 DELETE,将返回值替换为受影响的行数 $ret = self::$db->affected_rows(); } elseif ($cmd === 'INSERT') { $ret = self::$db->insert_id(); } } return $ret; }
为什么会有两种结果?
情况一:语句前面有空格(" DELETE FROM ...") strpos(sql,′′)0substr(sql, 0, 0) 返回空字符串 ""。 cmdcmd 不等于 'DELETE',代码跳过了 ret=self::db->affected_rows(); 这一步。 最终 DB::query 返回的是 MySQL 的结果对象(Resource/Object)。 在 PHP 中,非空的对象转换为布尔值通常是 true。所以你的代码认为“执行成功”。
情况二:语句前面没有空格("DELETE FROM ...") strpos(sql,′′)DELETE6substr(sql, 0, 6) 返回 "DELETE"。 cmd"DELETE"elseif(cmd === 'UPDATE' || cmd===DELETE)ret 被赋值为 self::$db->affected_rows()(受影响的行数)。 关键点: 如果 SQL 实际上没有删除任何数据(例如 sid 不匹配,或者你使用了事务未提交),affected_rows() 返回 0。 你的代码判断 if(0) 结果为 false,所以你认为“执行失败”或“未删除”。
为什么数据库里实际上没被删除?
既然情况一显示“成功删除”,情况二显示“未删除”,但你提到情况二“数据库中的数据并未删除”,这意味着 affected_rows 确实返回了 0。 这说明在两种情况下,发给数据库的 SQL 语句实际上可能都没有匹配到数据(或者 $sid 在第二种情况下的值有问题)。但是:
javascript
我知道答案 回答被采纳将会获得1 贡献 已有3人回答
回复

使用道具 举报

45

主题

3287

回帖

5589

积分

应用开发者

Discuz! 运维

贡献
219 点
金币
685 个
QQ
发表于 5 小时前 |江苏| 查看全部
;P代码都贴不好,这AI开发者真的是。。。
回复

使用道具 举报

15

主题

3566

回帖

6080

积分

应用开发者

贡献
423 点
金币
172 个
QQ
发表于 4 小时前 |河南| 查看全部
科站网 发表于 2026-1-16 11:03
;P代码都贴不好,这AI开发者真的是。。。

拒绝为 ai开发者 提供任何帮助
回复

使用道具 举报

4

主题

18

回帖

32

积分

初学乍练

贡献
0 点
金币
8 个
发表于 4 小时前 |河南| 查看全部
你问gemini啊,国内的不行

3. 如何验证和修复?

为了彻底解决这个问题,建议按以下步骤操作:

第一步:确认数据库里的真实数据

不要只用肉眼看,使用 SQL 的长度函数来检查数据库里到底存了什么。
执行这个查询(假设你要查 sid 为 '1001' 的那条):
SQL-- MySQL / PostgreSQL / SQLite SELECT sid, LENGTH(sid) as len FROM datatable WHERE sid LIKE '%1001%';
  • 如果显示 sid1001,但 len6(而不是4),说明前后各有一个空格。
  • 这就是为什么你不留空格删不掉,留了空格(刚好凑对了)才能删掉的原因。

第二步:修复代码(推荐使用 TRIM)

为了防止未来再出现这种“必须手动加空格才能删”的玄学问题,建议在 SQL 中忽略空格,或者在代码层清理数据。
方案 A:在 SQL 中强制忽略两端空格(最稳妥) 无论数据库里有没有空格,都进行修剪后再比对:
SQL-- 将数据库里的字段和传入的值都去除空格进行比对 DELETE FROM datatable WHERE TRIM(sid) = TRIM('你的变量值');
方案 B:在插入数据时就清洗 这是治本的方法。在写入数据库(INSERT/UPDATE)之前,确保对变量进行了 trim() 处理(去除首尾空格)。

第三步:使用参数化查询(Binding)

你目前使用的看起来像是字符串拼接(String Concatenation),这不仅容易出现空格拼接错误,还极易遭受 SQL 注入攻击
建议改为参数化查询(伪代码示例):
C++// 错误写法(拼接) query("DELETE FROM table WHERE sid = '" + sid + "'"); // 正确写法(参数化绑定) // 这样你就不用担心引号、空格拼接的问题,数据库库函数会帮你处理 query.prepare("DELETE FROM table WHERE sid = ?"); query.bindValue(0, sid.trimmed()); // 传入前去除空格 query.exec();

总结

你遇到的“不报错但不删除”,是因为**WHERE 条件没有匹配到任何数据**。最直接的原因是你的数据库中存储的数据包含了首尾空格,导致精确匹配失败。
下一步建议: 你可以先执行一句 SELECT sid FROM datatable WHERE sid LIKE '%...%' 看看那些删不掉的数据长度是多少,确认是否包含空格。需要我帮你写针对你特定数据库类型的排查 SQL 吗?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 关注公众号
  • 有偿服务微信
  • 有偿服务QQ

手机版|小黑屋|Discuz! 官方交流社区 ( 皖ICP备16010102号 |皖公网安备34010302002376号 )|网站地图|star

GMT+8, 2026-1-16 16:04 , Processed in 0.049199 second(s), 10 queries , Redis On.

Powered by Discuz! X5.0 Licensed

© 2001-2026 Discuz! Team.

关灯 在本版发帖
有偿服务QQ
有偿服务微信
返回顶部
快速回复 返回顶部 返回列表