Справка по перезаписи URL

Всем спасибо за терпение и помощь. Я полностью повторяю вопрос, потому что он становится довольно длинным из-за всех моих исправлений. У меня есть структура PHP MVC с 4 точками входа:

из корня:
index.php
index-ajax.php
admin/index.php
admin/index-ajax.php

Мне нужен был файл .htcaccess, который принимал бы любой запрос и перезаписывал его в соответствующий файл на основе URL-адреса. Длинный URL-адрес будет index.php?rt=cms/view/15, и я хотел, чтобы он был index/cms/view/15. Эта часть в значительной степени сделана, за исключением одного подводного камня.

Вот мой файл .htaccess сейчас:

# htaccess file for framework - GOOD
Options +FollowSymLinks

# Turn on the mod_rewrite engine - GOOD
RewriteEngine On

# Hide indexes - GOOD
Options -Indexes

# If a file is not one of these, continue processing. - GOOD
RewriteRule \.(css|js|jpg|jpeg|png|gif|ico)$ - [L]

# RewriteRules for folder index files
#RewriteRule ^(index)?(.php)?$ index.php [L] - GOOD
#RewriteRule ^admin(/?)(index)?(.php)?$ admin/index.php [L] - GOOD

# RewriteRules for admin folder arguements - going from more specific to less
RewriteRule ^admin/ajax/[A-Za-z0-9-_/]*$ admin/index-ajax.php?rt=$1 [L]
RewriteRule ^admin/[A-Za-z0-9-_/]*$ admin/index.php?rt=$1 [L]

# RewriteRule for root ajax file
RewriteRule ^ajax/[A-Za-z0-9-_/]*$ index-ajax.php?rt=$1 [L]

# RewriteRule for root file - by here, it is not ajax or admin related, so only
# possible option left if the root index file
RewriteRule ^[A-Za-z0-9-_/]*$ index.php?rt=$1 [L]

Я сделал простой сайт с двумя папками — «root» и «root/admin», и внутри каждой из них есть папка css, images и javascript с некоторым фиктивным содержимым. Внутри «root» и «root/admin» есть файл index.php и index-ajax.php, который просто выводит любой аргумент URL и использует файлы css, js и изображения из каждой из папок.

Проблема, с которой я столкнулся сейчас, заключается в том, что если я делаю URL-адрес, такой как index/blah или /admin/index/blah, то страница отображается правильно, и аргумент правильный. Однако, когда я делаю URL-адрес, такой как index/blah/view или admin/index/blah/view, аргумент правильный (?rt=blah/view), но страница отображается неправильно, потому что файл css/js/images переходит в индекс /blah/[css] вместо index/[css].

Любые идеи о том, как справиться с этим? Я разрешил файлам css/js/image проходить как есть через .htaccess, чтобы там было меньше работы.


person Robert DeBoer    schedule 08.07.2009    source источник


Ответы (7)


Таким образом, изображения/css/и т. д. ломаются, потому что вы используете относительный URL-адрес в HTML, и теперь, когда вы идете более вложенным, они ломаются? С некоторыми другими настройками MVC, с которыми я сталкивался, обычно есть какая-то переменная «корневого пути», устанавливаемая контроллером на основе URL-адреса запроса и используемая компонентом View для префикса всех путей к активам, таким как изображения/стили/скрипты.

Это превращает вашу проблему .htaccess в проблему контроллера/PHP, которая, если это приемлемое решение для вас, потребует от вашего контроллера выполнения чего-то вроде взрыва URL-адреса запроса на "/", подсчета количества результирующих частей и построения относительного URL-адрес из результата.

Я сделал то же самое для пользовательской настройки MVC, которую я сделал; проверьте http://avogadro.ws/hosted/skel/public/results/school-1 и просмотрите исходный код для местоположений CSS. CSS для этой страницы на самом деле находится по адресу http://avogadro.ws/hosted/skel/. level, который Контроллер встраивает в относительную строку.

