apache — Ссылка: mod_rewrite, перезапись URL и & quot; красивые ссылки & quot; объяснил

«Красивые ссылки» — часто запрашиваемая тема, но она редко полностью объясняется. mod_rewrite — это один из способов создания «симпатичных ссылок», но он сложный, его синтаксис очень лаконичен, его сложно найти, а документация предполагает определенный уровень владения HTTP. Может кто-нибудь объяснить простыми словами, как работают «красивые ссылки» и как mod_rewrite может быть использован для их создания?

Другие распространенные имена, псевдонимы, термины для чистых URL-адресов: RESTful URL-адреса, удобные для пользователя URL-адреса, оптимизированные для SEO URL-адреса, Slugged, MVC-URL (вероятно, неправильно)

131

Решение

Чтобы понять, что делает mod_rewrite, вам сначала нужно понять, как работает веб-сервер. Веб-сервер отвечает на HTTP-запросы. HTTP-запрос на самом базовом уровне выглядит следующим образом:

GET /foo/bar.html HTTP/1.1

Это простой запрос браузера к веб-серверу, запрашивающий URL /foo/bar.html от него. Важно подчеркнуть, что он не запрашивает файл, он запрашивает только какой-то произвольный URL. Запрос также может выглядеть так:

GET /foo/bar?baz=42 HTTP/1.1

Это так же верно и для запроса URL-адреса, и, очевидно, он не имеет ничего общего с файлами.

Веб-сервер — это приложение, которое прослушивает порт, принимает HTTP-запросы, поступающие на этот порт, и возвращает ответ. Веб-сервер полностью свободен отвечать на любой запрос любым способом, который он сочтет нужным / любым способом, которым вы настроили его для ответа. Этот ответ не файл, это HTTP ответ которые могут иметь или не иметь никакого отношения к физическим файлам на любом диске. Веб-сервер не обязательно должен быть Apache, есть много других веб-серверов, которые являются просто программами, которые работают постоянно и подключены к порту, который отвечает на HTTP-запросы. Вы можете написать один самостоятельно. Этот абзац был призван отделить вас от любых представлений о том, что URL-адреса напрямую совпадают с файлами, что действительно важно понять. 🙂

Конфигурация по умолчанию для большинства веб-серверов заключается в поиске файла, соответствующего URL-адресу на жестком диске. Если корень документа сервера установлен, скажем, /var/www, может ли файл посмотреть /var/www/foo/bar.html существует и служит этому, если так. Если файл заканчивается на «.php», он вызовет интерпретатор PHP и затем вернуть результат. Вся эта ассоциация полностью настраивается; файл не должен заканчиваться на «.php», чтобы веб-сервер мог запустить его через интерпретатор PHP, а URL-адрес не должен совпадать с каким-либо конкретным файлом на диске, чтобы что-то произошло.

mod_rewrite — это способ перезапись внутренняя обработка запросов. Когда веб-сервер получает запрос на URL /foo/bar, вы можете перезапись этот URL во что-то еще, прежде чем веб-сервер будет искать файл на диске, чтобы соответствовать ему. Простой пример:

RewriteEngine On
RewriteRule   /foo/bar /foo/baz

Это правило говорит всякий раз, когда запрос соответствует «/ foo / bar», переписывайте его в «/ foo / baz». Запрос будет обработан так, как если бы /foo/baz был запрошен вместо Это может быть использовано для различных эффектов, например:

RewriteRule (.*) $1.html

Это правило соответствует чему угодно (.*) а также захваты Это ((..)), затем переписывает его, чтобы добавить «.html». Другими словами, если /foo/bar был запрошенный URL, он будет обрабатываться как /foo/bar.html был запрошен. Увидеть http://regular-expressions.info для получения дополнительной информации о сопоставлении регулярных выражений, захвате и заменах.

Другое часто встречающееся правило:

RewriteRule (.*) index.php?url=$1

Это снова сопоставляет что-либо и переписывает его в файл index.php с первоначально запрошенным URL, добавленным в url параметр запроса. Т.е. для всех поступающих запросов выполняется файл index.php, и этот файл будет иметь доступ к исходному запросу в $_GET['url']так что он может делать с ним все, что захочет.

Прежде всего, вы помещаете эти правила переписывания в свой файл конфигурации веб-сервера. Apache также позволяет * помещать их в файл с именем .htaccess в корне вашего документа (то есть рядом с вашими .php файлами).

* Если разрешено основным файлом конфигурации Apache; это необязательно, но часто включено.

mod_rewrite волшебным образом не делает все ваши URL «красивыми». Это распространенное недоразумение. Если у вас есть эта ссылка на вашем веб-сайте:

