Как у вас реализовано чпу?

Хочу изменить реализацию чпу у себя, но не знаю как будет лучше. Под спойлером описан мой способ. Хотелось-бы посмотреть как это реализуете вы без использования фреймворков

ЗаголовокЭто пишем в файле index.php после загрузки ядра и всех необходимых файлов
define('MAIN_URI', ($_SERVER['REQUEST_URI'] == '/' ? '/index.php' : $_SERVER['REQUEST_URI']) );

// грузим правила для ЧПУ
include 'incl/furl_patterns.php';

$res =  preg_replace($patterns_keys, $patterns_values, MAIN_URI);
if ($res == MAIN_URI){
	// если не совпало ни одно из правил, выводим ошибку 404 или редиректим...
}	

// разбираем url и преопределяем суперглобальный массив _REQUEST
parse_str($res, $_REQUEST);	

$module = $_REQUEST['module'];

// далее подгружаем нужный модуль -  упрощенный вариант
// например modules/news/index.php
if(file_exists("modules/".$module."/index.php")) {		
	include "modules/".$module."/index.php";			
} else {		
	//опять 404 или редирект	
}



файл с правилами выглядит так:

$patterns_keys = array(
			'#^/(id([0-9]*)/?)?$#i',				//test.ru/id154 можно без слеша после ид, а можно и с ним
			'#^/(user/?)(new/?)?$#i',
			'#^/(user/?)(settings/?)?$#i',
			'#^/(user/?)(settings/?)?((general|avatar|security|social)/?)$#i'
			);

$patterns_values = array(
			'module=account&id=$2',
			'module=account&action=new', 
			'module=account&action=settings', 
			'module=account&action=settings&do=$4'				//модулю можно передавать дополнительные параметры
			);


Например для test.ru/user/new будет подключен файл modules/account/new_user.php,

для ссылки test.ru/user/settings — modules/account/settings.php и в зависимости от того какие настройки указаны — они и будут выведены(по дефолту general). Правда в таком случае модуль подключается иначе:

switch ($module) {			
	case 'account':				
		switch ($_REQUEST['action']) {						
			case 'new':
				include 'modules/account/new_user.php';
			break;
			case 'settings':
				include 'modules/account/settings.php';
			break;
			default:
				include 'modules/account/profile.php';
		}						
	break;
	...
}


Можно конечно грузить файл modules/account/index.php и уже в нем определять действия, и так для каждого модуля — неудобно, поэтому решил: пусть все будет в одном месте(можно вынести в отдельный файл).


Файл htaccess выглядит просто
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d 
RewriteRule ^(.*)$ index.php?%{REQUEST_URI} [l]



Этот способ был написан давно и вполне нормально работает, и я так давно его использую что не могу придумать ничего нового.

Единственным плюсом является то, что можно указывать любые правила, например:
test.ru/
	id15484
	userid15484
	15484
	erth15484yryu
	user/15484
	user/id/15484
	...


будет отображена страница профиля пользователя с id=15484

или просто логин пользователя, без указания его id
test.ru/artishok
test.ru/user/artishok



Минусов несколько. Кроме очевидных — нельзя передавать параметры через массив $_GET.


Если здесь поиск простой:
habrahabr.ru/search/?target_type=posts&q=text&orde...


то мне в таком случае надо писать дополнительные правила с учетом типа и сортировки, выглядеть будет примерно так:
'#^/(search/?)(([a-zA-Zа-яА-Я0-9%\+]*)/?)?((posts|comments|questions|users)/?)?((time|relevance)/?)?(page([0-9]*)/?)?$#i'


и
'module=search&text=$3&type=$5&sort=$7&page=$9',

test.ru/search/text/posts/time/page2 — не понятно что происходит, и если в ссылке тип и сортировку поменять местами — выдаст ошибку, также ошибку выдаст если убрать один из параметров…


ps: извините, если что-то мутно описано — залипаю уже
  • Вопрос задан
  • 12584 просмотра
Пригласить эксперта
Ответы на вопрос 7
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
Вот зачем постоянно городить велосипеды… мильен их, и еще если поискать может чего интереснее будет. Такие вещи как раутинг, логирование и т.д. вообще желательно реюзать, а писать свои велосипеды — от этого пользы мало. Разве что обсучение.
github.com/chriso/klein.php
noodlehaus.github.io/dispatch/
Ответ написан
Mendel
@Mendel
PHP-developer
А зачем вообще ЧПУ?
ЧПУ это наследие стареньких движков.
Решение должно быть изначально в архитектуре.
т.е. ЧПУ как правило подразумевает, что у нас есть некая карта, а потом мы делаем ее более красивой…
Мы все равно будем делать те или иные запросы в базу, так почему бы и не искать эту информацию по ключу в виде полноценного пути?
Должная оптимизация с лихвой покроет издержки от того, что мы ищем по более длинному чем числовой индексу.
Теоретически и тут можно оптимизировать но на практике лично я до этого не дошел.
Была мысль использовать не сам путь а md5 от него, а если и это будет недостаточно быстро, то урезать его до bigint или даже до int ведь md5 это всего 16 байт, а при конфликте хэша мы просто получим две страницы вместо одной, и выберем перед выводом нужную…
Хотя при разумном количестве страниц конфликты маловероятны даже для обычного int.

Но на практике наши задержки или слишком малы, или таких запросов просто непомерно много, а если их много, то они у нас и так будут закрыты кэшем, так стоит ли о них беспокоиться?
Ответ написан
copist
@copist
Empower people to give
ЧПУ — это человеко-понимаемый УРЛ

не
h_ttp://example.com/post/121212

а
h_ttp://example.com/post/latest%20news

Чтобы человек читал и понимал, что это за ссылка
Ответ написан
Комментировать
soprun
@soprun
Software Architecture
Ну почему нельзя передавать ?)
Если сделать например так:
$route = preg_replace( '/(\?.*)?$/', '', $_SERVER["REQUEST_URI"] );
$route = preg_replace( '/%2F/' , '/' , urlencode( trim( $route , '/' ) ) );
define( 'MAIN_URI' , $route );


То можно реализовать так:
/search/search_request?type=posts&sort=time
Ответ написан
Комментировать
@mgkirs
у меня оно реализовано средствами apache
Вот 1 из примеров:
RewriteRule ^(.[^/]*)/([0-9]*)$ /index.php?a=$1&n=$2 [QSA]
Ответ написан
Комментировать
student_ivan
@student_ivan
Web-Developer, Front-End Engineer
В своё время в одном из своих треш-проектов делал компилируемый роутер, который компилировал статические маршруты для apache + mod rewrite и nginx, через командную строку. Выглядело это как-то так, а маршруты как-то так
Ответ написан
Комментировать
fear86
@fear86
Developer
Мне нравиться вариант хранить все ссылки в базе данных, есть ЧПУ и есть системный урл на который он ведет. Таким образом ссылки можно создавать программного, руками, можно сделать поддержку 301 редиректа для перемещенных/переименованных страниц, и тд. и не привязывать логику чпу к серверу.
Ответ написан
Ваш ответ на вопрос

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

Похожие вопросы