首頁  >  問答  >  主體

從較舊的 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 天前517

全部回覆(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
  • 取消回覆