Введение: «Ваш логотип не работает, а база данных плачет»
Если вы когда-нибудь писали на PHP скрипт, который работает с MySQL, то наверняка сталкивались с этой пугающей фразой:
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given.
Давайте сразу договоримся: это не конец света. Это всего лишь сигнал от PHP: «Эй, я не могу взять данные из того, что ты мне подсунул!».
В этом туториале мы разберем, почему возникает ошибка mysql_fetch_array() expects parameter 1 to be resource, как её исправить, и самое главное — как перестать её видеть раз и навсегда (спойлер: перейти на PDO или MySQLi).
Статья написана специально для pythonlib.ru — образовательного портала, где мы учим писать код без боли. Поехали!
Почему PHP кричит на параметр? (причины)
Чтобы понять корень зла, вспомним, как работают старые функции mysql_* (да, те, что устарели ещё в PHP 5.5).
Типичный код новичка выглядит так:
// Подключение
$link = mysql_connect('localhost', 'user', 'password');
mysql_select_db('test');
// Запрос (с ошибкой)
$result = mysql_query("SELECT * FROM users WHERE id = '1");
// Попытка прочитать
while($row = mysql_fetch_array($result)) { // Ошибка!
echo $row['name'];
}
Что здесь не так? Всё! Но главное: mysql_query() вернул false, а не ресурс (resource). Почему?
- Синтаксическая ошибка в SQL — кавычка не закрыта.
- Нет подключения к БД —
mysql_connect()вернул false. - Не выбрана база —
mysql_select_db()не сработала. - Таблица не существует.
Когда mysql_query() падает, он возвращает false (логический тип), а не resource. Вы же пытаетесь передать false в mysql_fetch_array(), которая ждет resource. Конфликт! Отсюда и ошибка.
Какие функции страдают?
mysql_fetch_array()mysql_fetch_assoc()mysql_fetch_row()mysql_num_rows()mysql_data_seek()
Все они кричат одно и то же: «expects parameter 1 to be resource».
Пошаговое исправление (для старого кода)
Если у вас легаси-проект, и вы пока не можете обновить PHP (хотя очень советую), вот как отловить и починить ошибку.
Шаг 1. Проверяем соединение
$link = mysql_connect('localhost', 'user', 'password');
if (!$link) {
die('Ошибка соединения: ' . mysql_error());
}
Шаг 2. Проверяем выбор базы
if (!mysql_select_db('my_database')) {
die('Не удалось выбрать БД: ' . mysql_error());
}
Шаг 3. Делаем запрос с проверкой
$sql = "SELECT * FROM users WHERE id = 1";
$result = mysql_query($sql);
if (!$result) {
die('Ошибка запроса: ' . mysql_error());
}
// Теперь можно смело использовать
while($row = mysql_fetch_assoc($result)) {
echo $row['name'];
}
Видите разницу? Мы проверяем каждый шаг. Если mysql_query() вернул false — мы умираем с сообщением об ошибке, а не передаем false дальше.
Почему это всё ещё работает? (исторический контекст)
На Stack Overflow этот вопрос собрав тысячи просмотров. И это неудивительно: до сих пор на многих хостингах крутится PHP 5.x, и куча учебников (даже на YouTube) учат через mysql_*.
Но запомните раз и навсегда: расширение mysql устарело и удалено из PHP 7.0. Если вы пишете новый код — используйте mysqli или PDO.
Современное решение: переходим на PDO
PDO (PHP Data Objects) — это современный, безопасный и удобный способ работы с базами данных. Он поддерживает подготовленные запросы (защита от SQL-инъекций) и не страдает от описанной выше ошибки (потому что использует объекты, а не ресурсы).
Пример правильного кода на PDO
<?php
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8';
$user = 'root';
$password = '';
try {
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die('Ошибка подключения: ' . $e->getMessage());
}
// Подготовленный запрос
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => 1]);
// Получаем данные
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'];
}
Обратите внимание: ни единого вызова mysql_fetch_array(). Всё чисто, объектно-ориентированно, и никаких «expects parameter 1 to be resource».
Как правильно переписать старый код?
Если у вас есть проект на mysql_*, вот минимальный план миграции:
- Заменить
mysql_connect()наnew PDO(). - Заменить
mysql_query()на$pdo->query()илиprepare(). - Заменить
mysql_fetch_array()на$stmt->fetch(). - Заменить
mysql_num_rows()на$stmt->rowCount()(но осторожно — с SELECT не всегда работает).
Да, это потребует времени. Но поверьте: один раз переписать — и забыть об ошибках навсегда.
Частые вопросы (FAQ по ошибке)
1. Я проверил подключение, но ошибка всё равно есть
Проверьте регистр имён таблиц и полей. На Linux MySQL чувствителен к регистру. Если таблица называется Users, а вы пишете users — зап