【问题标题】:Prepared Statement getting Commands out of sync; you can't run this command now准备好的语句使命令不同步;你现在不能运行这个命令
【发布时间】:2013-08-10 22:57:50
【问题描述】:

我已经阅读了所有我能想到的解释,但似乎没有任何帮助。如果有人能够指出明显的问题或让我稍微了解一下哪里出了问题。我已经阅读了 php.net 和 mysqli 标签,但似乎无法弄清楚这一点。我读到的所有内容都说您不能发送两个查询,但我只尝试一个。任何帮助将不胜感激。

This->https://stackoverflow.com/a/9649149/1626329 - 表示我可能有多个结果集,但我不确定这是否有意义,或者我可以做些什么来获得有关准备好的语句的内部工作的更多细节。

我的代码:

class mydb {

    public function __construct() {
        // Connect to Database
        $this->mydb = new mysqli('****', '***', '***', '***');
        if ($this->mydb->connect_errno) { // Error on connection failure
            echo "Failed to connect to MySQL in Construct: (" . $this->mydb->connect_errno . ") " . $this->mydb->connect_error;
        }
    }

    public function choose ($select, $from, $config = 0, $options = NULL) {
        if ($config === 0) { /** Configure statement for prepare depending on options */
            $stmt = 'SELECT ' . $select . ' FROM ' . $from;
        } elseif ($config === 1) {
            $stmt = 'SELECT ' . $select . ' FROM ' . $from . ' WHERE ' . $options['where_comp'] . ' LIKE ?';
        } elseif ($config === 2) {
            $stmt = 'SELECT ' . $select . ' FROM ' . $from . ' WHERE ' . $options['where_comp'] . ' = ?';
        } /** End if/elseif Prepare statemenet */
        $mydb = $this->mydb->prepare($stmt);
        if ($config === 1 || $config === 2) {
            $mydb->bind_param("s",$options['where_value']);
        }

        if ($mydb->execute()) { /** If execute is good then get results */
            $result = $mydb->get_result();
            $payload = array();
            while ($row = $result->fetch_array(MYSQLI_NUM)) {
                $payload[] = $row;
            }
            return $payload;
        } /** End if results */
    } /** End choose class method */
} /** End mydb Class */

$myDB = new mydb();

$agentArray = $myDB->choose('*','`agent`');

使用了 php.net 示例并对其进行了修改以显示更好的示例:

$mysqli = new mysqli('host', 'database', 'user', 'pass');
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}

if (!($stmt = $mysqli->prepare("SELECT ? FROM ?"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

if (!$stmt->execute()) {
    echo "Execute failed: (" . $stmt->errno . ") " . $stmt->error;
}

if (!($res = $stmt->get_result())) {
    echo "Getting result set failed: (" . $stmt->errno . ") " . $stmt->error;
}

for ($row_no = ($res->num_rows - 1); $row_no >= 0; $row_no--) {
    $res->data_seek($row_no);
    var_dump($res->fetch_assoc());
}
$res->close();

【问题讨论】:

  • 你不能使用表名或列名作为参数,这是我注意到的第一件事。
  • 刚刚发现一个错误:$payload[] .= $row; 应该是$payload[]= $row;(删除了点.
  • Arg 我希望这在文档中更明显。也许我只是错过了准备好的陈述的全部目的,或者我正在清理不是用户输入的东西。是时候重新考虑这堂课了 LOL - 谢谢大家!
  • 另外,类构造函数不应该返回任何东西

标签: php mysqli prepared-statement


【解决方案1】:

此页面上“相关”部分的第一个结果(意味着它是在您编写问题时提供给您的)offers a solution

作为一般规则,根据错误消息很容易找到问题的答案。只需要不要停留在第一个搜索结果上,而是继续前进。

但是,在你的这个功能上choose()。我觉得它非常不切实际、不安全和无用:

  • 不切实际,因为它不允许您使用 SQL,而是它的一个非常有限的子集。
    • 而且它还使您的代码非常难以理解。
  • 不安全,因为它不为所有动态部件提供保护,但只提供价值
  • 没用,因为它可以为您节省太多,而不是一团糟。

看,你以为你救了自己两个字 - SELECTFROM

 $agentArray = $myDB->choose('*','`agent`',1,
               array('where_comp' => 'name', 'where_value' -> "%bob%"));

但是您让这段代码难以理解、难以维护并且无法运行最简单的 JOIN。为什么不去做。更不用说实际代码比传统的 SQL 查询更长了:

$sql = 'SELECT * FROM `agent` WHERE name LIKE ?';
$agentArray = $myDB->query($sql, "%bob%");

哪一个更容易阅读?

【讨论】:

  • 现在查看它的范围看起来非常无用,但我向您保证,从长远来看,它会更有意义。我不喜欢加入,我的系统旨在避免这种情况,但这是我将牢记的非常有效的一点。类的想法本质上是编写“不合理或有限的有效代码”,然后可以轻松地在以后更改格式,而不用重新编码整个站点。我发布此代码的另一个原因是为了查看那些已经编码了一段时间的人通常使用的其他角度。感谢您的洞察力!
【解决方案2】:

添加一个if语句来正确显示错误实际上给出了一个可以使用的mysql错误响应:

if (!($stmt = $mysqli->prepare("SELECT ? FROM ?"))) {
    echo "Prepare failed: (" . $mysqli->errno . ") " . $mysqli->error;
}

错误响应: Prepare failed: (1064) You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?' at line 1

-- 你不能通过准备好的语句传递标识符,你应该只将它用于从用户输入传递的值。

【讨论】:

  • 我提供了正确的答案供其他人查看,因为您对答案的建议不正确。这是我在执行返回我上面显示的结果之前就可以看到问题的方式。我的印象是,如果我的问题不适用于所有示例,那么当调试中未显示错误时,我应该在稍后的步骤中显示导致我的问题的示例。看到我因为详细解释这个问题而失去了代表,这非常令人失望。我并没有试图窃取它的功劳。
猜你喜欢
  • 1970-01-01
  • 2016-05-28
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 2013-10-05
  • 1970-01-01
  • 2013-04-08
  • 2016-04-11
相关资源
最近更新 更多