Конфигурация подключения к БД в PHP: от основ до сложных решений
Способы конфигурации подключения к базе данных в PHP
Основное решение: использование PDO с файлом config.php
Современный подход предполагает применение PDO (PHP Data Objects) и хранение параметров подключения в отдельном конфигурационном файле. Файл config.php возвращает массив с настройками, а класс Database обеспечивает единую точку доступа к соединению. Это даёт гибкость, безопасность и удобство тестирования.
Цель: централизованное управление параметрами БД, поддержка разных СУБД, защита от SQL-инъекций через подготовленные запросы.
Пример файла config.php:
<?php
return [
'driver' => 'mysql',
'host' => 'localhost',
'dbname' => 'myapp',
'username' => 'dbuser',
'password' => 'secret',
'charset' => 'utf8mb4',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false,
],
];
Moodle config php (php: конфигурация moodle (config.php))
Класс-обёртка для подключения:
<?php
class Database
{
private static ?PDO $instance = null;
public static function getInstance(): PDO
{
if (self::$instance === null) {
$config = require __DIR__ . '/config.php';
$dsn = sprintf(
'%s:host=%s;dbname=%s;charset=%s',
$config['driver'],
$config['host'],
$config['dbname'],
$config['charset']
);
self::$instance = new PDO($dsn, $config['username'], $config['password'], $config['options']);
}
return self::$instance;
}
}
Phpmyadmin config inc php (php: конфигурация phpmyadmin (config.inc.php))
Использование:
$pdo = Database::getInstance();
$stmt = $pdo->query('SELECT id, name FROM users');
while ($row = $stmt->fetch()) {
echo htmlspecialchars($row['name']) . "<br>";
}
Config config php домен (php: настройка конфигурации для домена)
Типичная ошибка: "could not find driver"
Возникает, если в системе не установлен драйвер PDO для используемой СУБД (например, pdo_mysql). Решение: установить расширение через менеджер пакетов или php.ini. Для MySQL в Ubuntu: sudo apt install php-mysql, затем перезапустить веб-сервер.
Другая проблема: неверные параметры подключения. Проверка: var_dump($config); убедиться, что массив содержит все ключи.
Как подключиться к базе данных через MySQLi с конфигурационным файлом?
MySQLi – альтернативный расширение с поддержкой процедурного и объектно-ориентированного стиля. Параметры можно хранить в константах или массиве.
Цель: использование, если проект завязан на эксклюзивных функциях MySQLi или требуется работа с асинхронными запросами.
<?php
define('DB_HOST', 'localhost');
define('DB_USER', 'root');
define('DB_PASS', 'password');
define('DB_NAME', 'app');
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME);
if ($mysqli->connect_error) {
die('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
}
// Работа с БД
$mysqli->close();
Wp admin config php (php: конфигурация wordpress (wp-admin/config.php))
Вариант с файлом config.php, возвращающим массив:
$config = require 'config.php';
$mysqli = new mysqli($config['host'], $config['username'], $config['password'], $config['dbname']);
Config php host (php: настройка host в конфигурационном файле)
Ошибка: "Connection refused" или "No such file or directory"
Причина: неверный host или порт. Для сокета MySQL укажите 'localhost' или полный путь к сокету. Для TCP-соединения используйте '127.0.0.1' и порт 3306. Решение: проверить настройки сервера MySQL и параметры в config.
Как использовать устаревшее расширение mysql_* (для справки)?
Функции mysql_connect(), mysql_select_db() и другие удалены из PHP 7.0. Их нельзя применять в новых проектах, но в старых кодовых базах они ещё встречаются.
Цель: миграция legacy-кода на современные драйверы.
$link = mysql_connect('localhost', 'user', 'pass');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb', $link);
$result = mysql_query('SELECT * FROM users', $link);
while ($row = mysql_fetch_assoc($result)) {
echo $row['name'] . "<br>";
}
Config ini php (php: настройка php.ini)
Ошибка: "Call to undefined function mysql_connect()"
Решение: обновить код на PDO или MySQLi. Другого пути нет - расширение более не поддерживается.
Как хранить параметры подключения в .env файле?
Использование библиотеки vlucas/phpdotenv позволяет изолировать конфиденциальные данные от кода. Файл .env не попадает в репозиторий.
Цель: повышение безопасности, удобство деплоя на разных окружениях.
# .env
DB_HOST=localhost
DB_NAME=app
DB_USER=root
DB_PASS=secret
DB_DRIVER=mysql
Php config connect (php: настройка подключения к базе данных в config)
<?php
require 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();
$dsn = $_ENV['DB_DRIVER'] . ':host=' . $_ENV['DB_HOST'] . ';dbname=' . $_ENV['DB_NAME'];
$pdo = new PDO($dsn, $_ENV['DB_USER'], $_ENV['DB_PASS']);
Define config php (php: определение констант через define в конфигурации)
Ошибка: "The environment file is not valid"
Причина: нарушен синтаксис .env (пробелы вокруг знака =, кавычки). Решение: проверить формат, каждая строка КЛЮЧ=значение без лишних пробелов.
Как настроить подключение через переменные окружения сервера?
Переменные окружения устанавливаются на уровне ОС или веб-сервера (например, в Apache SetEnv). PHP получает их через getenv() или суперглобальный массив $_SERVER.
Цель: нулевая конфигурация в коде, параметры задаются окружением.
<?php
$host = getenv('DB_HOST') ?: 'localhost';
$db = getenv('DB_NAME') ?: 'default';
$user = getenv('DB_USER') ?: 'root';
$pass = getenv('DB_PASS') ?: '';
$pdo = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
Проблема: переменные не определены, возвращают false
Проверьте, что переменные установлены в конфигурации сервера. Для CLI: export DB_HOST=.... Для Apache: директивы SetEnv в .htaccess или VirtualHost. Для Nginx: FastCGI параметры.
Как организовать единое подключение через паттерн Singleton?
Паттерн гарантирует, что в приложении существует только один экземпляр соединения. Реализация показана в основном решении (rbase). Вариант с ручной передачей конфига:
class DatabaseSingleton
{
private static ?PDO $pdo = null;
public static function connect(array $config): PDO
{
if (self::$pdo === null) {
$dsn = "{$config['driver']}:host={$config['host']};dbname={$config['dbname']}";
self::$pdo = new PDO($dsn, $config['user'], $config['pass'], $config['opts'] ?? []);
}
return self::$pdo;
}
}
Цель: избежать множественных соединений, экономия ресурсов.
Проблема: тестирование становится сложным, так как состояние статическое
Решение: использовать внедрение зависимостей (DI-контейнер) вместо Singleton, чтобы соединение передавалось явно. Если же Singleton необходим, предусмотреть метод сброса для тестов: resetInstance().
Расширенные примеры настройки и использования подключения к БД
Пример 1: Конфигурационный файл с поддержкой окружений
Файл config.php может определять настройки в зависимости от среды (development/production).
<?php
$env = getenv('APP_ENV') ?: 'development';
$config = [
'development' => [
'host' => 'localhost',
'dbname' => 'dev_db',
'user' => 'dev',
'pass' => 'dev',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => true,
],
],
'production' => [
'host' => 'db.example.com',
'dbname' => 'prod_db',
'user' => 'prod_user',
'pass' => 'prod_pass',
'options' => [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false,
],
],
];
return $config[$env];
Результат: при вызове require 'config.php' возвращается массив, соответствующий окружению.
Пример 2: Класс Database с методами для транзакций и пагинации
<?php
class AdvancedDatabase
{
private PDO $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
public function beginTransaction(): void
{
$this->pdo->beginTransaction();
}
public function commit(): void
{
$this->pdo->commit();
}
public function rollback(): void
{
$this->pdo->rollBack();
}
public function fetchPage(string $table, int $page, int $perPage): array
{
$offset = ($page - 1) * $perPage;
$stmt = $this->pdo->prepare("SELECT * FROM $table LIMIT :limit OFFSET :offset");
$stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
$stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}
}
$db = new AdvancedDatabase(Database::getInstance());
$users = $db->fetchPage('users', 1, 10);
print_r($users);
Результат: вывод массива из 10 записей таблицы users, начиная с первой страницы.
Пример 3: Обработка ошибок с логированием
<?php
function connectWithErrorHandling(): PDO
{
try {
$config = require 'config.php';
$dsn = "{$config['driver']}:host={$config['host']};dbname={$config['dbname']}";
$pdo = new PDO($dsn, $config['username'], $config['password'], $config['options']);
return $pdo;
} catch (PDOException $e) {
// Логирование в файл
error_log("Database connection failed: " . $e->getMessage(), 3, '/var/log/php_errors.log');
// Пользователю показываем общее сообщение
die('Извините, произошла ошибка базы данных. Пожалуйста, попробуйте позже.');
}
}
try {
$pdo = connectWithErrorHandling();
$stmt = $pdo->query('SELECT 1');
echo "Соединение установлено";
} catch (Exception $e) {
echo "Не удалось выполнить запрос";
}
Результат: если соединение не удалось, в лог записывается детальная ошибка, а пользователь видит общее сообщение.
Пример 4: Использование разных драйверов PDO (SQLite, PostgreSQL)
<?php
$drivers = [
'sqlite' => 'sqlite:/path/to/database.sqlite',
'pgsql' => 'pgsql:host=localhost;dbname=mydb',
'mysql' => 'mysql:host=localhost;dbname=mydb',
];
$driver = 'sqlite'; // можно менять
$pdo = new PDO($drivers[$driver], $driver === 'sqlite' ? null : 'user', $driver === 'sqlite' ? null : 'pass');
$stmt = $pdo->query('SELECT sqlite_version()');
$row = $stmt->fetch(PDO::FETCH_NUM);
echo "Версия SQLite: " . $row[0];
Результат: Версия SQLite: 3.31.1 (зависит от установленной версии).
Пример 5: Работа с пулом соединений через многократный вызов getInstance
<?php
$pdo1 = Database::getInstance();
$pdo2 = Database::getInstance();
var_dump($pdo1 === $pdo2); // bool(true)
// Доказательство единого подключения
$stmt = $pdo1->prepare('SELECT ? + ? AS sum');
$stmt->execute([10, 20]);
echo $stmt->fetchColumn(); // 30
Результат: на экран выводится bool(true) и 30.