<a href="/my/ugly/link.php?is=not&amp;very=pretty">

mod_rewrite ничего не может сделать, чтобы сделать ее красивой. Чтобы сделать эту ссылку красивой, вам необходимо:

  1. Измените ссылку на симпатичную ссылку:

    <a href="/my/pretty/link">
    
  2. Используйте mod_rewrite на сервере для обработки запроса к URL /my/pretty/link используя любой из методов, описанных выше.

(Можно использовать mod_substitute для преобразования исходящих HTML-страниц и содержащихся в них ссылок. Хотя обычно это больше усилий, чем просто обновление ваших HTML-ресурсов.)

Mod_rewrite может многое сделать, и вы можете создать очень сложные правила сопоставления, включая цепочку нескольких переписываний, передачу запросов на совершенно другой сервис или компьютер, возврат определенных кодов состояния HTTP в виде ответов, перенаправление запросов и т. Д. Это очень мощный инструмент, который можно использовать для очень хорошо, если вы понимаете фундаментальный механизм HTTP-запроса-ответа. Оно делает не автоматически сделать ваши ссылки красивыми.

Увидеть официальная документация для всех возможных флагов и опций.

95

Другие решения

Расширить на ответ децезе, Я хотел предоставить несколько примеров и объяснение некоторых других функций mod_rewrite.

Все приведенные ниже примеры предполагают, что вы уже включили RewriteEngine On в вашем .htaccess файл.

Давайте возьмем этот пример:

RewriteRule ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ /blog/index.php?id=$1&title=$2 [NC,L,QSA]

Правило разделено на 4 раздела:

  1. RewriteRule — запускает правило перезаписи
  2. ^blog/([0-9]+)/([A-Za-z0-9-\+]+)/?$ — Это называется шаблоном, однако я просто буду называть его левой частью правила — то, что вы хотите переписать с
  3. blog/index.php?id=$1&title=$2 — называется заменой или правой частью правила перезаписи — к чему вы хотите переписать
  4. [NC,L,QSA] флаги для правила перезаписи, разделенные запятой, о которых я расскажу позже.

Переписанное выше позволит вам сделать ссылку на что-то вроде /blog/1/foo/ и это будет на самом деле загрузить /blog/index.php?id=1&title=foo,

Левая сторона правила

  • ^ указывает на начало названия страницы — поэтому она будет переписана example.com/blog/... но нет example.com/foo/blog/...
  • Каждый набор (…) Скобки представляют собой регулярное выражение, которое мы можем записать в виде переменной в правой части правила. В этом примере:
    • Первый набор скобок — ([0-9]+) — соответствует строке длиной не менее 1 символа и только числовыми значениями (т. е. 0-9). На это можно ссылаться с $1 в правой части правила
    • Второй набор скобок соответствует строке длиной не менее 1 символа, содержащей только буквенно-цифровые символы (A-Z, a-z или 0-9) или - или же + (нота + экранируется с помощью обратной косой черты, поскольку без экранирования это будет выполняться как регулярное выражение). На это можно ссылаться с $2 в правой части правила
  • ? означает, что предыдущий символ является необязательным, поэтому в этом случае оба /blog/1/foo/ а также /blog/1/foo переписал бы туда же
  • $ указывает на то, что это конец строки, которую мы хотим сопоставить

Флаги

Это параметры, которые добавляются в квадратные скобки в конце правила перезаписи для указания определенных условий. Опять же, есть много разных флагов, которые вы можете прочитать в документация, но я пойду через некоторые из наиболее распространенных флагов:

NC

Флаг без регистра означает, что правило перезаписи нечувствительно к регистру, поэтому для приведенного выше примера правила это будет означать, что оба /blog/1/foo/ а также /BLOG/1/foo/ (или любой вариант этого) будет соответствовать.

L

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

END

Начиная с Apache 2.4 вы также можете использовать [END] флаг. Соответствующее правило с ним будет полностью прекратить дальнейшую обработку псевдонима / перезаписи. (Принимая во внимание, что [L] флаг может часто запускать второй раунд, например, при перезаписи в или из подкаталогов.)

QSA

Флаг добавления строки запроса позволяет нам передавать дополнительные переменные по указанному URL, которые будут добавлены к исходным параметрам получения. Для нашего примера это означает, что что-то вроде /blog/1/foo/?comments=15 будет загружать /blog/index.php?id=1&title=foo&comments=15

R

Этот флаг не тот, который я использовал в приведенном выше примере, но я думаю, стоит упомянуть. Это позволяет вам указать перенаправление http с возможностью включения кода состояния (например, R=301). Например, если вы хотите сделать редирект 301 в / myblog / to / blog /, вы просто напишите правило примерно так:

