【问题标题】:SQL query transition from mysql to procedural style error: Commands out of sync; you can't run this command nowSQL 查询从 mysql 转换到程序样式错误:命令不同步;你现在不能运行这个命令
【发布时间】:2025-12-03 13:25:01
【问题描述】:

目前我将我的代码从 mysqli 样式编辑为 mysqli_stmt,以便能够更好地防止 SQL 注入。我重写了我的代码,但是当我想检查某个查询有多少行时,我收到了这个错误:命令不同步;你现在不能运行这个命令,所以我的表不会显示任何数据,但实际上它有。

我已经阅读这个错误几个小时了,但我不知道如何调整它才能使其正常工作。

此外,我知道在这种情况下我没有变量,但我倾向于在所有代码中使用相同的样式。

这是我目前使用的代码(不工作):

$stmt = mysqli_prepare($conn,"SELECT * FROM `assets`");
    mysqli_stmt_execute($stmt);
    mysqli_stmt_store_result($stmt);

    if (!($result = mysqli_stmt_get_result($stmt))){ 
        die("Could not show the required data");}
    elseif (empty(mysqli_stmt_num_rows($result))){
                echo "Currently there are no assets to be shown.";}
    elseif (mysqli_stmt_num_rows($result) > 0){
        echo '<table id="table" class="display"><thead>
        <tr>
        <th>Asset name</th>
        <th>Classification</th> 
        <th>Tag</th>
        <th>Department</th> 
        <th>Next review date</th>   
        <th>Owner</th>  
        <th>Update</th>
        </tr></thead><tbody>';

        while($result2=mysqli_fetch_array($result, MYSQLI_NUM))
        {   $class="";
            if ($result2["Review_date"] < date('Y-m-d')){$class=" old";} elseif($result2["Review_date"] < date('Y-m-d', strtotime('+6 days'))){$class="notnew";} else {$class="new";}
                    echo '<tr class="'.$class.'">
                        <td>'.$result2["Asset_name"].'</td>
                        <td>'.$result2["Classification"].'</td>
                        <td>'.$result2["Tag"].'</td>
                        <td>'.$result2["Department"].'</td>
                        <td>'.$result2["Review_date"].'</td>
                        <td>'.$result2["Responsible"].'</td>
                        <td><a href="editassets.php?id='.$result2['id'].'">Edit</a> | <a href="deleteassets.php?id='.$result2['id'].'" onclick="return confirm(\'Do you want to delete this asset?\');">Delete</a></td>
                        </tr>';
        }
        echo '</tbody></table>';
    }

我知道我的问题在于第一个 elseif 语句,我尝试使用 mysqli_stmt_free_result($stmt) 但在这种情况下,我不知道它是否是解决方案,如果是,在哪里以及如何放置它。

感谢您的帮助!

【问题讨论】:

  • 尝试从您的代码中删除mysqli_stmt_store_result($stmt);。你不应该把它和mysqli_stmt_get_result()混在一起。
  • mysqli_stmt_num_rows() 期望参数 1 是 mysqli_stmt,给定对象 --> 如果不包括该行,我收到此错误
  • 试试mysqli_stmt_num_rows($stmt)mysqli_num_rows($result) - 顺便说一句,请阅读docs 了解您正在使用的功能。

标签: php mysql mysqli


【解决方案1】:

以下是我的建议:

  1. 永远不要使用mysqli_stmt_store_result(),除非您确切知道它有什么用处。请改用mysqli_stmt_get_result()。无论如何 - 你不应该混合这两个功能。
  2. 不要在结果上使用mysqli_stmt_num_rows()。请改用mysqli_num_rows($result)
  3. 切换到对象方法而不是全局函数调用。例如:$result-&gt;num_rows 而不是 mysqli_num_rows($result)。代码会更短,您将无法使用带有错误参数类型的函数,例如 mysqli_stmt_num_rows($result)
  4. 使用MYSQLI_ASSOC 而不是MYSQLI_NUM。或使用mysqli_fetch_assoc()

您的代码应如下所示:

$stmt = $conn->prepare("SELECT * FROM `assets`");
$stmt->execute();
$result = $stmt->get_result()

if (!$result) { 
    die("Could not show the required data");
} elseif ($result->num_rows == 0) {
    echo "Currently there are no assets to be shown.";
} else {
    echo '<table id="table" class="display"><thead> [..]';

    while($result2 = $result->fetch_assoc()) {
        $class="";
        if ($result2["Review_date"] < date('Y-m-d')){
            $class=" old";
        } elseif($result2["Review_date"] < date('Y-m-d', strtotime('+6 days'))){
            $class="notnew";
        } else {
            $class="new";
        }
        echo '<tr class="'.$class.'">
            <td>'.$result2["Asset_name"].'</td>
            [..]
            </tr>';
    }
    echo '</tbody></table>';
}

【讨论】:

  • 非常感谢,成功了!我需要做的唯一更改是我需要删除 $result->num_rows 末尾的 (),但谢谢。通过使用此解决方案,我的页面是否可以免受 SQL 注入?
  • 你是对的 num_rows 是一个属性 - 而不是一个方法。此代码是从 SQL 注入中保存的。但是您的查询是“恒定的”并且没有参数。你甚至可以只使用$conn-&gt;query("...") 而不使用prepare(),但它会很安全。当您必须在查询中包含变量时,有趣的部分就开始了。 SELECT * FROM users WHERE email = {$email} 即使有准备也不安全。您应该使用$stmt = $conn-&gt;prepare("SELECT * FROM users WHERE email = ?") - 然后绑定参数并执行。只要您不在查询字符串中使用变量,您就是安全的。