Mysqli_stmt::execute(): преждевременный EOF в метаданных поля результата

Я пишу PHP-приложение, используя MySQLi. Во время работы этого приложения я последовательно готовлю множество подготовленных операторов SQL, а затем выполняю их по мере необходимости на протяжении всей работы приложения.

Однако когда я дважды запускаю один и тот же конкретный оператор в своем приложении (с определенными параметрами), я получаю следующую ошибку: mysqli_stmt::execute(): Premature EOF in result field metadata.

Чтобы еще больше прояснить мою проблему, я прилагаю минимальный воспроизводимый пример моего кода. Во-первых, моя база данных содержит хранимую процедуру под названием GET_USER_ID_FROM_USERNAME. Это точно так, как следует из названия: в качестве параметра принимает строковое имя пользователя, проверяет, существует ли это имя пользователя, а затем возвращает два значения: логическое значение с меткой User_Exists, чтобы проверить, известно ли имя пользователя в базе данных, и (если первое true ) целое число с меткой ID. Вот код этой процедуры:

CREATE PROCEDURE GET_USER_ID_FROM_USERNAME (IN Username_Param TINYTEXT CHARSET utf8mb4)
BEGIN
    IF ((SELECT COUNT(1) FROM Users WHERE Username = Username_Param) = 1) THEN
    SELECT ID, TRUE AS User_Exists FROM Users WHERE Username = Username_Param;
    ELSE
    SELECT FALSE AS User_Exists;
    END IF;
END

Это работает именно так, как я хочу: когда я передаю известное имя пользователя, оно возвращает true в столбце User_Exists и ID соответствующего пользователя в одноименном столбце, а когда я передаю имя пользователя, которого нет в базе данных, оно возвращает false в столбце User_Exists.

Проблема возникает, когда я вызываю эту процедуру дважды (даже если между ними я вызываю другие процедуры), и только когда в первый раз это существующее имя пользователя, а во второй раз неизвестное (т. е. когда значение User_Exists равно true в первый раз, но false второй). Я вызываю эту процедуру, используя подготовленный оператор, к которому привязываю желаемое имя пользователя.

Вот минимальный пример кода, который выдает желаемую ошибку:

// CONNECT
$mysqli = new mysqli("localhost", "root", "root", "test_database");
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$mysqli->autocommit(false);
$mysqli->set_charset('utf8mb4');

// PREPARE STATEMENT
$stmt = $mysqli->prepare("CALL GET_USER_ID_FROM_USERNAME (?);");

// BIND PARAMETER
$username = "";
$stmt->bind_param("s", $username);

// EXECUTE WITH KNOWN VALUE
$username = "Existing_Username";
$stmt->execute();
// Flush result (if I exclude this I get a "commands out of sync" error)
$stmt->get_result();
$mysqli->next_result();

// All fine so far

// EXECUTE WITH UNKNOWN VALUE
$username = "Fake_Username";
$stmt->execute(); // <- Error thrown here: mysqli_stmt::execute(): Premature EOF in result field metadata

Эта (и только эта) конфигурация, в которой первое имя пользователя известно, а второе нет, выдает ошибку. Если оператор вызывается только один раз с известным или неизвестным именем пользователя, он возвращает то, что я ожидаю. Если оператор сначала вызывается с известным именем пользователя, а затем с другим известным именем пользователя, он также возвращает то, что я ожидаю.

Поиск сообщения об ошибке Premature EOF in result field metadata не дал результатов. Если кто-то знает, как и почему появляется это сообщение, или имеет представление о том, что я делаю не так с моим кодом, я был бы благодарен узнать!

Это таблица Users, которую я настроил для целей этого примера:

CREATE TABLE Users (
  ID BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, 
  Username TINYTEXT NOT NULL,
  Pass_Hash TINYTEXT NOT NULL
);

Строки:

ID   -   Username      -     Pass_Hash
------------------------------------------------------------------------------------------
1        Existing_Username   $2y$10$l8y.GEK3LFnLyJWhAmHdg.7lMb45SezorBDODrqWUq4M0K1P3rDCq

(Pass_Hash равен Password1, хеширован).

Установка, на которой я это запускаю:

МАМП в Windows

PHP 8.1.0

MySQL 5.7.24

Я не могу воспроизвести это с помощью PHP 8.2 и MariaDB 10.4.

Dharman 24.02.2024 20:26

По таким вопросам было бы хорошо, если бы вы могли воспроизвести их на phpize.online

Dharman 24.02.2024 21:11

Дело в том, что «Преждевременный EOF в метаданных поля результата» — это ошибка mysqlnd, которая НИКОГДА не должна происходить. Очень странно, что вам каким-то образом удалось получить эту ошибку. Тем более, что вы используете не такие уж старые версии PHP и MySQL.

Dharman 24.02.2024 21:13

Мне не удалось воспроизвести это на phpize.online - продолжим попытки, но, конечно, от этого не будет много толку, если это действительно проблема, специфичная для платформы. И очень странно, что вы говорите, что этого никогда не должно произойти - разве раньше такое вообще не встречалось?

user9214088 24.02.2024 21:23

На данный момент я бы назвал MySQL 5.7 довольно старой... В любом случае моим первым шагом было бы обновление PHP до последней версии 8.1. Возможно, вы также посмотрите, работает ли он без параметров привязки. Просто передайте их как массив для выполнения метода. Также вы вызываете хранимую процедуру; ошибка возникает при обычном операторе?

miken32 24.02.2024 21:31

В MySQL 8.4 метод подготовки также выдал мне исключение «Преждевременный EOF в метаданных поля результата». MySQL 9 исправил это.

Adam 04.07.2024 09:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
1
6
156
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это ошибка в PHP, и она исправлена ​​в PHP 8.1.23 и 8.2.10

Вот пиар https://github.com/php/php-src/pull/11551

Я убедился, что это одна и та же ошибка, несмотря на то, что описание ошибки немного отличается.


Как видите, о проблеме сообщалось и раньше, хотя и с другими симптомами. Я предполагаю, что не многие люди сталкиваются с этой проблемой, потому что то, что вы делаете, довольно необычно. Хранимые процедуры обычно не используются из кода PHP, а если и используются, то обычно выполняются только один раз. Нередко можно выполнить хранимую процедуру несколько раз с использованием подготовленного оператора, но это довольно редкий случай.

Весьма признателен. Считается ли плохой практикой запуска хранимых процедур в PHP с использованием подготовленных операторов? В настоящее время я часто делаю это в своем приложении и теперь беспокоюсь, не повлияет ли это на скорость/эффективность и т. д. Я считал, что это более безопасно (поскольку весь мой фактический код SQL предварительно написан в реальной базе данных), но Я удивлен, узнав, что это не распространено.

user9214088 25.02.2024 01:12

@ Брайан Я бы не сказал, что это плохая практика. Это просто очень громоздко и без каких-либо преимуществ. Хранимые процедуры следует использовать для сложных операций, выполняемых администратором базы данных непосредственно на сервере. Использование SP в PHP не имеет особого смысла. Вы можете просто выполнять те же запросы прямо из PHP. Это не повышает безопасность, а если вы сделаете это неправильно, это может даже ухудшить безопасность. Сложность — враг безопасности. SP также скрывают от разработчика PHP реальную логику, что затрудняет написание кода на PHP.

Dharman 25.02.2024 08:19

Другие вопросы по теме