首页  >  问答  >  正文

从较旧的 PHP 版本更新到 php8.2.5 时,“未捕获 mysqli_sql_exception:命令不同步;您现在无法运行此命令”

我有一个多年前编写的 PHP 5 的 mysqli 包装器,但在尝试在 PHP 8.2.5 上运行时出现错误。我已经尝试了一切。以下是两个主要功能:

global $db_obj, $db_driver;

function db_login() {
    global $db_obj;
    $res = @$db_obj->connect(DB_HOST, DB_USER, DB_PASS);
    if($res == false) {
        display_error("Could not connect to database.");
    }
    db_maybe_handle_error();
    db_select_db();
    db_set_charset();
}

function db_select_db($db = DB_NAME) {
    global $db_obj;
    @$db_obj->select_db($db);
    db_maybe_handle_error();
}

function db_set_charset($charset = 'utf8') {
    global $db_obj;
    @$db_obj->set_charset($charset);
    db_maybe_handle_error();
}

function db_error() {
    global $db_obj;
    return $db_obj->error();
}

function db_maybe_handle_error($r = null, $extra_info = "") {
    $e = db_error();
    if($e != '') {
       echo "mysql error: " . $e . " " . hsc($extra_info);
    }
    return $r;
}

function db_query($q) {

    $num_args = func_num_args();
    $arg_list = func_get_args();
    $r = null;

    global $db_obj;

    if($num_args > 1) {
        $stmt = $db_obj->stmt_init();
        if($stmt->prepare($q)) {
            $types = "";
            $refArr = array("");
            for($i = 1; $i < $num_args; $i++) {
                $type = gettype($arg_list[$i]) === "integer" ? "i" : "s";
                //$stmt->bind_param($type, $arg_list[$i]);
                // PHP <=5.2: Remove the ampersand
                // See http://php.net/manual/de/mysqli-stmt.bind-param.php
                $refArr[] = &$arg_list[$i];
                $types .= $type;
            }
            $refArr[0] = $types;
            $ref = new ReflectionClass('mysqli_stmt');
            $method = $ref->getMethod("bind_param");
            $method->invokeArgs($stmt, $refArr);
            $stmt->execute();
            $stmt->store_result();
            $r = $stmt;
        } else {
            db_maybe_handle_error(null, $q);
        }
    } else {
        $r = @$db_obj->query($q);
    }

    db_maybe_handle_error(null, $q);

    return $r;
}

function db_fetch($res, $use_numerical_indices = null) {
    global $db_obj;

    $use_numerical_indices = $use_numerical_indices === true ||
        ($use_numerical_indices === null && DB_DEFAULT_USE_NUMERICAL_INDEXES);

    if(is_array($res)) {
        return array_shift($res);
    }

    if($res instanceof mysqli_stmt) {
        $res->store_result();
        //$res->get_result();
        $variables = array();
        $data = array();
        $meta = $res->result_metadata();

        while($field = $meta->fetch_field()) {
            $variables[] = &$data[$field->name];
        }

        call_user_func_array(array($res, 'bind_result'), $variables);

        if(!$res->fetch()) {
            $res->close();
            return null;
        }
        $array = array();
        $i = 0;
        foreach($data as $k => $v) {
            $array[$k] = $v;
            if($use_numerical_indices) {
                $array[$i] = $v;
            }
            $i++;
        }
        db_maybe_handle_error($array);
    }
    $result_type = $use_numerical_indices ? $db_obj->BOTH : $db_obj->ASSOC;
    $r = @$db_obj->fetch_array($res, $result_type);
    return db_maybe_handle_error($r);
}

function db_num_rows($res) {
    global $db_obj;
    if(is_array($res)) {
        return count($res);
    }
    if($res instanceof mysqli_stmt) {
        return mysqli_stmt_num_rows($res);
    }
    $r = @$db_obj->num_rows($res);
    return db_maybe_handle_error($r);
}

function db_insert_id() {
    global $db_obj;
    $r = @$db_obj->insert_id();
    return db_maybe_handle_error($r);
}

要获取一行,可以使用标准查询来完成:

$row = db_fetch(db_query("SELECT * FROM $table WHERE id=? LIMIT 1", $id));

带有 store_result() 的行(在 db_fetch 函数中)给出了此错误:

未捕获 mysqli_sql_Exception:命令不同步;您现在无法运行此命令

我已经尝试了几乎所有方法,包括尝试将 $stmt->free_result()$stmt->close() 添加到代码的不同部分段。

问题是我特别请求帮助使用 $stmt->free_request()$stmt->close() 重写此代码段,所以发生最少的代码更改并可以尽可能地保持原样。这些将在 db_querydb_fetch 函数中去哪里?

P粉883278265P粉883278265277 天前512

全部回复(1)我来回复

  • P粉718165540

    P粉7181655402024-01-17 12:42:35

    您收到的错误意味着您正在尝试无序执行 mysqli 函数(以及 MySQL 命令)。当 MySQL 收到此时不期望的命令时,它会回复此错误。

    您不要在代码中的任何位置添加 free_result()close()。正确结构的代码不应具有任何这些功能。它们只是为了防止意大利面条代码中的内存泄漏。

    要修复该错误,您必须确保操作以正确的顺序执行。但这段代码太混乱了,无法搞清它的情况。你必须重写它!

    尝试像这样简单的事情:

    function db_query($q, $params = []): mysqli_result
    {
        global $db_obj; // DO NOT USE GLOBALS!!!
    
        return $db_obj->execute_query($q, $params);
    }
    
    function db_fetch(mysqli_result $res, $use_numerical_indices = null)
    {
        $use_numerical_indices = $use_numerical_indices === true ||
            ($use_numerical_indices === null && DB_DEFAULT_USE_NUMERICAL_INDEXES);
    
        $result_type = $use_numerical_indices ? MYSQLI_NUM : MYSQLI_ASSOC;
        return $res->fetch_array($result_type);
    }

    其他函数需要以类似的方式进行修剪。

    实际问题是您调用了 store_result() 两次。最简单的解决方法是删除其中之一。但是删除哪一个是一个谜,因为这段代码并没有明确说明哪一个(如果有的话)实际上是必要的。您可能可以删除两者,但是 db_num_rows 将不起作用。

    回复
    0
  • 取消回复