Jumast
@Jumast
разработка сайтов - html/css/php/js

Как сделать простой php-роутер?

Приветствую!

Как реализовать простой роутер-php без компонентов/views/методов тд.

Пример реализации скрипта:
/index.php / который инклудит и является роутом
/pages/ страницы которые доступны без авторизации
/pages/account.php - это файл которые будет инклудить содержимое /user/
/pages/user/ страницы аккаунта


Вот что в корневом index.php
# Шапка
include("inc/_header.php");

$url = $_GET['url'];
if(isset($url)){
if(file_exists(dirname(__FILE__).'/pages/'.$url.'.php')){
include(dirname(__FILE__).'/pages/'.$url.'.php');
} else if(isset($_GET['url']) && $_GET['url'] == 'user'){
include(dirname(__FILE__).'/pages/user/'.$url.'.php');
} else{
include(dirname(__FILE__).'/pages/404.php'); // Если страница не найдена
}
} else{
include(dirname(__FILE__).'/pages/index.php'); // Главная
}
echo $_GET['url'];
# Подвал
include("inc/_footer.php");


в файле /account.php переключатель нужен для того чтобы доп.стили и инклудить меню профиля.
$url = strval($_GET["url"]);
			
	switch($url){
		
		case "$url": include("pages/user/$url.php"); break; // Страницы
		case "output": @session_destroy(); Header("Location: /"); return; break; // Выход

	}

не совсем правильно обрабатывает страницы

и .htaccess
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

Попробовал еще так в корне 2 файла index.php и account.php
/pages/ общие страницы
/user/ страницы аккаунта

но не разобрался в htaccess как получить страницы в место /site.ru/dashboard.php такой /site.ru/dashboard

Что я делаю не так? или есть другой способ реализации? Помогите поправить руки) Всем добра!.
  • Вопрос задан
  • 3292 просмотра
Решения вопроса 1
orlov0562
@orlov0562 Куратор тега PHP
I'm cool!
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?route=$1 [QSA,L]


index.php
try {
    // берем переданный роут
    $route = trim($_REQUEST['route']??'index');

    // проверяем, если в конце слеш, то это index роут
    if (substr($route,'-1') == '/') $route.='index';

    // минимальная защита от инклуда неожидаемых файлов
    // ограничиваем имена до символов a-b, 0-9, тире, нижнее подчеркивание и слеш
    if (!preg_match('~^[-a-z0-9/_]+$~i', $route)) throw new Exception('Not allowed route');

    // генерим путь к файлу
    $filePath = dirname(__FILE__).'/pages/'.$route.'.php';

    // если не существует выкидываем ошибку
    if (!file_exists($filePath)) throw new Exception('Route not found');

    // если существует, инклудим файл
    include $filePath;
} catch (Throwable $ex) {
    // в случае любых ошибок, показываем 404
    // тут обычно делают разные типы эксепшенов и разделяют 400 и 500 ошибки
    include dirname(__FILE__).'/pages/404.php';
}


структура вызова
/ => /pages/index.php
/index => /pages/index.php
/about => /pages/about.php
/user/ => /pages/user/index.php
/user/index => /pages/user/index.php
/user/hello => /pages/user/hello.php
...
/404 => /pages/404.php
/<not-found> => /pages/404.php
/user/<not-found> => /pages/404.php

Далее доработать по потребностям.

Но, я бы не советовал самому пилить, т.к. есть много всяких нюансов. Кроме того, есть куча готовых, проверенных, решений. Разве что, просто для интереса.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
gzhegow
@gzhegow
aka "ОбнимиБизнесмена"
/app
/app/controllers
/app/controllers/hello
/app/controllers/hello/world.php
/app/controllers/index.php
/app/routes.php
/public
/public/index.php
/.htaccess
/app.php

.htaccess
# .htaccess

Options +FollowSymlinks -Indexes
DirectoryIndex public/index.html public/index.php

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.*)$ /public/index.php?_url=/$1 [L,QSA]


app.php
<?php
// app.php

define('__ROOT__', __DIR__);
define('__APP__', realpath(__ROOT__ . '/app'));

$routes = require_once __APP__ . '/routes.php';

foreach ($routes as $pattern => $action) {
  if (! preg_match($pattern, $_SERVER['REQUEST_URI'], $matches)) continue;

  $action = array_filter(explode('/', $action));
  $file = basename(array_pop($action), '.php');

  array_push($action, $file);

  require __APP__ . '/controllers/' . implode('/', $action) . '.php';
  break;
}


public/index.php
<?php
// public/index.php

// strict
register_shutdown_function(function () {
  $error = error_get_last();
  if (! $error) return;
  if (! ($error['line'] ?? null)) return;

  $errno    = $error['type'];
  $errmsg   = $error['message'];
  $errfile  = $error['file'];
  $errline  = $error['line'];

  handle(new \ErrorException($errmsg, $errcode = -1, $errno, $errfile, $errline));
});

// error
set_error_handler(function ($errno, $errmsg, $errfile, $errline) {
  if (! $errline) return;

  throw new \ErrorException($errmsg, $errcode = -1, $errno, $errfile, $errline);
}, E_ALL);

// handle
function handle(\Throwable $e)
{
  echo '<pre>';
  die(var_dump($e));
}

// index.php
try {
  // run application
  require_once __DIR__ . '/../app.php';

} catch (\Throwable $e) { handle($e); }


app/routes.php
<?php
// app/routes.php

$routes = [];

foreach ([
  '/' => 'index',
  '/foo/bar' => 'index',
  '/hello/world' => 'hello/world',
] as $pattern => $action) {
  $routes[ '/^' . preg_quote($pattern, '/') . '$/' ] = $action;
}

return $routes;


app/controllers/index.php
<?php
// app/controllers/index.php

echo 'Index';


app/controllers/hello/world.php
<?php
// app/controllers/hello/world.php

echo 'Hello/World';
Ответ написан
@ar2rsoft
PHP-developer
switch($url){
    case "$url": include("pages/user/$url.php"); break; // Страницы

Это пять)

Вы в htaccess передаете параметр menu, а принимаете параметр url
Ответ написан
anton_reut
@anton_reut
Начинающий веб-разработчик
Посмотри вот это древнее видео по роутеру, как пример: https://www.youtube.com/watch?v=ba3M3_Myrqg&list=P...
Суть роутера - понять по адресной строке какие скрипты ты от него хочешь, если таких нет то 404. ВСЁ.
Ответ написан
sergiks
@sergiks Куратор тега PHP
♬♬
На github есть много популярных (по числу звёзд) реализаций php router'а.

Задача типичная, решений много.

Для обучения так же полезно, как писать велосипед, изучать чужой код.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы