浅生 发表于 2026-1-16 13:52:31

新人帖 使用原生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人回答

TyCoding 发表于 2026-1-16 13:53:29

;P代码都贴不好,这AI开发者真的是。。。

TyCoding 发表于 2026-1-16 13:53:47

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

拾光 发表于 2026-1-16 13:54:43

你问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]
查看完整版本: 新人帖 使用原生DELET语句无空格时无法删除数据的问题 New