183 lines
6.7 KiB
PHP
Executable File
183 lines
6.7 KiB
PHP
Executable File
<?php
|
||
// index.php - единая точка входа
|
||
require_once 'config/config.php';
|
||
|
||
// Получаем путь к запрашиваемому ресурсу
|
||
$requestUri = $_SERVER['REQUEST_URI'];
|
||
$requestPath = parse_url($requestUri, PHP_URL_PATH);
|
||
|
||
// Убираем базовый URL (SITE_URL) из пути
|
||
$basePath = parse_url(SITE_URL, PHP_URL_PATH) ?? '';
|
||
if ($basePath && strpos($requestPath, $basePath) === 0) {
|
||
$requestPath = substr($requestPath, strlen($basePath));
|
||
}
|
||
|
||
// Убираем ведущий слеш
|
||
$requestPath = ltrim($requestPath, '/');
|
||
|
||
// Проверяем, существует ли запрашиваемый файл
|
||
$physicalPath = __DIR__ . '/' . $requestPath;
|
||
if (file_exists($physicalPath) && !is_dir($physicalPath) && !str_contains($physicalPath, '..')) {
|
||
// Определяем MIME-тип
|
||
$mimeTypes = [
|
||
'css' => 'text/css',
|
||
'js' => 'application/javascript',
|
||
'png' => 'image/png',
|
||
'jpg' => 'image/jpeg',
|
||
'jpeg' => 'image/jpeg',
|
||
'gif' => 'image/gif',
|
||
'webp' => 'image/webp',
|
||
'svg' => 'image/svg+xml',
|
||
'ico' => 'image/x-icon',
|
||
'json' => 'application/json',
|
||
'woff' => 'font/woff',
|
||
'woff2' => 'font/woff2',
|
||
'ttf' => 'font/ttf',
|
||
'eot' => 'application/vnd.ms-fontobject',
|
||
];
|
||
|
||
$extension = strtolower(pathinfo($physicalPath, PATHINFO_EXTENSION));
|
||
if (isset($mimeTypes[$extension])) {
|
||
header('Content-Type: ' . $mimeTypes[$extension]);
|
||
}
|
||
|
||
// Запрещаем кэширование для разработки, в продакшене можно увеличить время
|
||
header('Cache-Control: public, max-age=3600');
|
||
|
||
// Отправляем файл
|
||
readfile($physicalPath);
|
||
exit;
|
||
}
|
||
// Простой роутер
|
||
class Router {
|
||
private $routes = [];
|
||
|
||
public function add($pattern, $handler) {
|
||
$this->routes[$pattern] = $handler;
|
||
}
|
||
|
||
public function handle($uri) {
|
||
// Убираем базовый URL если есть
|
||
$basePath = parse_url(SITE_URL, PHP_URL_PATH) ?? '';
|
||
$uri = str_replace($basePath, '', $uri);
|
||
$uri = parse_url($uri, PHP_URL_PATH) ?? '/';
|
||
|
||
foreach ($this->routes as $pattern => $handler) {
|
||
if ($this->match($pattern, $uri)) {
|
||
return $this->callHandler($handler, $this->params);
|
||
}
|
||
}
|
||
|
||
// 404
|
||
http_response_code(404);
|
||
include 'views/errors/404.php';
|
||
exit;
|
||
}
|
||
|
||
private function match($pattern, $uri) {
|
||
$pattern = preg_replace('/\{(\w+)\}/', '(?P<$1>[^/]+)', $pattern);
|
||
$pattern = "#^$pattern$#";
|
||
|
||
if (preg_match($pattern, $uri, $matches)) {
|
||
$this->params = array_filter($matches, 'is_string', ARRAY_FILTER_USE_KEY);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
private function callHandler($handler, $params) {
|
||
if (is_callable($handler)) {
|
||
return call_user_func_array($handler, $params);
|
||
}
|
||
|
||
if (is_string($handler)) {
|
||
list($controller, $method) = explode('@', $handler);
|
||
$controllerFile = "controllers/{$controller}.php";
|
||
|
||
if (file_exists($controllerFile)) {
|
||
require_once $controllerFile;
|
||
$controllerInstance = new $controller();
|
||
|
||
if (method_exists($controllerInstance, $method)) {
|
||
return call_user_func_array([$controllerInstance, $method], $params);
|
||
}
|
||
}
|
||
}
|
||
|
||
throw new Exception("Handler not found");
|
||
}
|
||
}
|
||
|
||
// Инициализация роутера
|
||
$router = new Router();
|
||
|
||
// Маршруты
|
||
$router->add('/', 'DashboardController@index');
|
||
$router->add('/login', 'AuthController@login');
|
||
$router->add('/logout', 'AuthController@logout');
|
||
$router->add('/register', 'AuthController@register');
|
||
|
||
// Книги
|
||
$router->add('/books', 'BookController@index');
|
||
$router->add('/books/create', 'BookController@create');
|
||
$router->add('/books/{id}/edit', 'BookController@edit');
|
||
$router->add('/books/{id}/delete', 'BookController@delete');
|
||
$router->add('/books/delete-all', 'BookController@deleteAll');
|
||
$router->add('/books/{id}/normalize', 'BookController@normalizeContent');
|
||
$router->add('/books/{id}/regenerate-token', 'BookController@regenerateToken');
|
||
|
||
// Главы
|
||
$router->add('/books/{book_id}/chapters', 'ChapterController@index');
|
||
$router->add('/books/{book_id}/chapters/create', 'ChapterController@create');
|
||
$router->add('/chapters/{id}/edit', 'ChapterController@edit');
|
||
$router->add('/chapters/{id}/delete', 'ChapterController@delete');
|
||
$router->add('/chapters/preview', 'ChapterController@preview');
|
||
|
||
// Серии
|
||
$router->add('/series', 'SeriesController@index');
|
||
$router->add('/series/create', 'SeriesController@create');
|
||
$router->add('/series/{id}/edit', 'SeriesController@edit');
|
||
$router->add('/series/{id}/delete', 'SeriesController@delete');
|
||
$router->add('/series/{id}/add-book', 'SeriesController@addBook');
|
||
$router->add('/series/{id}/remove-book/{book_id}', 'SeriesController@removeBook');
|
||
$router->add('/series/{id}/update-order', 'SeriesController@updateBookOrder');
|
||
|
||
// Профиль
|
||
$router->add('/profile', 'UserController@profile');
|
||
$router->add('/profile/update', 'UserController@updateProfile');
|
||
|
||
// Экспорт с параметром формата
|
||
$router->add('/export/{book_id}/{format}', 'ExportController@export');
|
||
$router->add('/export/{book_id}', 'ExportController@export'); // по умолчанию pdf
|
||
$router->add('/export/shared/{share_token}/{format}', 'ExportController@exportShared');
|
||
$router->add('/export/shared/{share_token}', 'ExportController@exportShared'); // по умолчанию pdf
|
||
|
||
// Публичные страницы
|
||
$router->add('/book/{share_token}', 'BookController@viewPublic');
|
||
$router->add('/author/{id}', 'UserController@viewPublic');
|
||
$router->add('/series/{id}/view', 'SeriesController@viewPublic');
|
||
|
||
|
||
// Администрирование
|
||
$router->add('/admin/users', 'AdminController@users');
|
||
$router->add('/admin/add-user', 'AdminController@addUser');
|
||
$router->add('/admin/user/{user_id}/toggle-status', 'AdminController@toggleUserStatus');
|
||
$router->add('/admin/user/{user_id}/delete', 'AdminController@deleteUser');
|
||
|
||
|
||
// Обработка запроса
|
||
$requestUri = $_SERVER['REQUEST_URI'];
|
||
$router->handle($requestUri);
|
||
|
||
// Редирект с корня на dashboard для авторизованных
|
||
$router->add('/', function() {
|
||
if (is_logged_in()) {
|
||
header("Location: " . SITE_URL . "/dashboard");
|
||
} else {
|
||
header("Location: " . SITE_URL . "/login");
|
||
}
|
||
exit;
|
||
});
|
||
|
||
|
||
?>
|