Собственный index.php в PHP: от простого к сложному
Создание собственного index.php (custom index php)
Основное эффективное решение - использование единой точки входа (front controller) с автоматической загрузкой классов через Composer и маршрутизацию на основе компонента Symfony HttpFoundation или собственного роутера. Такой подход отделяет обработку запроса от логики приложения и облегчает тестирование.
<?php
// index.php - точка входа
require_once __DIR__ . '/../vendor/autoload.php';
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
$request = Request::createFromGlobals();
$uri = $request->getPathInfo();
// Пример простого роутера
$routes = [
'/' => 'homepage',
'/about' => 'aboutPage',
'/contact' => 'contactPage',
];
$handler = $routes[$uri] ?? 'notFound';
switch ($handler) {
case 'homepage':
$response = new Response('<h1 class="fw-bold">Главная</h1>');
break;
case 'aboutPage':
$response = new Response('<h1 class="fw-bold">О нас</h1>');
break;
case 'contactPage':
$response = new Response('<h1 class="fw-bold">Контакты</h1>');
break;
default:
$response = new Response('Страница не найдена', 404);
}
$response->send();Php форматы данных (форматы данных в php (json, xml, serialize))
Этот код подходит для небольших проектов, где нужно быстро начать. Он использует автозагрузку Composer, объекты Request и Response, что делает код более структурированным. Проблемы: при росте числа маршрутов switch становится громоздким. Решение: вынести роутинг в отдельный класс или использовать готовый роутер (например, FastRoute).
Возможные ошибки и их решения:
- Класс Request не найден - проверьте установку пакета symfony/http-foundation через Composer.
- Путь к autoload.php неверен - укажите правильный путь относительно index.php.
- Зацикливание при использовании mod_rewrite - настройте корректно .htaccess.
Как сделать index.php, который обрабатывает все запросы, включая статические файлы?
Для этого в корне проекта располагают файл .htaccess (для Apache) с правилами перезаписи:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [QSA,L]Php null false (null и false в php)
Как сделать простой index.php для статического сайта?
Когда сайт состоит только из HTML и CSS, index.php может просто подключать нужный контент:
<?php
$page = $_GET['page'] ?? 'home';
$allowed = ['home', 'about', 'contact'];
if (!in_array($page, $allowed)) $page = 'home';
include __DIR__ . "/pages/{$page}.html";Php get started (начало работы с php)
Цель: быстрый старт для многостраничного сайта на PHP без базы данных. Проблемы: безопасность - прямое включение файлов по параметру может привести к path traversal. Решение: проверка в белом списке.
Ошибка: передача параметра page=../../etc/passwd. Решение: использовать только разрешенные значения.
Как реализовать маршрутизацию через switch в index.php без сторонних библиотек?
<?php
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
switch ($uri) {
case '/':
$content = '<h1>Главная</h1>';
break;
case '/users':
$content = '<h1>Пользователи</h1>';
break;
default:
http_response_code(404);
$content = '<h1>404</h1>';
}
echo $content;Custom index php (создание собственного index.php)
Подходит для очень маленьких проектов. Недостаток: маршруты смешаны с выводом, сложно добавлять новые.
Как использовать Composer автозагрузку в index.php?
Установите Composer, создайте composer.json с автозагрузкой PSR-4:
{
"autoload": {
"psr-4": {
"App\\": "src/"
}
}
}Php структура данных (изучение структур данных в php)
После composer dump-autoload в index.php подключайте автозагрузку:
<?php
require __DIR__ . '/../vendor/autoload.php';
use App\Router;
$router = new Router();
$router->dispatch();Php добавить переменную (добавление переменной php)
Цель: организовать классы по папкам и подключать их автоматически. Типичная ошибка: неправильный namespace в классе - проверьте соответствие папке.
Как обрабатывать ошибки в index.php?
<?php
error_reporting(E_ALL);
ini_set('display_errors', 0);
set_error_handler(function($severity, $message, $file, $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
});
set_exception_handler(function($e) {
http_response_code(500);
echo '<h1>Внутренняя ошибка сервера</h1>';
// логирование ошибки
error_log($e->getMessage());
});
// остальной кодDefault php file (файл по умолчанию в php)
Проблема: ошибки могут выводиться пользователю при display_errors=1. Решение: в production выключить вывод и использовать лог.
Как сделать index.php для REST API?
<?php
header('Content-Type: application/json');
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$parts = explode('/', trim($uri, '/'));
if ($parts[0] === 'api' && $parts[1] === 'users') {
$userId = $parts[2] ?? null;
if ($method === 'GET' && $userId) {
// получить одного пользователя
echo json_encode(['id' => $userId, 'name' => 'John']);
} elseif ($method === 'GET') {
// список пользователей
echo json_encode([['id' => 1, 'name' => 'John'], ['id' => 2, 'name' => 'Jane']]);
} else {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
}
} else {
http_response_code(404);
echo json_encode(['error' => 'Not found']);
}Php return file (возврат файла из функции в php)
Цель: быстрый API без фреймворка. Ошибка: неверный HTTP-метод - нужно проверять.
Как организовать многосайтовость через index.php?
<?php
$domain = $_SERVER['HTTP_HOST'];
switch ($domain) {
case 'site1.example.com':
$config = require 'config_site1.php';
break;
case 'site2.example.com':
$config = require 'config_site2.php';
break;
default:
http_response_code(404);
exit('Сайт не найден');
}
// Дальнейшая обработка с $config
Подходит для хостинга с несколькими доменами на одном аккаунте. Проблема: утечка конфигурации, если файл не защищен.
Расширенные примеры и редкие случаи использования index.php
Пример 1: index.php с middleware (цепочка обработчиков)
Реализация PSR-15 совместимого middleware вручную:
<?php
require 'vendor/autoload.php';
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Diactoros\Response;
class AuthMiddleware implements \Psr\Http\Server\MiddlewareInterface {
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): \Psr\Http\Message\ResponseInterface {
if (!$request->hasHeader('Authorization')) {
return new Response('Unauthorized', 401);
}
return $handler->handle($request);
}
}
class RouterHandler implements RequestHandlerInterface {
public function handle(ServerRequestInterface $request): \Psr\Http\Message\ResponseInterface {
// ваша логика маршрутизации
return new Response('Hello World', 200);
}
}
$request = Laminas\Diactoros\ServerRequestFactory::fromGlobals();
$middleware = new AuthMiddleware();
$handler = new RouterHandler();
$response = $middleware->process($request, $handler);
// отправка ответа
(new Laminas\HttpHandlerRunner\Emitter\SapiEmitter())->emit($response);
Результат: при отсутствии заголовка Authorization вернёт 401, иначе выполнится роутер.
Пример 2: index.php с динамической загрузкой классов на основе анонимных функций (closure router)
<?php
$routes = [];
$routes['GET']['/'] = function() {
return 'Главная';
};
$routes['GET']['/user/{id}'] = function($id) {
return "Пользователь $id";
};
$method = $_SERVER['REQUEST_METHOD'];
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$matched = false;
foreach ($routes[$method] ?? [] as $pattern => $handler) {
$regex = preg_replace('/\{([a-z]+)\}/', '(?P<$1>[^/]+)', $pattern);
if (preg_match('#^' . $regex . '$#', $uri, $matches)) {
$params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
echo call_user_func_array($handler, $params);
$matched = true;
break;
}
}
if (!$matched) {
http_response_code(404);
echo '404';
}
Результат: GET /user/42 выведет "Пользователь 42".
Пример 3: index.php, использующий Composer скрипты для генерации кэша маршрутов
В composer.json:
{
"scripts": {
"post-autoload-dump": [
"php -r 'file_put_contents(\"routes_cache.php\", \"<?php return [\\\"home\\\" => function(){ return \\\"Cached home\\\"; }];\");'"
]
}
}
После composer dump-autoload создаётся routes_cache.php. В index.php проверяем существование кэша и используем его:
<?php
if (file_exists('routes_cache.php')) {
$routes = require 'routes_cache.php';
if (isset($routes[$_GET['route'] ?? 'home'])) {
echo $routes[$_GET['route']]();
}
} else {
// обычная загрузка маршрутов
}
Результат: ускорение за счёт отсутствия разбора маршрутов каждый раз.
Пример 4: Обработка ошибок с выводом подробного отчёта в dev-режиме
<?php
define('ENV', 'dev');
if (ENV === 'dev') {
error_reporting(E_ALL);
ini_set('display_errors', 1);
} else {
error_reporting(0);
ini_set('display_errors', 0);
}
set_exception_handler(function($e) {
if (ENV === 'dev') {
echo '<pre>' . $e->getMessage() . '\n' . $e->getTraceAsString() . '</pre>';
} else {
http_response_code(500);
echo '<h1>Произошла ошибка, повторите попытку позже</h1>';
error_log($e->getMessage());
}
});
throw new \Exception('Тестовая ошибка');
Результат: в dev-режиме увидим полный трейс, в production - стандартную заглушку.
Пример 5: index.php с поддержкой CORS для AJAX-запросов
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}
// остальная обработка
Результат: браузер не блокирует кросс-доменные запросы.
Пример 6: index.php, который выполняет перенаправление на другой протокол (HTTP -> HTTPS)
<?php
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
$redirectUrl = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('Location: ' . $redirectUrl, true, 301);
exit;
}
// дальнейшая обработка
Результат: все запросы перенаправляются на HTTPS.