Основы файла index.php в учебных проектах PHP
Основной подход: учебный index.php как точка входа
Учебная версия index.php обычно служит единой точкой входа для всего приложения. В самом простом случае файл принимает запрос, анализирует параметры и подключает нужные компоненты. Ниже приведён базовый шаблон, который подходит для первого знакомства с PHP.
<?php
// index.php – учебная точка входа
$page = $_GET['page'] ?? 'home';
$allowed = ['home', 'about', 'contact'];
if (!in_array($page, $allowed)) {
$page = 'home';
}
$title = ucfirst($page);
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title><?= $title ?></title>
</head>
<body>
<h1><?= $title ?></h1>
<?php include "pages/{$page}.php"; ?>
</body>
</html>Index php учебная (учебная версия index.php)
Пояснение: переменная $page получает значение из GET-параметра page. Если параметр отсутствует или содержит недопустимое значение, используется страница 'home'. Затем подключается соответствующий файл из папки pages. Такой подход позволяет легко добавлять новые страницы без изменения основного файла.
Типичные ошибки и их устранение
- Ошибка include: если файл pages/ошибка.php не существует, PHP выдаст предупреждение. Рекомендуется использовать include_once или проверять файл функцией file_exists.
- Относительные пути: при вложенных вызовах include может произойти путаница с путями. Лучше задавать абсолютный путь через __DIR__.
- Уязвимость LFI: если параметр page может содержать пути вроде `../../etc/passwd`, злоумышленник сможет прочитать системные файлы. Всегда проверяйте значение по белому списку.
Как организовать простую маршрутизацию без фреймворка?
Второй распространённый вариант – использование конструкции switch для прямого сопоставления URI с кодом. Это удобно, когда страниц мало и каждая требует разной логики.
<?php
$uri = $_SERVER['REQUEST_URI'];
$uri = parse_url($uri, PHP_URL_PATH); // очищаем от GET-параметров
switch ($uri) {
case '/':
echo 'Главная страница';
break;
case '/about':
echo 'О нас';
break;
case '/contact':
echo 'Контакты';
break;
default:
http_response_code(404);
echo 'Страница не найдена';
break;
}Здесь $_SERVER['REQUEST_URI'] содержит путь, а функция parse_url отбрасывает параметры. Каждый case отвечает за свой маршрут. Ветка default обрабатывает ошибку 404.
Возможные проблемы
- Дублирование кода при большом количестве маршрутов – switch становится громоздким.
- Не учитываются POST-запросы и методы HTTP. Для этого нужна дополнительная проверка $_SERVER['REQUEST_METHOD'].
- Если используется вложенная директория, например /blog/post, потребуется разбивать URI на сегменты.
Как включить содержимое разных страниц через include?
Третий вариант – использовать include с динамическим именем файла, но с защитой от подмены. В отличие от первого варианта, здесь нет шаблона HTML – каждый подключаемый файл сам выводит всю структуру.
<?php
$action = isset($_GET['action']) ? basename($_GET['action']) : 'home';
$file = __DIR__ . '/inc/' . $action . '.php';
if (file_exists($file)) {
include $file;
} else {
include __DIR__ . '/inc/404.php';
}Функция basename удаляет все возможные пути, оставляя только имя файла – это защита от атак. Константа __DIR__ даёт абсолютный путь к текущей директории, исключая путаницу с относительными путями.
Распространённые ошибки
- Использование пользовательского ввода без очистки – возможно внедрение кода через include.
- Забыли проверить file_exists – получите ошибку включения несуществующего файла.
- В подключаемых файлах могут быть объявлены функции, которые уже определены – используйте include_once для предотвращения повторного включения.
Как обрабатывать POST-запросы в том же index.php?
Часто один и тот же файл должен обслуживать и отображение страниц, и обработку форм. Для этого отделяют логику по методу запроса.
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// обработка формы
$name = htmlspecialchars($_POST['name'] ?? '');
if ($name) {
$message = "Привет, $name!";
} else {
$message = 'Имя не введено';
}
}
?>
<!DOCTYPE html>
<html>
<head><title>Обработка формы</title></head>
<body>
<?php if (isset($message)): ?>
<p><?= $message ?></p>
<?php endif; ?>
<form method="post">
<input type="text" name="name">
<button type="submit">Отправить</button>
</form>
</body>
</html>Здесь проверка $_SERVER['REQUEST_METHOD'] определяет, нужно ли обрабатывать данные. После обработки результат выводится в той же HTML-обёртке. Такой подход прост, но при росте проекта лучше разделять логику и представление.
Замечания по безопасности
- Всегда используйте htmlspecialchars для вывода данных, переданных пользователем.
- Проверяйте источник POST-запроса (например, CSRF-токены) для критических действий.
- Не делайте die() после обработки без перенаправления, чтобы избежать повторной отправки формы при обновлении страницы.
Расширенные примеры и нестандартные сценарии
Ниже представлены более сложные варианты учебного index.php, которые помогут углубить понимание маршрутизации, безопасности и работы с сессиями.
Пример 1: Маршрутизация с поддержкой ЧПУ через .htaccess
Чтобы в index.php получать «красивые» URL (например, /about вместо /index.php?page=about), используется веб-серверный модуль mod_rewrite и файл .htaccess.
# .htaccess в корне
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]<?php
// index.php с роутером на основе REQUEST_URI
$request = $_SERVER['REQUEST_URI'];
$path = parse_url($request, PHP_URL_PATH);
$routes = [
'/' => 'home',
'/about' => 'about',
'/contact' => 'contact',
'/blog' => 'blog_list',
'/blog/(\d+)' => 'blog_show',
];
$matched = false;
foreach ($routes as $pattern => $handler) {
$pattern = '/^' . str_replace('/', '\/', $pattern) . '$/';
if (preg_match($pattern, $path, $matches)) {
$matched = true;
// Передаём захваченные параметры (например, ID поста)
array_shift($matches);
include "handlers/{$handler}.php";
break;
}
}
if (!$matched) {
http_response_code(404);
include 'handlers/404.php';
}Результат: при запросе /blog/42 будет подключён файл handlers/blog_show.php, а в переменной $matches[0] окажется '42'.
Пример 2: Использование autoload для классов в учебном проекте
Современный PHP использует автозагрузку. Даже в учебной версии index.php можно применить spl_autoload_register, чтобы не писать require для каждого класса.
<?php
spl_autoload_register(function ($class) {
$prefix = 'App\\';
$base_dir = __DIR__ . '/src/';
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
$relative_class = substr($class, $len);
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
if (file_exists($file)) {
require $file;
}
});
use App\Controllers\HomeController;
$controller = new HomeController();
echo $controller->index();Предположим, класс App\Controllers\HomeController лежит в файле src/Controllers/HomeController.php. Тогда при первом обращении к классу он будет автоматически загружен.
Пример 3: Работа с сессиями и редиректами
Учебный index.php часто используется для управления сессиями (логин, корзина). Важно корректно начинать сессию до любого вывода.
<?php
session_start();
$action = $_GET['action'] ?? 'login';
if ($action === 'logout') {
session_destroy();
header('Location: index.php');
exit;
}
if ($_SERVER['REQUEST_METHOD'] === 'POST' && $action === 'login') {
$user = $_POST['user'] ?? '';
if ($user === 'admin') {
$_SESSION['user'] = $user;
header('Location: index.php?action=profile');
exit;
} else {
$error = 'Неверное имя';
}
}
?>
<?php if (isset($_SESSION['user'])): ?>
<p>Привет, <?= htmlspecialchars($_SESSION['user']) ?>!</p>
<a href="index.php?action=logout">Выйти</a>
<?php else: ?>
<?php if (isset($error)) echo "<p class='error'>$error</p>"; ?>
<form method="post" action="index.php?action=login">
<input type="text" name="user">
<button>Войти</button>
</form>
<?php endif; ?>Результат: после успешного входа пользователь перенаправляется на страницу профиля. Использование header() и exit предотвращает выполнение кода после редиректа.
Пример 4: Буферизация вывода для перехвата контента
Иногда нужно собрать весь вывод в переменную, например, для отправки email или создания PDF. В index.php можно использовать буферизацию.
<?php
ob_start(); // включение буферизации
?>
<h1>Страница</h1>
<p>Текст, который будет захвачен.</p>
<?php
$content = ob_get_clean(); // получение и очистка буфера
// теперь $content содержит весь HTML
file_put_contents('cache/page.html', $content); // пример записи в файл
echo $content; // и вывод на экранРезультат: в файл cache/page.html будет сохранён сгенерированный HTML. Этот приём полезен для кэширования или при работе с шаблонизаторами.