RewriteRule ^/myblog/(*.)$ /blog/$1 [R=301,QSA,L]

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

# if the host doesn't start with www. then add it and redirect
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Это очень распространенная практика, которая добавляет ваш домен к www. (если его там еще нет) и выполните перенаправление 301. Например, загрузка http://example.com/blog/ это перенаправит вас на http://www.example.com/blog/

# if it cant find the image, try find the image on another domain
RewriteCond %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)$ http://www.example.com/$1 [L]

Это немного реже, но это хороший пример правила, которое не выполняется, если имя файла является каталогом или файлом, который существует на сервере.

  • %{REQUEST_URI} \.(jpg|jpeg|gif|png)$ [NC] выполнит перезапись только для файлов с расширением jpg, jpeg, gif или png (без учета регистра).
  • %{REQUEST_FILENAME} !-f проверит, существует ли файл на текущем сервере, и выполнит перезапись, только если его нет
  • %{REQUEST_FILENAME} !-d проверит, существует ли файл на текущем сервере, и выполнит перезапись, только если его нет
  • Перезапись попытается загрузить тот же файл в другом домене
72

Рекомендации

Переполнение стека имеет много другие большие ресурсы, чтобы начать:

И обзоры регулярных выражений даже для новичков:

Неиспользуемые заполнители

  • .* соответствует чему угодно, даже пустой строке. Вы не хотите использовать этот шаблон везде, но часто в последнем запасном правиле.
  • [^/]+ чаще используется для сегментов пути. Это соответствует чему угодно, кроме косой черты.
  • \d+ соответствует только числовым строкам.
  • \w+ соответствует буквенно-цифровым символам Это в основном сокращение для [A-Za-z0-9_],
  • [\w\-]+ для сегментов пути в стиле «slug», используя буквы, цифры, тире - а также _
  • [\w\-.,]+ добавляет точки и запятые. Предпочитаю сбежавшего \- броситься в […] charclasses.
  • \. обозначает буквальный период. Иначе . вне […] является заполнителем для любого символа.

Каждый из этих заполнителей обычно упакован в (…) скобки как группа захвата. И вся картина часто в ^………$ маркеры начала + конца. Цитировать «шаблоны» необязательно.