person MidnightLightning    schedule 06.08.2009
comment
да. Ссылки на файлы image/css/js/etc в html относятся к этому документу. Есть некоторые внешние ресурсы, которые будут иметь каждый результат MVC (глобальная таблица стилей, скелетные изображения html и т. д.). Проблема, похоже, заключается в том, что в моем .htaccess я разрешил любой запрос файла с расширением css, js или изображения проходить без изменений, потому что я думал, что эти ресурсы не нуждаются в какой-либо обработке, они используются как есть. Но теперь, когда URL-адрес вложен, он думает, что они находятся в папке с именем blah, когда blah на самом деле является контроллером, поэтому URL-адрес переходит в несуществующую папку. - person Robert DeBoer; 07.08.2009
comment
Я думаю, хорошо, что ваши файлы image/css/js/etc обходят .htaccess. Мое вышеприведенное решение исправляет проблему, связанную с тем, что они думают, что они находятся в папке с именем «blah», добавляя префикс к URL-адресу. В моем примере выше папка /hosted/skel действительно существует. Однако public/results/ нет. Если страница «school-1» ссылается на файл CSS как main.css, она попытается получить /hosted/skel/public/results/main.css. Итак, я изменяю HTML, чтобы ссылаться на файл CSS как ../../main.css, что помещает его в /hosted/skel/main.css, где на самом деле находится файл. - person MidnightLightning; 10.08.2009

Вы уверены, что все должно обрабатываться index.php? Как насчет статических файлов, таких как изображения/css и т. д.?

Вот альтернативный метод, который может вас заинтересовать. Вы можете перенаправить любой URL-адрес, который еще не существует в виде файла или каталога, в ваш файл index.php, а затем проанализировать URL-адрес там, например. [domain.com]/cms/view/15 будет переписан на [domain.com]/index.php/cms/view/15 . Для этой работы вам необходимо установить для директивы Apache AcceptPathInfo значение On.

.htaccess:

RewriteEngine On
#check url is not a valid file
RewriteCond %{REQUEST_FILENAME} !-f
#check url is not a valid directory
RewriteCond %{REQUEST_FILENAME} !-d
#rewite anything left
RewriteRule ^(.*)$ index.php/$1 [L]

index.php

$path = trim($_SERVER['PATH_INFO'], '/');
$pathParts = explode('/', $path);

if (isset($pathParts[0])) {
    $com = $pathParts[0];
} else {
    $com = 'defaultcom';
}

//$com[1] will be 'view' if supplied
//$com[2] will be 15 if supplied

Мне нравится этот подход, потому что вы не обязаны определять и понимать URL-адрес в конфигурации apache, но вы можете выполнять большую часть работы в PHP.

Изменить

Вместо этого вы можете использовать это как свой .htaccess, это перенаправит любой запрос с расширением, которого нет в списке, на ваш PHP-скрипт. RewriteCond должен предотвращать перезапись запросов к папке администратора.

