Глиф Учебники

Урок 7. Файлы и подключение: include и require

Курс «PHP» · урок 7 из 10 · 4 минуты чтения

У сайта много страниц, но шапка, меню и подвал на них одинаковые. Копировать их в каждый файл — плохая идея: правка меню превратится в правку двадцати файлов. В PHP общие части выносят в отдельные файлы и подключают командой require.

Сайт из частей

Файл header.php — начало каждой страницы:

PHP
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title><?= htmlspecialchars($title) ?></title>
</head>
<body>
<nav><a href="/">Главная</a> · <a href="/about.php">О сайте</a></nav>

Файл footer.php — конец:

PHP
<footer>© <?= date('Y') ?></footer>
</body>
</html>

Страница index.php задаёт заголовок и подключает обе части:

PHP
<?php
$title = 'Главная';
require __DIR__ . '/header.php';
?>
<h1>Добро пожаловать</h1>
<p>Текст главной страницы.</p>
<?php require __DIR__ . '/footer.php'; ?>

Подключённый файл выполняется так, будто его текст вставлен на место require. Поэтому header.php видит переменную $title из index.php. Страница about.php устроена так же, только со своим заголовком и текстом.

index.php <?php $title = 'Главная'; require __DIR__ . '/header.php'; ?> <h1>Добро пожаловать</h1> <p>Текст главной страницы.</p> <?php require __DIR__ . '/footer.php'; ?> Страница в браузере из header.php <title>Главная</title> Главная · О сайте Добро пожаловать Текст главной страницы. из footer.php © текущий год
Страница index.php собирается из трёх частей: шапка из header.php с заголовком из $title, свой текст и подвал из footer.php — браузер получает их одной страницей.

include, require и _once

КомандаЕсли файла нетЕсли файл уже подключён
includeпредупреждение, программа идёт дальшеподключит ещё раз
requireфатальная ошибка, программа остановитсяподключит ещё раз
include_onceпредупреждениене подключит повторно
require_onceфатальная ошибкане подключит повторно

Почти всегда нужен require: без шапки или настроек страница всё равно не заработает, и лучше сразу увидеть ошибку. Файлы с функциями и классами подключают через require_once — повторное объявление функции вызвало бы ошибку Cannot redeclare.

Зачем __DIR__

__DIR__ — встроенная константа: папка, где лежит текущий файл. Путь от __DIR__ одинаково работает отовсюду:

PHP
<?php
require __DIR__ . '/inc/functions.php';
require __DIR__ . '/../config.php';

Вторая строка подключает файл из папки уровнем выше.

Без __DIR__ путь легко сломать. Путь вроде require 'inc/menu.php' PHP ищет не от папки файла, а по списку папок include_path и от текущей рабочей папки. Пути с ./ и ../ — только от рабочей папки. Рабочая папка — та, из которой запущен скрипт, и она не всегда совпадает с папкой файла. Особенно часто путаница случается, когда файлы подключают друг друга из разных папок.

require __DIR__ . '/inc/functions.php'; require __DIR__ . '/../config.php'; site/ config.php public/ __DIR__ index.php текущий файл inc/ functions.php Путь считается от __DIR__ /inc/ — вниз, в папку inc /.. — на уровень выше Рабочая папка (откуда запущен скрипт) может быть другой, а путь от __DIR__ от неё не зависит.
Для index.php в папке public __DIR__ — это public: путь '/inc/functions.php' ведёт от неё в папку inc, а '/../config.php' — на уровень выше, к config.php в папке site.

На Linux-сервере в именах файлов важен регистр: Header.php и header.php — разные файлы. В Windows они совпадают, поэтому ошибка часто всплывает только после выкладки сайта на хостинг.

Файл настроек

Подключённый файл может вернуть значение через return. Так удобно хранить настройки:

PHP
<?php
return [
    'db_host' => 'localhost',
    'db_name' => 'shop',
    'per_page' => 20,
];

Если это файл config.php, настройки читаются одной строкой:

PHP
<?php
$config = require __DIR__ . '/config.php';
echo $config['per_page'];

Файлы с паролями держите вне папки, которую видно из интернета, и не добавляйте их в публичные репозитории.

Чтение и запись файлов

Простые операции делаются одной функцией:

PHP
<?php
$file = __DIR__ . '/notes.txt';
file_put_contents($file, "Первая строка\n");
file_put_contents($file, "Вторая строка\n", FILE_APPEND);
echo file_get_contents($file);
$lines = file($file, FILE_IGNORE_NEW_LINES);
echo count($lines) . "\n";
Вывод
Первая строка
Вторая строка
2

Если в файл одновременно пишут несколько посетителей, добавьте блокировку: FILE_APPEND | LOCK_EX. Тогда записи не перемешаются.

Большой файл (журнал на сотни мегабайт) целиком в память не читают, а идут по строкам:

PHP
<?php
$handle = fopen(__DIR__ . '/notes.txt', 'r');
if ($handle === false) {
    exit("Файл не открылся\n");
}
while (($line = fgets($handle)) !== false) {
    echo mb_strtoupper(trim($line)) . "\n";
}
fclose($handle);

fopen открывает файл ('r' — для чтения, 'w' — для записи с очисткой, 'a' — для дописывания), fgets читает очередную строку и возвращает false в конце файла, fclose закрывает файл.

Проверить, есть ли файл, — file_exists($path) или is_file($path); удалить — unlink($path); создать папку — mkdir($path).

Права на сервере

На Linux-сервере PHP работает от имени пользователя веб-сервера (в Ubuntu и Debian это обычно www-data). Если у него нет права писать в папку, запись закончится предупреждением Failed to open stream: Permission denied. Дайте право на запись только той папке, куда сайт действительно пишет (например, data или uploads), а не всему сайту.

Опасно: имя файла из адреса

Никогда не подключайте файл по имени, пришедшему от посетителя: include $_GET['page'];. Подставив в адрес ../ и другие пути, злоумышленник заставит сайт выполнить чужой PHP-файл или показать любой файл сервера, который может прочитать PHP, — например, настройки с паролями.

Безопасный способ — список разрешённых страниц:

PHP
<?php
$pages = [
    'home' => 'home.php',
    'about' => 'about.php',
    'contacts' => 'contacts.php',
];
$page = $_GET['page'] ?? 'home';
if (!isset($pages[$page])) {
    http_response_code(404);
    $page = 'home';
}
require __DIR__ . '/pages/' . $pages[$page];

Посетитель выбирает только ключ, а имя файла берётся из списка, который составили вы.

Имя файла из адреса include $_GET['page']; в адресе: ?page=../config.php подключится любой файл — даже настройки с паролями Список разрешённых 'home' => 'home.php', 'about' => 'about.php', 'contacts' => 'contacts.php', $pages ?page=about pages/about.php ?page=../config.php такого ключа нет — код 404 и home.php
Если подключать файл по имени из адреса, ?page=../config.php подключит любой файл; со списком $pages адрес ?page=about открывает pages/about.php, а неизвестный ключ даёт код 404 и home.php.

Частые ошибки

Коротко

Проверьте себя

1. Чем require отличается от include?
2. Что содержит константа __DIR__?
3. Как дописать строку в конец файла, не стирая его?
4. Почему опасна строка include $_GET['page'];?