Следующие примеры ориентированы на PHP и немного более инкрементны, их легче адаптировать для подобных случаев.
Это просто резюме, часто ссылающиеся на больше вариантов или подробные вопросы.&Как.

  • Статическое отображение
    /contact, /about

    Сократить несколько имен страниц до внутренних схем файлов проще всего:

     RewriteRule ^contact$  templ/contact.html
    RewriteRule ^about$    about.php
    
  • Числовые идентификаторы
    /object/123

    Представляем ярлыки, такие как http://example.com/article/531 к существующим сценариям PHP также легко. Числовой заполнитель может быть просто переназначен на $_GET параметр:

     RewriteRule ^article/(\d+)$    article-show.php?id=$1
    #                      └───────────────────────────┘
    
  • Заполнители в стиле слизней
    /article/with-some-title-slug

    Вы можете легко расширить это правило, чтобы учесть /article/title-string заполнители:

     RewriteRule ^article/([\w-]+)$    article-show.php?title=$1
    #                       └────────────────────────────────┘
    

    Обратите внимание, что ваш сценарий должен быть в состоянии (или адаптироваться) отображать эти заголовки обратно в идентификаторы базы данных. Только RewriteRules не может создавать или угадывать информацию из воздуха.

  • Слизни с числовыми префиксами
    /readable/123-plus-title

    Поэтому вы часто будете видеть смешанные /article/529-title-slug Пути, используемые на практике:

     RewriteRule ^article/(\d+)-([\w-]+)$    article.php?id=$1&title=$2
    #                      └───────────────────────────────┘
    

    Теперь вы можете просто пропустить прохождение title=$2 во всяком случае, потому что ваш сценарий, как правило, будет опираться на идентификатор базы данных в любом случае. -title-slug стал произвольным украшением URL.

  • Однородность с альтернативными списками
    /foo/… /bar/… /baz/…

    Если у вас есть похожие правила для нескольких путей к виртуальным страницам, вы можете сопоставить и сжать их | альтернативные списки. И снова просто переназначить их на внутренние параметры GET:

     #                               ┌─────────────────────────┐
    RewriteRule ^(blog|post|user)/(\w+)$  disp.php?type=$1&id=$2
    #               └───────────────────────────────────┘
    

    Вы можете разделить их на отдельные RewriteRuleЕсли это станет слишком сложным.

  • Отправка связанных URL-адресов в разные бэкэнды
    /date/SWITCH/backend

    Более практичным использованием альтернативных списков является сопоставление путей запросов с различными сценариями. Например, чтобы предоставить унифицированные URL-адреса для старых и новых веб-приложений на основе дат:

     #                   ┌─────────────────────────────┐
    #                   │                 ┌───────────┼───────────────┐
    RewriteRule ^blog/(2009|2010|2011)/([\d-]+)/?$ old/blog.php?date=$2
    RewriteRule ^blog/(\d+)/([\d-]+)/?$  modern/blog/index.php?start=$2
    #                          └──────────────────────────────────────┘
    

    Это просто переназначает записи 2009-2011 годов в один сценарий, а все остальные годы неявно — в другой обработчик.
    Обратите внимание более конкретное правило приходит первым. Каждый скрипт может использовать разные параметры GET.

  • Другие разделители, чем просто / косые черты
    /user-123-name

    Вы чаще всего видите RewriteRules для имитации структуры виртуальных каталогов. Но вы не обязаны быть нетворческими. Вы можете также использовать - дефисы для сегментации или структуры.

     RewriteRule ^user-(\d+)$    show.php?what=user&id=$1
    #                   └──────────────────────────────┘
    # This could use `(\w+)` alternatively for user names instead of ids.
    

    Для также общего /wiki:section:Page_Name схема:

     RewriteRule ^wiki:(\w+):(\w+)$  wiki.php?sect=$1&page=$2
    #                   └─────┼────────────────────┘       │
    #                         └────────────────────────────┘
    

    Иногда целесообразно чередовать /ограничители и : или же . в том же правиле даже. Или снова используйте два RewriteRules для сопоставления вариантов с разными сценариями.

  • Дополнительный трейлинг / слэш
    /dir знак равно /dir/

    Выбирая пути в стиле каталога, вы можете сделать его доступным с окончательным /

     RewriteRule ^blog/([\w-]+)/?$  blog/show.php?id=$1
    #                         ┗┛
    

    Теперь это обрабатывает как http://example.com/blog/123 а также /blog/123/, И /?$ подход легко добавить к любому другому RewriteRule.

  • Гибкие сегменты для виртуальных путей
    .*/.*/.*/.*

    Большинство правил, с которыми вы столкнетесь, отображают ограниченный набор /…/ путь ресурса сегментируется к отдельным параметрам GET. Некоторые скрипты обрабатывать переменное количество опций тем не мение.
    Движок регулярных выражений Apache не позволяет произвольно выбирать их число. Но вы можете легко развернуть его в блок правил самостоятельно:

     Rewriterule ^(\w+)/?$                in.php?a=$1
    Rewriterule ^(\w+)/(\w+)/?$          in.php?a=$1&b=$2
    Rewriterule ^(\w+)/(\w+)/(\w+)/?$    in.php?a=$1&b=$2&c=$3
    #              └─────┴─────┴───────────────────┴────┴────┘
    

    Если вам нужно до пяти сегментов пути, скопируйте эту схему в пять правил. Вы можете, конечно, использовать более конкретный [^/]+ заполнитель каждого.
    Здесь порядок не так важен, так как не совпадает. Итак, иметь наиболее часто используемые пути в порядке.

    В качестве альтернативы вы можете использовать параметры массива PHP через ?p[]=$1&p[]=$2&p[]=3 Строка запроса здесь — если ваш сценарий просто предпочитает их предварительно разделить.
    (Хотя более распространенным является использование правила перехвата всех и позволить самому сценарию расширять сегменты из REQUEST_URI.)

    Смотрите также: Как мне преобразовать мои сегменты пути URL в пары ключ-значение строки запроса?

  • Дополнительные сегменты
    prefix/opt?/.*

    Распространенным вариантом является наличие дополнительных префиксов в правило. Обычно это имеет смысл, если у вас есть статические строки или более ограниченные заполнители:

      RewriteRule ^(\w+)(?:/([^/]+))?/(\w+)$  ?main=$1&opt=$2&suffix=$3
    

    Теперь более сложная картина (?:/([^/])+)? там просто заворачивается без захвата (?:…) группа, и делает это необязательным )?, Содержится
    заполнитель ([^/]+) будет образец замещения $2, но будь пуст, если нет середины /…/ дорожка.

  • Захватить остаток
    /prefix/123-capture/…/*/…whatever…

    Как уже говорилось ранее, вам не часто нужны слишком общие шаблоны перезаписи. Однако имеет смысл объединить статические и конкретные сравнения с .* иногда.

     RewriteRule ^(specific)/prefix/(\d+)(/.*)?$  speci.php?id=$2&otherparams=$2
    

    Это необязательно /…/…/… конечные отрезки пути. Что, конечно, требует сценария обработки, чтобы разделить их, и variabl-римент извлеченные параметры
    сам (что к чему WEB- «MVC» рамки делают).

  • Конечный файл «расширения»
    /old/path.HTML

    URL не имеют расширений файлов. Вот о чем вся эта ссылка (= URL-адреса являются виртуальными локаторами, не обязательно прямым образом файловой системы).
    Однако, если у вас раньше было отображение файла 1: 1, вы Можно выработать более простые правила:

     RewriteRule  ^styles/([\w\.\-]+)\.css$  sass-cache.php?old_fn_base=$1
    RewriteRule  ^images/([\w\.\-]+)\.gif$  png-converter.php?load_from=$2
    

    Другие общие виды использования являются переназначением устаревших .html пути к новым .php обработчики или просто псевдонимы имен каталогов только для отдельных (реальных / реальных) файлов.

  • Пинг-понг (перенаправляет и переписывает в унисон)
    /ugly.html ← → /pretty

    Так что в какой-то момент вы переписываете свои HTML-страницы, чтобы содержать только красивые ссылки, как обрисованный в общих чертах deceze.
    Тем временем вы все равно будете получать запросы на старый дорожки, иногда даже из закладок. Как обходной путь, вы можете пинг-понг браузеры для отображения / установки
    новые URL.

    Этот общий трюк включает в себя отправку 30x / Location переадресовывать всякий раз, когда входящий URL следует устаревшей / уродливой схеме именования.
    Браузеры будут тогда rerequest новый / красивый URL, который впоследствии переписывается (только внутри) в исходное или новое местоположение.

     # redirect browser for old/ugly incoming paths
    RewriteRule ^old/teams\.html$ /teams [R=301,QSA,END]
    
    # internally remap already-pretty incoming request
    RewriteRule ^teams$ teams.php        [QSA,END]
    

    Обратите внимание, как этот пример просто использует [END] вместо [L] безопасно чередовать. Для более старых версий Apache 2.2 вы можете использовать и другие обходные пути, кроме переотображения
    параметры строки запроса, например:
    Перенаправить некрасивый на красивый URL, переназначить обратно на безобразный путь без бесконечных циклов

  • пространства в шаблонах
    /this+that+

    Это не это довольно в адресной строке браузера, но вы можете использовать пробелы в URL. Для перезаписи шаблонов используйте обратную косую черту \␣ пространства.
    Остальное просто "-цитировать весь шаблон или замену:

     RewriteRule  "^this [\w ]+/(.*)$"  "index.php?id=$1"  [L]
    

    Клиенты сериализуют URL с + или же %20 для пробелов. Тем не менее, в RewriteRules они интерпретируются буквальными символами для всех относительных сегментов пути.

Частые дубликаты:

Теперь возьмите это с зерном соли. Не каждый совет может быть распространен на все контексты.
Это просто краткое изложение известных и несколько неочевидных камней преткновения:

  • включить mod_rewrite а также .htaccess

    Чтобы фактически использовать RewriteRules в файлах конфигурации для каждого каталога, вы должны:

    • Проверьте, что ваш сервер имеет AllowOverride All включен. В противном случае ваш каталог .htaccess директивы будут игнорироваться, а RewriteRules не будет работать.

    • очевидно иметь mod_rewrite включен в вашем httpd.conf раздел модулей.

    • Добавить каждый список правил RewriteEngine On еще. Хотя mod_rewrite неявно активен в <VirtualHost> а также <Directory> секции,
      на каталог .htaccess файлы нужны индивидуально.

  • Ведущий слеш ^/ не будет соответствовать

    Вы не должны начинать .htaccess Переписать шаблоны с ^/ обычно:

     RewriteRule ^/article/\d+$  …
    ↑
    

    Это часто встречается в старых уроках. И это было правильно для древних версий Apache 1.x. В настоящее время пути запроса удобно от корки до корки Каталог-родственница в .htaccess RewriteRules. Просто оставь ведущий / из.

    · Обратите внимание, что начальная косая черта все еще корректна в <VirtualHost> разделы хотя. Вот почему вы часто видите это ^/? необязательный для паритета правила.
    · Или при использовании RewriteCond %{REQUEST_URI} ты бы все равно соответствовал лидирующему /,
    · Смотрите также Webmaster.SE: Когда в шаблонах mod_rewrite требуется начальная косая черта (/)?

  • <IfModule *> фантики

    Вы, наверное, видели это во многих примерах:

    <IfModule mod_rewrite.c>
    Rewrite…
    </IfModule>
    
    • Это делает иметь смысл в <VirtualHost> разделы — если он был объединен с другим резервным вариантом, таким как ScriptAliasMatch. (Но никто никогда не делает это).
    • И это обычно распространяется по умолчанию .htaccess наборы правил со многими проектами с открытым исходным кодом. Там он просто подразумевается как запасной вариант и по умолчанию сохраняет «некрасивые» URL-адреса.

    Однако ты не хочу что обычно в вашем собственном .htaccess файлы.

    • Во-первых, mod_rewrite не отключается случайным образом. (Если это произойдет, у вас будут большие проблемы).
    • Если бы он был действительно отключен, ваши RewriteRules все равно не работали бы.
    • Он предназначен для предотвращения HTTP 500 ошибки. Обычно это дает вашим пользователям HTTP 404 ошибки вместо. (Не так много более удобным, если вы об этом думаете.)
    • Практически это просто подавляет более полезные записи журнала или почтовые уведомления сервера. Вы бы не мудрее относительно того, почему ваши RewriteRules никогда не работают.

    То, что кажется заманчивым как общая гарантия, часто оказывается препятствием на практике.

  • Не использовать RewriteBase если не нужно

    Многие примеры копирования + вставки содержат RewriteBase / директивы. Что в любом случае оказывается неявным значением по умолчанию. Так что вам на самом деле это не нужно. Это обходной путь для причудливых схем перезаписи VirtualHost и неправильных путей DOCUMENT_ROOT для некоторых общих хостеров.

    Имеет смысл использовать с отдельными веб-приложениями в более глубоких подкаталогах. В таких случаях это может сократить шаблоны RewriteRule. Обычно лучше указывать относительные пути в наборах правил для каждого каталога.

    Смотрите также Как RewriteBase работает в .htaccess

  • запрещать MultiViews когда виртуальные пути перекрываются

    Перезапись URL в основном используется для поддержки виртуальный входящие пути. Обычно у вас есть только один диспетчерский скрипт (index.php) или несколько отдельных обработчиков (articles.php, blog.php, wiki.php…) Последний может столкнуться с похожими виртуальными путями RewriteRule.

    Запрос на /article/123 например, может сопоставить с article.php с /123 PATH_INFO неявно. Вы либо должны были бы охранять свои правила тогда с обычным делом RewriteCond !-f+!-dи / или отключить поддержку PATH_INFO, или, возможно, просто отключить Options -MultiViews,

    Что не всегда сказать вам должен. Content-Negotiation — это просто автоматизация виртуальных ресурсов.

  • Заказ важен

    Увидеть Все, что вы когда-либо хотели знать о mod_rewrite
    если вы еще этого не сделали Объединение нескольких RewriteRules часто приводит к взаимодействию. Это не то, что обычно мешает [L] флаг, но схема, которую вы примете однажды разбирается.
    Вы Можно ре-ре-резаписывать виртуальные пути от одного правила к другому, пока он не достигнет фактического целевого обработчика.

    Тем не менее, вы бы довольно часто хотите иметь наиболее конкретные правила (фиксированная строка /forum/… шаблоны или более ограничительные заполнители [^/.]+) в рано правила.
    Общие правила Slurp-all (.*) лучше оставить потом из них. (Исключением является RewriteCond -f/-d охрана как основной блок.)

  • Таблицы стилей и изображения перестают работать

    Когда вы вводите структуры виртуальных каталогов /blog/article/123 это влияет на относительные ссылки на ресурсы в HTML (такие как <img src=mouse.png>).
    Что может быть решено путем:

    • Только с использованием серверных абсолютных ссылок href="/old.html" или же src="/logo.png"
    • Часто просто добавляя <base href="/index"> в ваш HTML <head> раздел.
      Это косвенно связывает относительные ссылки на то, что они были раньше.

    В качестве альтернативы вы можете создать дополнительные RewriteRules для повторного связывания .css или же .png пути к их оригинальным местам.
    Но это как ненужное, так и влечет за собой дополнительные перенаправления и затрудняет кеширование.

    Смотрите также: CSS, JS и изображения не отображаются с красивым URL

  • RewriteConds просто маскирует один RewriteRule

    Распространенная неправильная интерпретация заключается в том, что RewriteCond блокирует несколько RewriteRules (потому что они визуально расположены вместе):

     RewriteCond %{SERVER_NAME} localhost
    RewriteRule ^secret  admin/tools.php
    RewriteRule ^hidden  sqladmin.cgi
    

    Что это не по умолчанию. Вы можете приковать их с использованием [S=2] флаг. Иначе вам придется их повторять. Хотя иногда вы можете создать «перевернутое» первичное правило для [END] обработки перезаписи на ранней стадии.

  • QUERY_STRING освобождается от RewriteRules

    Вы не можете соответствовать RewriteRule index.php\?x=yпотому что mod_rewrite сравнивает только с относительными путями по умолчанию. Вы можете сопоставить их отдельно, однако через:

     RewriteCond %{QUERY_STRING} \b(?:param)=([^&]+)(?:&|$)
    RewriteRule ^add/(.+)$  add/%1/$1  # ←──﹪₁──┘
    

    Смотрите также Как я могу сопоставить переменные строки запроса с mod_rewrite?

  • .htaccess против <VirtualHost>

    Если вы используете RewriteRules в конфигурационном файле для каждого каталога, то беспокоиться о производительности регулярных выражений бессмысленно. Apache сохраняет
    скомпилированные шаблоны PCRE длиннее PHP-процесса с общей структурой маршрутизации. Однако для сайтов с большим трафиком следует учитывать
    перемещение наборов правил в конфигурацию сервера vhost после того, как они были испытаны в бою.

    В этом случае предпочитайте необязательный ^/? префикс разделителя каталогов. Это позволяет свободно перемещать RewriteRules между PerDir и сервером
    конфигурационные файлы.

  • Всякий раз, когда что-то не работает

    Не волнуйтесь.

    • сравнить access.log а также error.log

      Часто вы можете понять, как RewriteRule плохо себя ведет, просто глядя на ваш error.log а также access.log,
      Соотнесите время доступа, чтобы увидеть, какой путь запроса был изначально введен, и какой путь / файл не удалось разрешить Apache (ошибка 404/500).

      Это не говорит вам, какой RewriteRule является виновником. Но недоступные конечные пути, такие как /docroot/21-.itle?index.php может дать, где осмотреть дальше.
      В противном случае отключите правила, пока не получите предсказуемые пути.

    • Включить RewriteLog

      Увидеть Apache RewriteLog Docs. Для отладки вы можете включить его в разделах vhost:

      # Apache 2.2
      RewriteLogLevel 5
      RewriteLog /tmp/rewrite.log
      
      # Apache 2.4
      LogLevel alert rewrite:trace5
      #ErrorLog /tmp/rewrite.log
      

      Это дает подробную сводку того, как пути входящих запросов модифицируются каждым правилом:

      [..] applying pattern '^test_.*$' to uri 'index.php'
      [..] strip per-dir prefix: /srv/www/vhosts/hc-profi/index.php -> index.php
      [..] applying pattern '^index\.php$' to uri 'index.php'
      

      Что помогает сузить слишком общие правила и неудачи регулярных выражений.

      Смотрите также:
      · .htaccess не работает (mod_rewrite)
      · Советы по отладке .htaccess переписать правила

    • Прежде чем задать свой вопрос

      Как вы, возможно, знаете, Stack Overflow очень подходит для того, чтобы задавать вопросы по mod_rewrite. Сделать их по теме
      Включая предыдущие исследования и попытки (избегать лишних ответов), продемонстрируйте основные понимание и:

      • Включают полный примеры входных URL, ошибочно переписанные целевые пути, ваша реальная структура каталогов.
      • Полный набор RewriteRule, но также выделите предполагаемый дефектный.
      • Версии Apache и PHP, тип ОС, файловая система, DOCUMENT_ROOT и PHP $_SERVER среда, если речь идет о несоответствии параметров.
      • Выдержка из вашего access.log а также error.log чтобы проверить, к чему разрешены существующие правила. Еще лучше, rewrite.log резюме.

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

  • Прокомментируйте ваш .htaccess

    Если вы копируете примеры откуда-то, постарайтесь включить # comment and origin link, Хотя это просто плохие манеры опускать атрибуцию,
    это часто действительно вредит обслуживанию позже. Документирование любого кода или учебного источника. В частности, пока вы не говорите, вы должны быть
    тем более заинтересованы в том, чтобы не относиться к ним, как к волшебным ящикам

  • Это не «SEO» -URL

    Отказ от ответственности: просто любимая мозоль. Вы часто слышите красивые схемы перезаписи URL, называемые ссылками «SEO» или что-то в этом роде. Хотя это полезно для примеров поиска в Google, это устаревший неправильный номер.

    Ни одна из современных поисковых систем действительно не обеспокоена .html а также .php в сегментах пути, или ?id=123 Строки запроса по этому вопросу. Поисковые системы старых, таких как AltaVista, сделал избегайте сканирования сайтов с потенциально неоднозначными путями доступа. Современные сканеры часто даже жаждут глубоких веб-ресурсов.

    То, для чего «концептуально» должны быть использованы концептуально, это создание сайтов удобный.

    1. Имея понятные и понятные схемы ресурсов.
    2. Обеспечение долговечности URL (AKA Permalinks).
    3. Обеспечение открываемости через /common/tree/nesting,

    Однако не жертвуйте уникальными требованиями к конформизму.

инструменты

Существуют различные онлайн-инструменты для генерации RewriteRules для большинства URL-адресов с GET-параметрами:

В основном просто вывод [^/]+ общие заполнители, но, вероятно, достаточно для тривиальных сайтов.

36

Альтернативы mod_rewrite

Многие основные схемы виртуальных URL могут быть реализованы без использования RewriteRules. Apache позволяет запускать сценарии PHP без .php расширение, и с виртуальным PATH_INFO аргумент.

  1. Использовать PATH_INFO, Люк

    Настоящее время AcceptPathInfo On часто включен по умолчанию. Что в основном позволяет .php и URL других ресурсов для переноса виртуального аргумента:

    http://example.com/script.php/virtual/path
    

    Теперь это /virtual/path появляется в PHP как $_SERVER["PATH_INFO"] где вы можете обрабатывать любые дополнительные аргументы, как вам нравится.

    Это не так удобно, как иметь отдельные сегменты входного пути Apache в $1, $2, $3 и передавая их как отдельные $_GET переменные в PHP. Он просто эмулирует «красивые URL» с меньшими усилиями по настройке.

  2. включить MultiViews скрыть .php расширение

    Самый простой вариант также отказаться от .php «Расширения файлов» в URL-адресах включает:

    Options +MultiViews
    

    Это имеет выбор Apache article.php для HTTP-запросов на /article из-за совпадения базового имени. И это хорошо работает вместе с вышеупомянутой функцией PATH_INFO. Таким образом, вы можете просто использовать URL-адреса, такие как http://example.com/article/virtual/title, Это имеет смысл, если у вас есть традиционное веб-приложение с несколькими точками вызова / сценариями PHP.

    Обратите внимание, что MultiViews имеет другое / более широкое назначение. Это влечет за собой очень незначительный снижение производительности, потому что Apache всегда ищет другие файлы с соответствующими базовыми именами. Это на самом деле предназначено для Content-Negotiation, поэтому браузеры получают лучшую альтернативу среди доступных ресурсов (таких как article.en.php, article.fr.php, article.jp.mp4).

  3. SetType или SetHandler для без расширения .php скрипты

    Более направленный подход, чтобы не носить с собой .php суффиксы в URL есть настройка обработчика PHP для других файловых схем. Самый простой вариант — переопределить тип MIME / обработчика по умолчанию через .htaccess:

    DefaultType application/x-httpd-php
    

    Таким образом, вы можете просто переименовать article.php сценарий просто article (без расширения), но все равно обрабатывать его как PHP-скрипт.

    Теперь это может иметь некоторые последствия для безопасности и производительности, потому что все файлы без расширений теперь будут передаваться через PHP. Следовательно, вы можете установить это поведение только для отдельных файлов:

    <Files article>
    SetHandler application/x-httpd-php
    # or SetType
    </Files>
    

    Это в некоторой степени зависит от настроек вашего сервера и используемого PHP SAPI. Общие альтернативы включают ForceType application/x-httpd-php или же AddHandler php5-script,

    Снова обратите внимание, что такие настройки распространяются от одного .htaccess в подпапках. Вы всегда должны отключить выполнение скрипта (SetHandler None а также Options -Exec или же php_flag engine off и т. д.) для статических ресурсов, а также для загрузки / каталогов и т. д.

  4. Другие схемы переписывания Apache

    Apache предоставляет множество возможностей mod_alias функции — которые иногда работают так же, как mod_rewrites RewriteRules. Обратите внимание, что большинство из них должны быть настроены в <VirtualHost> раздел, однако, не в каждом каталоге .htaccess конфигурационные файлы.

    • ScriptAliasMatch в первую очередь для сценариев CGI, но также должен работать на PHP. Это позволяет регулярные выражения, как и любой RewriteRule, На самом деле это, пожалуй, самый надежный вариант для настройки универсального фронт-контроллера.

    • И равнина Alias помогает с несколькими простыми схемами переписывания.

    • Даже равнина ErrorDocument Директива может быть использована, чтобы позволить PHP-скрипту обрабатывать виртуальные пути. Обратите внимание, что это хитрый обходной путь, однако запрещает что-либо, кроме запросов GET, и затопляет error.log по определению.

    Увидеть http://httpd.apache.org/docs/2.2/urlmapping.html для дальнейших советов.

5
По вопросам рекламы [email protected]