新人帖 使用原生DELET语句无空格时无法删除数据的问题 New
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"在checkcmd数组中存在,安全检查正常通过当SQL语句无前后空格时("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,′′)会找到第一个空格,其位置是0。substr(sql, 0, 0) 返回空字符串 ""。cmd变成了空字符串。因为cmd 不等于 'DELETE',代码跳过了 ret=self::db->affected_rows(); 这一步。最终 DB::query 返回的是 MySQL 的结果对象(Resource/Object)。在 PHP 中,非空的对象转换为布尔值通常是 true。所以你的代码认为“执行成功”。
情况二:语句前面没有空格("DELETE FROM ...")strpos(sql,′′)会找到DELETE后面的空格,位置是6。substr(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人回答 ;P代码都贴不好,这AI开发者真的是。。。 拒绝为 ai开发者 提供任何帮助 你问gemini啊,国内的不行
3. 如何验证和修复?
为了彻底解决这个问题,建议按以下步骤操作:
第一步:确认数据库里的真实数据
不要只用肉眼看,使用 SQL 的长度函数来检查数据库里到底存了什么。
执行这个查询(假设你要查 sid 为 '1001' 的那条):
SQL-- MySQL / PostgreSQL / SQLiteSELECT sid, LENGTH(sid) as len FROM datatable WHERE sid LIKE '%1001%';
[*]如果显示 sid 是 1001,但 len 是 6(而不是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 吗?
.ce-block { margin-bottom: 20px;}.ce-block__content,.ce-toolbar__content { /* max-width:calc(100% - 50px) */ margin-left: auto; margin-right: auto;}.ce-paragraph { line-height: 1.6em; outline: none; text-indent: 2em; font-size: 16px;}.ce-paragraph--right { text-align: right;}.ce-paragraph--center { text-align: center;}.ce-paragraph--left { text-align: left;}.ce-paragraph--justify { text-align: justify;}.ce-paragraph-text-indent { text-align: justify;}.ce-paragraph:empty::before{content: attr(data-placeholder);color: #707684;font-weight: normal;opacity: 0;}/** Show placeholder at the first paragraph if Editor is empty */.codex-editor--empty .ce-block:first-child .ce-paragraph:empty::before {opacity: 1;}.codex-editor--toolbox-opened .ce-block:first-child .ce-paragraph:empty::before,.codex-editor--empty .ce-block:first-child .ce-paragraph:empty:focus::before {opacity: 0;}.ce-paragraph p:first-of-type{ margin-top: 0;}.ce-paragraph p:last-of-type{ margin-bottom: 0;}.svg-icon { width: 1em; height: 1em;}.svg-icon path,.svg-icon polygon,.svg-icon rect { fill: #4691f6;}.svg-icon circle { stroke: #4691f6; stroke-width: 1;}.ce-block { margin-bottom: 20px;}.ce-block__content, .ce-toolbar__content { margin-left: auto; margin-right: auto;}.cdx-quote { position: relative; background-color: #f8f8f8; padding: 24px!important; margin: 0px; border-radius: 12px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); overflow: hidden;}.quote-background-icon { position: absolute; top: 10px; right: 10px; opacity: 0.2; z-index: 1;}.cdx-quote__text { min-height: 30px; margin-bottom: 10px; font-size: 16px; line-height: 1.5; color: #333;}.cdx-quote__caption { padding: 10px 20px 0px 20px; font-size: 14px; color: #777;}.cdx-quote__caption-left { text-align: left;}.cdx-quote__caption-center { text-align: center;}.cdx-quote__caption-right { text-align: right;}.cdx-quote ::before { position: absolute; content: attr(data-placeholder); color: #bbb; font-weight: normal; opacity: 0;}.cdx-quote :empty::before { opacity: 1;}.cdx-quote :empty:focus::before { opacity: 0;}.cdx-quote-settings { display: flex;}.cdx-quote-settings .cdx-settings-button { width: 50%;}.ce-block { margin-top: 20px; margin-bottom: 20px;}.ce-block__content,.ce-toolbar__content { /* max-width:calc(100% - 50px) */ margin-left: auto; margin-right: auto;}/** * Plugin styles */.ce-header {position: relative;padding: 1px 0px 1px 15px;margin: 0;line-height: 1.25em;outline: none;margin-bottom: 10px;}.ce-header p,.ce-header div {padding: 0 !important;margin: 0 !important;}.ce-header::before { content: ""; width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; border-left: 12px solid #155BD5; position: absolute; left: 0; top: 50%; transform: translateY(-50%); background-color: transparent; border-radius: 0;}/** * Styles for Plugin icon in Toolbar */.ce-header__icon {}.ce-header::before {position: absolute;content: attr(data-placeholder);color: #707684;font-weight: normal;display: none;cursor: text;}.ce-header:empty::before {display: block;}.ce-header:empty:focus::before {display: none;}/* FontSize */h1.ce-header { font-size: 2.0em;}h2.ce-header { font-size: 1.7em;}h3.ce-header { font-size: 1.4em;}h4.ce-header { font-size: 1.15em;}h5.ce-header { font-size: 0.95em;}h6.ce-header { font-size: 0.8em;}/* Alignment*/.ce-header--right {text-align: right;}.ce-header--center {text-align: center;}.ce-header--left {text-align: left;}.ce-header--justify {text-align: justify;}.ce-block { margin-bottom: 20px;}.ce-block__content,.ce-toolbar__content { /* max-width:calc(100% - 50px) */ margin-left: auto; margin-right: auto;}.cdx-list { margin:0; outline:none; display:block; counter-reset:item; padding:6px;}.cdx-list__item { line-height:1.45em; display:block; padding-top:8px}.cdx-list__item-children { display:block;}.cdx-list__item { outline:none}.cdx-list__item-content { word-break:break-word; white-space:pre-wrap; grid-area:content; padding-left:8px}.cdx-list__item:before { counter-increment:item; white-space:nowrap}.cdx-list-li-container {display: flex;}.cdx-list-ordered .cdx-list__item:before { /* content:counters(item,".",numeric) "." */}.cdx-list-ordered { list-style-type: none; margin-left: -15px; counter-reset:item; font-size: 16px;}.cdx-list-unordered { font-size: 16px;}.cdx-list-unordered .cdx-list__item:before { content:"•"}.cdx-list-checklist .cdx-list__item:before { content:""}.cdx-list__settings .cdx-settings-button { width:50%}.cdx-list__checkbox { padding-top:calc((1.45em - 1.2em) / 2); grid-area:checkbox; width:1.2em; height:1.2em; display:flex; cursor:pointer; font-size: 16px;}.cdx-list__checkbox svg { opacity:0; height:1.2em; width:1.2em; left:-1px; top:-1px; position:absolute}@media (hover:hover) { .cdx-list__checkbox:not(.cdx-list__checkbox--no-hover):hover .cdx-list__checkbox-check svg { opacity:1}}.cdx-list__checkbox--checked-1 { line-height:1.45em}@media (hover:hover) { .cdx-list__checkbox--checked-1:not(.cdx-list__checkbox--checked-1--no-hover):hover .cdx-checklist__checkbox-check { background:#0059AB; border-color:#0059AB}}.cdx-list__checkbox--checked-1 .cdx-list__checkbox-check { background:#369FFF; border-color:#369FFF}.cdx-list__checkbox--checked-1 .cdx-list__checkbox-check svg { opacity:1}.cdx-list__checkbox--checked-1 .cdx-list__checkbox-check svg path { stroke:#fff}.cdx-list__checkbox--checked-1 .cdx-list__checkbox-check:before { opacity:0; visibility:visible; transform:scale(2.5)}.cdx-list__checkbox-check { cursor:pointer; display:inline-block; position:relative; margin:0 auto; width:1.2em; height:1.2em; box-sizing:border-box; border-radius:5px; border:1px solid #C9C9C9; background:#fff}.cdx-list__checkbox-check:before { content:""; position:absolute; top:0; right:0; bottom:0; left:0; border-radius:100%; background-color:#369FFF; visibility:hidden; pointer-events:none; transform:scale(1); transition:transform .4s ease-out,opacity .4s}.cdx-list__checkbox-check--disabled { pointer-events:none}.cdx-list-start-with-field { background:#F8F8F8; border:1px solid rgba(226,226,229,.2); border-radius:6px; padding:2px; display:grid; grid-template-columns:auto auto 1fr; grid-template-rows:auto}.cdx-list-start-with-field--invalid { background:#FFECED; border:1px solid #E13F3F}.cdx-list-start-with-field--invalid .cdx-list-start-with-field__input { color:#e13f3f}.cdx-list-start-with-field__input { font-size:16px; outline:none; font-weight:500; font-family:inherit; border:0; background:transparent; margin:0; padding:0; line-height:22px; min-width:calc(100% - 10px)}.cdx-list-start-with-field__input::placeholder { color:#797979; font-weight:500}.inline-code {background: rgba(250, 239, 240, 0.78);color: #b44437;padding: 3px 4px;border-radius: 5px;margin: 0 1px;font-family: inherit;font-size: 0.86em;font-weight: 500;letter-spacing: 0.3px;}
页:
[1]