Сразу к делу ) Вот так я реализовал на своем сайте переключение контента по разделам PHP: $id = ''; if (!empty($_GET)) { $id = empty($_GET['id']) ? '' : trim(strip_tags($_GET['id'])); } $blocks = ['header', 'content', 'footer']; ?> <?php foreach ($blocks as $block): ?> <?php if ($block == 'header'): ?> <?php include 'header.php'; ?> <?php elseif ($block == 'content'): ?> <?php switch ($id) { case 'arenda': include 'menu/arenda.php'; break; case 'store': include 'menu/store.php'; break; case 'errorpage': include 'menu/errorpage.php'; break; case 'emailconfirm': include 'menu/emailconfirm.php'; break; case 'lc': if ($_SESSION['session_id']) { include 'menu/lc.php'; } else { include 'menu/default.php'; } break; default: include 'menu/default.php'; break; } ?> <?php elseif ($block == 'footer'): ?> <?php include 'footer.php'; ?> <?php endif; ?> <?php endforeach; ?> Подключаем header, footer, а в контенте свитчем по id страницу контента что в итоге мне дает вот такой url http://mysite/index.php?id=activation or http://mysite/index.php?id=somemenu Вопрос, какой вы посоветуете самый просто способ превратить мой url в http://mysite/activation or http://mysite/somemenu. Что я имею ввиду под "самый простой" - без туевой хучи классов и роутинга? вот я хочу добавить админку по адресу http://mysite/~ как мне этого добиться?
все зависит от структуры сайта)) я себе для простого проекта сделал роутинг простой)) добавляю экшен в контроллер - он сразу становится доступным по ссылке.. все экшены которые недоступны в контроллере - выдают 404 ошибку)
@Taktreba, самый простой способ – это полностью избавиться от промежуточного использования строки параметров и работать в скрипте напрямую с путем в исходном адресе. Гляньте мою статью Как сделать единую точку входа с ЧПУ? --- Добавлено --- Без роутинга не получится. Ваш свитч – это уже примитивный роутер.
@Taktreba действительно зачем лишние свечи? при добавлении файла нужно лезть и прописывать его... проще же проверять наличие файла в директории и инклудить а если отсутствует до индексную страницу и зачем целая куча выходов\входов в пхп если они лишние?
Я вот такой вот делал роутер для простого сайта.. PHP: <?php /* * Нет лицензии)) */ namespace natCMF\core; /** * Простой роутинг * * Необходимый вид файла .htaccess * RewriteEngine on * RewriteCond %{REQUEST_FILENAME} !-f * RewriteCond %{REQUEST_FILENAME} !-d * RewriteRule ^(.*)$ index.php?route=$1 [L,QSA] * * Теперь если в адресной строке у нас вот такая конструкция * http://test.ru/site/page/34 * То: * site - это контроллер * page - это метод экшена в контроллере * 34 - это параметр передаваемый в метод экшена * * Если строка выглядит так * http://test.ru/page/34 * То роутер проверяет наличие контроллера PageController и если его нет * считает что это экшен контролера по умолчанию * таким образом мы пряем контроллер по умолчанию из строки * * ВНИМАНИЕ: в методе parseURI и __construct стоят редиректы * 1. Для того что бы убирать дефолтные значения из роута * 2. Для того что бы убирать слеш в конце роута * TODO: Заменить на правила в htaccess * * @author я */ class Router { /** * Текущий путь, даже если в адресной строке путь не указан * то все равно этот массив заполняется значениями по умолчанию * @var array */ public $gets = []; /** * Контроллер, экшен и параметры по умолчанию * такие вещи лучше хранить в реестре где то * и вставять сюда при создании объекта * но в данном случае для примера поместил сюда * @var array */ protected $defaultGets = ['site', 'index', []]; /** * Имя класса который вызывается в результате текушего роута * @var string */ protected $classController = ''; /** * Имя метода экшена который вызывается в результате текущего роута * @var string */ protected $methodAction = ''; /** * Набор параметров который должен принять текущий экшен * @var array */ protected $methodParams = []; /** * Конструктор * парсим URI */ public function __construct() { /* Парсим URI */ $this->parseURI(); /* Удаляем дефолтный контроллер/экшен */ if (!isset($this->gets['2']) && isset($this->gets['0']) && isset($this->gets['1'])) { if ($this->gets['0'] == $this->defaultGets['0'] && $this->gets['1'] == $this->defaultGets['1']) { App::redirectexit('/'); } } /* Удаляем дефолтный экшен если не указан контроллер и нет параметров */ if (!isset($this->gets['1']) && isset($this->gets['0'])) { if ($this->gets['0'] == $this->defaultGets['1']) { App::redirectexit('/'); } } /* Удаляем дефолтный экшен если указан контроллер и нет параметров */ if (!isset($this->gets['2']) && isset($this->gets['1'])) { if ($this->gets['1'] == $this->defaultGets['1']) { unset($this->gets['1']); App::redirectexit(implode('/', $this->gets)); } } /* Фиксируем контроллер, экшен и параметры */ $this->fixController(); $this->fixAction(); $this->fixParams(); } /** * Парсим URI */ private function parseURI() { /* Получили строку из $_GET['route'] параметра */ $uri = (string) filter_input(INPUT_GET, 'route'); /* Убрали слеш в конце роута */ if (mb_substr($uri, -1) == '/') { App::redirectexit(trim($uri, '/')); } /* Разбили строку и обрезали по бокам слеши */ $this->gets = explode('/', trim($uri, '/')) ?? []; } /** * Фиксируем контроллер который надо использовать в роуте * и проверяем наличие такого контроллера, если такого контроллера нет * то подставляем контроллер по умолчанию * Таким образом мы скрываем из строки контроллер по умолчанию * @return boolean */ private function fixController() { if (empty($this->gets['0'])) { /* Если пусто после указания компонента то берем контроллер по умолчанию */ $this->gets['0'] = $this->defaultGets['0']; } else { /* Если что то указано в первом параметре то проверяем наличие такого контроллера */ if (!class_exists('\natCMF\controllers\\' . $this->parseRouteString($this->gets['0']) . 'Controller')) { /* Если нет такого метода то вставляем в начало массива контроллер по умолчанию */ array_unshift($this->gets, $this->defaultGets['0']); } } $this->classController = '\natCMF\controllers\\' . $this->parseRouteString($this->gets['0']) . 'Controller'; return true; } /** * Фиксируем экшен который надо использовать в роуте, * @return boolean */ private function fixAction() { if (empty($this->gets['1'])) { /* Если нет экшена то берем экшен по умолчанию */ $this->gets['1'] = $this->defaultGets['1']; } else { /* Если экшен есть то проверяем его существования иначе отдает 404 экшен */ if (!method_exists($this->classController, 'action' . $this->parseRouteString($this->gets['1']))) { $this->gets['1'] = '404'; } } $this->methodAction = 'action' . $this->parseRouteString($this->gets['1']); return true; } /** * Фиксируем параметры которые надо использовать в роуте * @return boolean */ private function fixParams() { if (empty($this->gets['2'])) { $this->gets['2'] = []; } else { /* Пересобираем gets выделяя параметры в отдельный массив */ $params = $this->gets; $this->gets = []; $this->gets['0'] = $params['0']; $this->gets['1'] = $params['1']; unset($params['0']); unset($params['1']); $this->gets['2'] = array_values($params); } /* Для метода проверяем количество принимаемых параметров */ $classMethod = new \ReflectionMethod($this->classController, $this->methodAction); /* Отдаем ровно столько сколько нужно отдать.. */ $this->methodParams = array_slice($this->gets['2'], 0, count($classMethod->getParameters())); return true; } /** * Обрабатываем строку типа page-info что бы получить PageInfo * @param string $inStr * @return string */ private function parseRouteString($inStr) { $result = ''; $names = explode('-', $inStr); foreach ($names as $name) { $result .= ucfirst($name); } return $result; } /* Поехали (с) */ public function run() { /* Создаем объект контроллера */ $controller = new $this->classController; /* Вызываем метод объекта */ call_user_func_array(array($controller, $this->methodAction), $this->methodParams); } }
@Алекс8 хм. советую переименовать метод parseURI в parseURIAndMayBeRedirect вообще логика работы странная местами. но дело хозяйское
редиректы вчера добавил когда выкладывал)) захотелось поиграться)) раньше их не было)) а кроме редиректов почему странная логика?
неочевидная логика, как по мне. получается что нельзя использовать на сайте контроллер с именем, которое будет пересекаться с именем хоть одного экшена, любого другого контроллера. например, добавил на сайт новости /market/news а потом решил добавить глобальную ленту новостей типа /news/4, и все. роутер начнет вызывать не то что задумано. я бы сделал его более гибким, но менее интеллектуальным. я сам хочу управлять роутингом, а не надеяться каждый раз, что он сможет переварить любой новый необычный роутинг. если запросили неизвестный контроллер, зачем подменять его на дефолтный? запросили бред - это 404. и нечего его вообще обрабатывать дальше. ну и по мелочи, по коду бы сделал подругому моменты.. как я и сказал, дело вкуса.
В .htaccess у меня так сделано было: RewriteRule ^auth$ /nav?page=auth Где ^auth$ - это как хочешь, чтобы выглядела ссылка. /nav?page=auth - адрес до файла --- Добавлено --- Но придется каждую ссылку прописывать: RewriteRule ^activation$ http://mysite/index.php?id=activation RewriteRule ^someone$ http://mysite/index.php?id=someone RewriteRule ^~$ http://mysite/admin
@Danil005, и не лень? Проще взять любой человеческий роутер и сделать единую точку входа. http://route.thephpleague.com/, или, как @askanim, микрофрейморк Slim или любой другой (к примеру, https://fatfreeframework.com/3.6/home) в качестве роутера.
Мини велосипед PHP: <?php # Author - Fedor Vlasenko define('METHOD', $_SERVER['REQUEST_METHOD']); define('URI', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)); function router($url, ...$args) { (empty($args[1]) || false !== strpos($args[0], METHOD)) && (URI === $url || preg_match('#^' . $url . '$#iu', URI, $match)) && die(call_user_func_array(end($args), $match ?? [])); } router('/', function () { echo 'Main Micro'; }); router('/article/(.*[^/])', 'GET', function (...$args) { echo 'Article: ', $args[1]; }); header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found'); echo '404';
PHP: router('/article/(.*[^/])', 'GET', function (...$args) { echo 'Article: ', $args[1]; }); я смотрел несколько разных роутеров.. и честно говоря не понял прикол вот таких вот роутов) в yii2 роуты указываются в массиве и фреймворк сам роутит куда что надо... а вот нафига в мини роутерах такие записи.. они предлагают инклудить файлы в зависимости от роута? я поэтому для себя и написал свой минироутер)) потому что я хотел просто добавить контроллер и экшен в нем и больше ничего не добавлять)) а тут получается для каждого экшена надо добавлять свой роут.. или я гоню?)
что вам мешает прописать параметры в массиве, json, yaml, ini, базе... И затем в цикле передавать параметры Это пример в функциональном стиле, для общего понимания, не для больших приложений. Роутер со "шлюхами" это прежде всего Reflection, где вы будете заглядывать в методы контроллера, смотреть вызываемые параметры и подставлять в них значения. как будто вы это не делаете используя классы Ребята я привел пример, и он вроде один из маленьких и универсальных, позволяющий отработать различные виды запросов. Советую для изучения рассмотреть Fat-Free Framework