RewriteEngine On
#don't rewrite admin
RewriteCond %{REQUEST_URI} ^admin/
#rewrite anything with a file extension not in the list
RewriteRule !\.(js|gif|jpg|png|css|ico)$ /index.php [L]
person Tom Haigh    schedule 08.07.2009
comment
Изображения и CSS также могут обрабатываться PHP. Я делаю это регулярно для чего-то довольно глупого и, безусловно, выполнимого путем перенастройки Apache (хотя вы можете или не можете это сделать): я помещаю файл с именем static.php, который добавляет только заголовки срока действия к файлам, обслуживаемым из static_files/. - person Ivan Vučica; 09.07.2009
comment
Спасибо, я никогда не думал об изображениях, css и т. д. Пользователю потребуется прямой доступ к этим файлам для конечного вывода html - правильно? Однако я не хочу, чтобы пользователь имел доступ к каким-либо файлам PHP - им не нужно запускать какие-либо файлы, кроме index.php - все остальные файлы php используются фреймворком и не будут работать, если все равно вырвано из контекста. - person Robert DeBoer; 09.07.2009
comment
Еще раз спасибо. Для перезаписи всего, чего нет в списке, вы можете просто перейти к следующему правилу перезаписи. Итак, если файлов нет в списке, перейдите к следующему правилу перезаписи, которое затем перепишет URL-адрес index.php? - person Robert DeBoer; 09.07.2009
comment
Это все равно должно делать? Я не уверен, что ты имеешь в виду. - person Tom Haigh; 09.07.2009
comment
Прошу прощения за путаницу. Я почти уверен, что мне нужно следующее: отключить индексы, прямой доступ к любому файлу jpg, png, gif, css, js, правило перезаписи для index.php, правило перезаписи для index-ajax.php, правило перезаписи для /admin/ index.php, переписать правило для /admin/index-ajax.php, чтобы index.php?..... стал .com/[part1]/[part2]/[part3] ; admin/index.php?.... становится .com/admin/[part1]/[part2]/[part3] ; и то же самое для соответствующих файлов index-ajax.php. - person Robert DeBoer; 09.07.2009

Если я не упустил суть вашего вопроса (я вмешиваюсь после редактирования вашего вопроса), звучит так, как будто вам нужно исправить относительные пути изображений/css для URL-адресов, которые имеют много папок. Простое решение, не используйте относительные пути к изображениям! Просто начните свои ссылки image/css с косой черты..

<img src="/img/logo.png" alt="something" />

Я всегда считал, что это более простой подход, когда у вас есть один шаблон, поддерживающий множество страниц с непредсказуемой глубиной папок. Пока у вас есть тестовый URL для локальной разработки, он отлично работает для локальных и рабочих серверов.

person simonrjones    schedule 08.08.2009
comment
Я обнаружил, что этот подход хорошо работает для любых проблем с путями перезаписи, с которыми я сталкивался в прошлом. - person justinl; 11.08.2009

Я бы сделал это как сказал Том Хей и проанализировал запрошенный URL-адрес с помощью PHP:

