php - PHP 7.4.18 更新:Mysqlnd -- 在 fetch 之后调用 stmt_store_result 现在会引发错误
问题描述
我们有很多网站使用共享的 MySQLi 类。PHP 7.4 正在使用这些,并且没有看到任何错误产生。
现在,PHP 错误 #80837已在 PHP 7.4.18 版本中得到修复
问题是这个修复意味着我们所有的网站都抛出这个致命错误,我看不到如何修复错误本身。
例外:
[06-May-2021 08:04:19 UTC] PHP 致命错误:未捕获的 mysqli_sql_exception:命令不同步;您现在无法
在 /usr/local/lib/php/databaseClass.php:169 中运行此命令 堆栈跟踪:
#0 /usr/local/lib/php/databaseClass.php(169): mysqli_stmt->store_result()
#1 /usr/local/lib/php/databaseClass.php(897): 数据库->fetchResult(Object(mysqli_stmt), true)
#2 /home/account/public_html/.../file.php(45): DatabaseObject->getSelect('SELECT (bad_log...', Array, true)
#3 /home/katemawdsley/public_html/start.php(10): include('/home/account...')
#4 {main在第 169 行的 databaseClass.php 中抛出
数据库类 'fetchResult' 方法:
/***
* For use with MySQLi->dbiLink Object.
* Returns the result as an array of KEY=>VALUE pairs from the Database.
* @param $result mysqli_result object.
* @return array|mixed
***/
private function fetchResult($result)
{
if ($result instanceof \mysqli_stmt) {
$result->store_result(); // This is line 169
$variables = [];
$data = [];
$meta = $result->result_metadata();
//error_log(print_r(debug_backtrace(),true));
while ($field = $meta->fetch_field()) {
$variables[] = &$data[$field->name]; // pass by reference
}
\call_user_func_array([$result, 'bind_result'], $variables);
$i = 0;
while ($result->fetch()) {
$resultsArray[$i] = [];
foreach ($data as $k => $v) {
$resultsArray[$i][$k] = $v;
if ($this->numericIndexes) {
$resultsArray[$i][] = $v;
}
}
unset($k, $v);
$i++;
}
} elseif ($result instanceof \mysqli_result) {
$rowNumber = 0;
while ($row = $result->fetch_assoc()) {
$resultsArray[$rowNumber] = $row;
if ($this->numericIndexes) {
foreach ($row as $numerical) {
$resultsArray[$rowNumber][] = $numerical;
}
unset($numerical);
}
$rowNumber++;
}
$i = 0;
unset($row, $rowNumber);
}
return $resultsArray;
}
从“select”方法调用的数据库类“fetchResult”方法:
/***
* Function for retrieving SQL query data from the Database
* @param $sql string the SQL select query
* @param null $data string|array the data to check in the query with
* @return array|bool|mixed
***/
public function select($sql, $data = null){
/***
* Now prepare the SQL
***/
try {
$query = $this->databaseObject->prepare($sql);
/****
* $query is prepared here....
***/
...
$query->execute();
}
catch (\mysqli_sql_exception $ex) {
$this->exceptionalError($ex);
return false;
}
catch (\Exception $ex) {
$this->exceptionalError($ex);
return false;
}
if (\mb_strtoupper($reduce, "UTF-8") !== "NORETURN") {
if ($query->field_count > 0 ) {
$query->store_result();
}
$this->rowsFound[] = $query->num_rows;
$output = $this->fetchResult($query); // Call to fetch result method
if ($query->field_count > 0) {
$query->free_result();
}
$query->close();
unset($query);
return $output;
}
/***
* NORETURN value so no result to return.
***/
$successValue = $this->rowsAffected[] = $query->affected_rows;
$query->close();
unset($query);
return $successValue;
}
fetchResult
根据更新如何构建此方法的正确解决方法是什么?
(如您所知,我们完全不知道上一个问题,并且它没有出现在任何错误日志中,所以令人惊讶)
解决方案
你打store_result()
了两次电话。你不能那样做。一旦结果在 PHP 中被缓冲,连接线是空闲的 - 没有更多的结果等待获取。第二次调用store_result()
将抛出“不同步”错误。
你先在这里调用它:
if (\mb_strtoupper($reduce, "UTF-8") !== "NORETURN") {
if ($query->field_count > 0 ) {
$query->store_result();
}
然后在这里
private function fetchResult($result)
{
if ($result instanceof \mysqli_stmt) {
$result->store_result(); // This is line 169
删除一种用法,你应该没问题。
我会建议与之合作mysqli_result
。当您调用get_result
它时,它将缓冲结果并为您提供可以使用的熟悉对象。这可以显着简化您的抽象类。
这是我将如何重构这个类:
public function select($sql, $data = null)
{
/***
* Now prepare the SQL
***/
try {
$query = $this->databaseObject->prepare($sql);
/****
* $query is prepared here....
***/
$query->execute();
} catch (\mysqli_sql_exception $ex) {
$this->exceptionalError($ex);
return false;
} catch (\Exception $ex) {
$this->exceptionalError($ex);
return false;
}
$result = $query->get_result();
if (\mb_strtoupper($reduce, "UTF-8") !== "NORETURN") {
$this->rowsFound[] = $result->num_rows;
if ($result) {
return $this->fetchResult($result); // Call to fetch result method
}
}
/***
* NORETURN value so no result to return.
***/
$successValue = $this->rowsAffected[] = $query->affected_rows;
return $successValue;
}
private function fetchResult(mysqli_result $result)
{
return $result->fetch_all($this->numericIndexes ? MYSQLI_BOTH : MYSQLI_ASSOC);
}
推荐阅读
- azure-devops - Azure 虚拟规模集和 MS 托管代理
- apache-spark - 故障转移后如何配置 alb 以指向新的主实例(EMR)
- ios - 此版本的 Realm 不支持打开格式版本 22 的 Realm 文件
- sentry - 我在哪里可以找到 webpack-sentry-plugin 上传的 sourceMap 文件
- azure-functions - Oryx - 找不到框架“Microsoft.NETCore.App”,版本“3.1.0”
- android - RecyclerView 中的 AdjustResize 未按预期工作,自 API 30 (targetSdkVersion 30) 以来将 EditText 隐藏在键盘下方
- python - 根据命令实例化异步 python 模块(discord.py)的不同实例
- python - 为什么我的等值线地图不显示颜色?
- javascript - D3@6 在箭头函数中寻址映射数据结构的通用方向
- python - 我可以在 FastAPI StreamingResponse 中使用线程吗