// extract the URL path
$_SERVER['REQUEST_URI_PATH'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
// extract the path segments
$segments = explode('/', trim($_SERVER['REQUEST_URI_PATH'], '/'));
// expected parameters and its default values
$params = array(
    'com'    => 'default',
    'action' => 'default',
    'val'    => 'default'
);
foreach ($params as $key => $val) {
    if (isset($segments[0])) {
        $_GET[rawurldecode($key)] = rawurldecode(array_shift($segments));
    } else {
        break;
    }
}
$restOfTheURLPath = implode('/', $segments);
var_dump($_GET);

И правила mod_rewrite:

# redirect every request, that cannot be mapped to an existing file, to index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^admin(/|$) admin/index.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

Изменить    В ответ на ваш комментарий и теперь отредактированный вопрос: вы можете исключить нужные каталоги с помощью правила, которое завершает процесс перезаписи:

RewriteRule ^(css|images)/ - [L]
RewriteRule ^admin/index\.php$ - [L]
RewriteRule !^index\.php$ index.php [L]
person Gumbo    schedule 09.07.2009
comment
Спасибо, я никогда не думал об изображениях, css и т. д. Пользователю потребуется прямой доступ к этим файлам для конечного вывода html - верно? ‹br /› Однако я не хочу, чтобы пользователь имел доступ к каким-либо другим файлам PHP - им не нужно для запуска любого, кроме index.php - все остальные файлы php используются фреймворком и в любом случае не будут работать, если они будут вне контекста. ‹br /› Я разрабатываю фреймворк MVC, поэтому index.php служит точкой входа который обрабатывает запрос пользователя с URL-адреса. Или я что-то упустил в своем мыслительном процессе (возможно :). - person Robert DeBoer; 09.07.2009
comment
Спасибо, я решил сделать двойной подход, как вы предложили. Переменная GET будет содержать путь, который уже будет содержать косые черты, разделяющие различные компоненты пути. Я просто использую mod_rewrite, чтобы избавиться от ?rt= в общедоступном URL-адресе, и использовать PHP для анализа переменной GET. Это должно быть проще, чем пытаться взломать все с помощью mod_rewrite. Мой фреймворк уже имеет дело с разбиением переменной GET, так что это также будет самая быстрая адаптация mod_rewrite. Мне просто нужно убедиться, что мой файл .htaccess правильный. - person Robert DeBoer; 09.07.2009
comment
Отличный алгоритм! Мне просто нужно было сделать $segments = array_filter(explode(...)) для обработки пустого REQUEST_URI, когда взрыв PHP не возвращает пустой массив, как ожидалось. - person Jannie Theunissen; 19.05.2011

Ну, это выглядит довольно хорошо, за исключением того, что $, которые вы ставите посередине, могут его испортить; $ отмечает конец регулярного выражения, поэтому я не думаю, что оно будет работать правильно.

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

person Eugene Bulkin    schedule 08.07.2009
comment
Я просто не печатаю достаточно быстро, очевидно. - person seth; 09.07.2009
comment
Я думал, что знаки $ служат заполнителями для переноса значения из левого URL-адреса в правильный URL-адрес? - person Robert DeBoer; 09.07.2009
comment
Он имеет в виду $ в первой части, между / - person seth; 09.07.2009
comment
Да, наверняка знак $ был проблемой - person Robert DeBoer; 09.07.2009

# htaccess file for framework - GOOD
Options +FollowSymLinks

# Turn on the mod_rewrite engine - GOOD
RewriteEngine On

# Hide indexes - GOOD
Options -Indexes

# If a file is not one of these, continue processing. - GOOD
RewriteRule ^images/([A-Za-z0-9\-_]*)\.(css|js|jpg|jpeg|png|gif|ico))$ - 
RewriteRule ^images/admin/([A-Za-z0-9\-_]*)\.(css|js|jpg|jpeg|png|gif|ico))$ - 
RewriteRule ^admin/(([A-Za-z0-9\-_/]*)/([A-Za-z0-9\-_]*)\.(css|js|jpg|jpeg|png|gif|ico))$ admin/images/$3.$4 [L]
RewriteRule ^(([A-Za-z0-9\-_/]*)/([A-Za-z0-9\-_]*)\.(css|js|jpg|jpeg|png|gif|ico))$ images/$3.$4 [L]

# RewriteRules for folder index files
#RewriteRule ^(index)?(.php)?$ index.php [L] - GOOD
#RewriteRule ^admin(/?)(index)?(.php)?$ admin/index.php [L] - GOOD

# RewriteRules for admin folder arguements - going from more specific to less
RewriteRule ^admin/ajax/([A-Za-z0-9\-_/]*)$ admin/index-ajax.php?rt=$1 [L]
RewriteRule ^admin/([A-Za-z0-9\-_/]*)$ admin/index.php?rt=$1 [L]

# RewriteRule for root ajax file
RewriteRule ^ajax/([A-Za-z0-9\-_/]*)$ index-ajax.php?rt=$1 [L]

# RewriteRule for root file - by here, it is not ajax or admin related, so only
# possible option left if the root index file
RewriteRule ^([A-Za-z0-9\-_/]*)$ index.php?rt=$1 [L]

Приведенный выше .htaccess работает при тестировании с вашим каталогом и настройкой файла на сервере Linux/apache.

Я заменил вам строку ignore-images переписыванием, которое делает запрос на изображение в /ajax/hello/world/images переходом к /images, а если оно находится в папке администратора, оно переходит в /admin/images

person Simon Byholm    schedule 08.08.2009

Последняя строка, вероятно, должна быть:

RewriteRule ^/([A-Za-z\-_]+)/([A-Za-z\-_]+)/([A-Za-z0-9\-_]+)$ /index.php?com=$1&action=$2&val=$3 [L,R]
person lemonad    schedule 08.07.2009