Htaccess примеры чпу – Kак сделать чтобы часть урл в чпу с htaccess начиналась после другой но кроме той же самой?

Содержание

Пример настройки файла htaccess php


Примеры записей в htaccess: Индексный файл, Редирект с сохранением рейтинга страницы, Склеивание www и http, Создание ЧПУ или ЧеловекуПонятныхУрлов, Редирект всех файлов папки на один файл, Защита от хотлинков, Определение кодировки и многое другое!

Указываем индексный файл (который первым открывает при обращении к сайту)

DirectoryIndex index.php index.html index.shtml

Можно указать один или несколько файлов

Редирект htaccess php

Redirect / http://www.newsite.ru/

Глобальный редирект(первый /) ВСЁ пересылаем на новый адрес http://www.newsite.ru/
Redirect /katalog http://www.newsite.ru/newkatalog

Все обращения к katalog переадресуем на домен newsite.ru в раздел newkatalog

Редирект с сохранением рейтинга страницы

Redirect 301 /old/old.php http://www.yoursite.ru/new.php

old — пример пути старой страницы. new — пример пути новой страницы.

Редирект пользователя с конкретным ip

SetEnvIf REMOTE_ADDR 192.100.220.1 REDIR="redir"
RewriteCond %{REDIR} redir
RewriteRule ^/$ /out.html

Конкретного пользователя (надоел он или нужно его переслать на внутренний раздел) с данным ip пересылает на страницу /out.html

Склеивание www и http htaccess php


Уже многим SEO (продвижение и оптимизация) известно, что для Поисковых Систем адреса с/без www — это разные адреса и доступность сайта с www отрицательно влияет на индексацию и ранжирование. Поэтому зачастую SEO просят разработчиков склеить сайт без www (чтобы при обращении к сайту с www происходила пересылка на без www, т.е. только http)
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www.yoursite\.ru$ [NC]
RewriteRule ^(.*)$ http://yoursite.ru/$1 [L,R=301]

Теперь даже если Вы наберёте в адресной строке www.yoursite.ru, то сервер перешлёт Вас на http://yoursite.ru

Создание ЧПУ или Человеко-Понятных-Урлов htaccess php

RewriteEngine on
RewriteRule ^article/([^/\.]+)/?$ article.php?id=$1 [L]

После добавления данной строки в .htaccess будут доступны два адреса для документа. Например: www.yoursite.ru/article.php?id=1 и www.yoursite.ru/article/1
RewriteEngine on
RewriteRule cat/(.*)/(.*)/$ /art.php?$1=$2

В результате www.yoursite.ru/art.php?type=123 превращается в www.yoursite.ru/cat/type/123/:

Вот ещё частные варианты:

RewriteEngine on
RewriteRule katalog-saitov[/]*$ article.php?id=$1 [L]

Статья с технически адресом www.yoursite.ru/article.php?id=1 теперь будет доступна со своим понятным человеку названием www.yoursite.ru/katalog-saitov.

Редирект всех файлов папки на один файл


Например вы больше не нуждаетесь в разделе сайта articles и хотите перенаправить все запросы к папке /articles на один файл /non-articles.php. Поможет код ниже
RewriteRule ^articles(.*)$ /non-articles.php [L,R=301]

Защита от хотлинков htaccess php


Возможно Вам знаком такой вариант, когда изображения на сервер не закачивают, а используют просто ссылку на сайт. В результате для сайта-владельца изображения создаётся лишняя нагрузка трафик. Используем код ниже
RewriteEngine On
#В строке с ?yoursite\.ru/ меняете данную конструкцию на УРЛ Вашего сайта
RewriteCond %{HTTP_REFERER} !^http://(.+\.)?yoursite\.ru/ [NC]
RewriteCond %{HTTP_REFERER} !^$
#Меняем /images/exit.jpg на другое изображение. Можно неприличное
RewriteRule .*\.(jpe?g|gif|bmp|png)$ /images/exit.jpg [L]

Определение кодировки htaccess php


Дополнительные варианты самых популярных кодировок: UTF-8, Windows-1251, KOI8-R. В примерах рассмотрим самую распространённую UTF-8
AddDefaultCharset UTF8 # кодировка файлов, в которой по умолчанию отдаёт документы
AddCharset UTF8 .html # Пример: обрабатывает в данной кодировке html
AddCharset UTF8 * # Пример: обрабатывает в данной кодировке Все файлы

# Обработка в данной кодировке определённого файла
<Files "index.html">
AddCharset UTF8 .html
</Files> 

CharsetDisable On # Отменяем перекодировку Сервером загруженных файлов
CharsetDefault UTF8 # Кодировка, передаваемая Сервером Браузеру по умолчанию
CharsetSourceEnc UTF8 # Принудительная Перекодировка ВСЕХ загруженных на сервер файлов

Создание своих страниц ошибок


Если Вам хочется видеть после неправильной ссылки другую страницу, сделанную, например, самим собой, то указываем в .htaccess следующий код (ну и соответственно делаем там свои страницы):
# ошибка сервера, неверный запрос
ErrorDocument 400 /error/badrequest.html

# неавторизован
ErrorDocument 401 /error/authreqd.html

# вход запрещён
ErrorDocument 403 /error/forbid.html

# самая распространённая - страница не найдена
ErrorDocument 404 /error/notfound.html

# внутренняя ошибка сервера
ErrorDocument 500 /error/serverr.html


Видов ошибок на самом деле больше. Можете создать дополнительно и для них записи, опираясь на весь список

Запрещаем доступ


Скорее всего Вы столкнётесь с тем, что часть файлов и директорий надо будет закрыть от общего доступа.

Закрываем от всех

deny from all

Закрываем конкретный файл от всех

<Files admin.php>
deny from all
</Files>

Разрешаем доступ только с одного ip

order deny,allow
deny from all
allow from 192.111.37.125

Запрещаем доступ с конкретных ip

<Limit GET POST PUT>
order allow,deny
allow from all
deny from 192.111.35.122
deny from 192.111.37.171
</LIMIT>

Убираем из Урла (URL) расширение файла

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.php
# php можно заменить другим расширением. Например: html, htm, shtml, asp

Запрещаем отображать содержимое директории, если нет индексного файла


Вы скорее всего хоть раз видели текст Index of и список файлов. Так происходит в том случае, когда в директории нет индексного файла (например index.php), а система предлагает выбрать файл для дальнейшего открытия. Минус этого заключается в том, что случайный пользователь может увидеть список и содержание всех файлов директории.
Options -Indexes

Преобразование входящих ЧПУ с помощью модуля MOD_REWRITE

Преобразование входящих ЧПУ с помощью модуля MOD_REWRITE

Здравствуйте уважаемый посетитель!

В прошлой статье мы преобразовали динамические ссылки в статические адреса с использованием человеко-понятных урлов (ЧПУ).

Сегодня сделаем обратные преобразования — из входящих ЧПУ с помощью модуля MOD_REWRITE получим обычные динамические URL. После чего, для проверки выполненных преобразований, используя PHP выведем соответствующие GET-параметры на HTML-страницу.

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

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

  • Составляем шаблоны правила RewriteRule модуля MOD_REWRITE
  • Формируем динамические ссылки используя подстановку в RewriteRule
  • Вносим необходимые дополнения в файл ‘.htaccess’
  • Проверяем выполненные преобразования
  • Исходные файлы сайта

Составляем шаблоны правила RewriteRule модуля MOD_REWRITE


Смысл выполнения преобразований из статических ссылок в динамических — это возможность использования полученных значений GET-параметров для идентификации запросов и формирования динамических страниц.

Конечно, с помощью функций PHP можно извлекать из адреса нужные текстовые фрагменты и выполнять его проверку на соответствие регулярным выражениям и дальше с этим работать. Но более логичный и простой способ — это использовать для такого преобразования правило RewriteRule модуля MOD_REWRITE веб-сервера Apache.

Ранее, при выполнении первого, наиболее простого способа применения ЧПУ, в предыдущей статье в разделе Перенаправляем запросы с ЧПУ на главную страницу сайта мы уже использовали модуль MOD_REWRITE. Где рассматривали довольно простой вариант применения в правиле RewriteRule аргументов, определяющих «шаблон» «подстановку» «флаг» для перенаправления всех запросов пользователей на главную страницу сайта.

Тогда в качестве шаблона использовалось регулярное выражение ^(.*)$, при котором правило RewriteRule должно выполняться для любых входящих ссылок. А вторым аргументом являлся адрес главной страницы (файл index.php).

Теперь же, для того, чтобы получить из входящих ЧПУ динамические адреса, необходимо в файле «.htaccess» изменить это правило. А если быть точнее, заменить его на несколько правил, в которых запросы будут обрабатываться для разных вариантов текущих URL.

В нашем случае необходимо создать правила для трех вариантов входящих ссылок:

  • при наличии в адресе ЧПУ трех элементов, разделенных знаком слеш «/», что соответствует максимальному количеству используемых GET-параметров;
  • при входящих ссылках с двумя параметрами;
  • при ссылках с одним параметром.

Количество правил определено из ранее установленного максимального уровня вложенности страниц равного 3. При его увеличении следует добавить и соответствующие правила.

При этом, в каждом правиле в случае совпадения с заданными шаблонами, запросы также должны перенаправляться по адресу «index.php». Но теперь при подстановке URL требуется выполнять преобразование входящего ЧПУ в обычную динамическую ссылку с применением GET-параметров.

Для того, чтобы более подробно это рассмотреть, составим правило RewriteRule для варианта ранее используемой ссылки с максимальным количеством параметров. А именно, преобразуем статическую ЧПУ-ссылку httρ://newsite.local/statyi/ugon-avtomobiley/statistika-ugonov-2016 в обычную динамическую httρ://newsite.local/index.php?section=statyi&rubric=ugon-avtomobiley&page=statistika-ugonov-2016.

И в первую очередь составим шаблон для элементов статической ссылки, основанный на регулярном выражении. Если по-простому — регулярные выражения это система текстового разбора, которая обычно используется для поиска и замены подстроки по шаблону.

Конечно, тема регулярных выражений заслуживает отдельного внимания. И для большего понимания, наверное, следует более подробно ознакомиться с теорией этого вопроса из специально предназначенных для этого источников. Тем более, что в интернете можно найти большое количество описаний синтаксиса этих выражений. Например, уже упомянутый раздел Модуль Apache mod_rewrite одного из интернет-ресурсов.

скриншот 11

Здесь же при практическом применении правила RewriteRule мы остановимся на тех моментах, которые касаются нашего примера.

На рис.1 графически изображено как на основе используемой нами статической ссылки можно создать шаблон для поиска нужной подстроки, присутствующей в текущем URL.

Преобразование входящих ЧПУ с помощью модуля MOD_REWRITE, картинка 1

Рис.1 Создание шаблона в правиле RewriteRule

Как видно шаблон состоит из начала строки — символ «^», конца строки — знак доллара «$», слеш «/», разделяющий ссылку на элементы и трех регулярных выражений для каждой части адресной строки.

Сначала разберем регулярное выражение для первой группы шаблона — ([A-Za-z0-9-]+).

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

Теперь рассмотрим символы, которые используются в этом выражении.

  • ( ) — выделение группы символов;
  • [ ] — определение класса символов — все, что находится в скобках являются допустимыми символами;
  • A-Z — все заглавные буквы латинского алфавита;
  • a-z — все прописные буквы латинского алфавита;
  • 0-9 — все цифры от 0 до 9;
  • — знак тире.
  • + — относится к квантификаторам (кванторам), определяющим количественное соотношение предшествующих символов. В данном случае + означает, что может присутствовать один или любое другое количество символов. В иных случаях могут быть применены другие кванторы, такие как:
  • ? — 0 или 1 символ из предшествующего текста;
  • * — 0 или любое количество символов из предшествующего текста.

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

Теперь рассмотрим символы, которые используются в регулярном выражении во второй части шаблона — ([^/]+).

Здесь все значительно проще. Указывается только то, что в этом выражении исключается знак слеш «/». Это обусловлено тем, чтобы исключить использование знака, совпадающего с разделительным символом.

А для этого используется класс символов вида [^символы исключения], означающий, что шаблон не должен содержать символы, следующие за знаком «^«. В данном случае в этой части шаблон не должен содержать слеш «/».

Что же касается используемого здесь знака «+«, то как было ранее отмечено, это означает, что в этой группе может быть 1 или любое другое количество символов.

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

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

  • . — любой одиночный символ;
  • * — означает, что символ может присутствовать неограниченное число раз, либо отсутствовать;

Третий аргумент директивы RewriteRule, а именно — флаг [L] («last» последнее правило), который ранее мы уже использовали, предназначен для остановки выполнения остальных правил. Что является совершенно логичным в этом наборе директив модуля MOD_REWRITE.

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

Например, если требуется использовать в группах такие символы, как: «. [ ] ( ) ? >» в качестве их прямого значения, а не в составе каких-либо синтаксических конструкций, то перед таким символами следует применять знак обратный слеш «\«.

И последнее, и очень важное, это то, что найденные соответствия в каждой группе будут возвращаться в отдельных переменных $1,$2 и т.д. по количеству групп. И именно значения этих переменных будут использоваться в последующих преобразованиях в строке подстановки правила RewriteRule. На рис.1 это выделено отдельным фрагментом.

В нашем случае:

  • группа ([A-Za-z0-9-]+) соответствует переменной S1;
  • ([^/]+)S2;
  • (.*)$S3.

И теперь, получив эти переменные перейдем к формированию динамической ссылки.

Формируем динамические ссылки используя подстановку в RewriteRule


Формирование строк подстановки правила RewriteRule значительно проще, чем написание регулярных выражений шаблонов. Для нашего случая достаточно будет лишь составить обычную динамическую ссылку. С той лишь разницей, что здесь вместо конкретных значений GET-параметров будут применяться значения ранее полученных переменных $1,$2 и $3, как показано на рис.2.

Преобразование входящих ЧПУ с помощью модуля MOD_REWRITE, картинка 2

Рис.2 Формирование динамической ссылки в строке подстановки правила RewriteRule

Наверное, здесь комментарии излишни. Поэтому сразу перейдем к следующему этапу преобразований.

Вносим необходимые дополнения в файл ‘.htaccess’


Ниже показан код файла «.htaccess», с помощью которого на основе полученного выше правила RewriteRule будут выполняться преобразования из статических ЧПУ в динамические ссылки (как обычно строки с изменениями выделены более светлым фоном).

  1. AddDefaultCharset UTF-8

  2. RewriteEngine on

  3. RewriteCond %{REQUEST_FILENAME} !-d

  4. RewriteCond %{REQUEST_FILENAME} !-f

  5. RewriteRule ^([A-Za-z0-9-]+)/([^/]+)/(.*)$ index.php?section=$1&rubric=$2&page=$3 [L]

  6. RewriteCond %{REQUEST_FILENAME} !-d

  7. RewriteCond %{REQUEST_FILENAME} !-f

  8. RewriteRule ^([A-Za-z0-9-]+)/([^/]+)$ index.php?section=$1&rubric=$2 [L]

  9. RewriteCond %{REQUEST_FILENAME} !-d

  10. RewriteCond %{REQUEST_FILENAME} !-f

  11. RewriteRule ^([A-Za-z0-9-]+)$ index.php?section=$1 [L]

Рис.3 Преобразование в файле «.htaccess» входящих ЧПУ в обычные динамические ссылки

Здесь в строках 5,8.11 присутствуют правила для вариантов ссылок с разным количеством параметров — с тремя, который мы рассматривали выше (поз.5), с двумя без параметра page(поз.8) и с одним параметром section(поз.11).

А в строках 3,4,6,7,9,10 применены директивы RewriteCond, определяющие условия при которых могут выполняться следующие за ними правила RewriteRule.

Так как условия RewriteCond влияют только на одно следующее за ними правило, то они должны здесь повторяться перед каждым правилом.

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

В итоге, после этих преобразова

Cоздание ЧПУ в .htaccess | Vavik96

Основной проблемой любого динамического сайта является отсутствие читабельного URL-адреса. В тоже время, читабельный URL-адрес это подсказка о содержащемся на веб-странице контенте. Таким образом, возникает необходимость создать полноценный ЧПУ. Решением может служить использования модуля преобразований на стороне веб-сервера. В данной статье я хочу помочь Вам решить задачи по созданию ЧПУ и настройке преобразований в файле .htaccess с целью дальнейшей обработки запросов пользователей в PHP-скрипте.

Содержание:

  • Создание ЧПУ
  • Настройка преобразований в .htaccess
    • Разбор регулярного выражения в RewriteRule
  • Обработчик ЧПУ на PHP
  • Подведём итоги

Создание ЧПУ

А начну я с того, что  использование модуля преобразований, в качестве полноценного обработчика ЧПУ, нельзя назвать удачным решением. В частности, это часто приводило к сообщениям об ошибках в логах сервера, которые связанны с многоуровневыми ЧПУ.

Например, если: category/name/ – обрабатывается вполне успешно, то вот просто: category/ – даже при наличии соответствующей директивы в файле .htaccess, выдаёт предупреждение. Впрочем, это никак не сказывается на работе самого сайта. Помимо этого есть и ряд других проблем, но я не буду в них вдаваться, т.к. они носят чисто субъективный характер.

Настройка преобразований в .htaccess

При создании сайтов, лучше использовать несколько более простое преобразование URL-адресов, передавая ЧПУ управляющему php-скрипту. Для этого в фале .htaccess нужно указать что-то вроде следующего:

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?furl=$1 [L,QSA]
</IfModule>

Давайте разберем приведенный пример подробнее.

ifModule – как следует из названия, эта директива проверяет наличия модуля mod_rewrite.c на сервере, который в свою очередь обеспечивает работу директив преобразований.

Далее идёт RewriteEngine – это директива, которая позволяет управлять статусом модуля преобразований. Обычно он отключен, используя директиву RewriteEngine, мы можем его включить. Для этого в качестве значение указываем: on.

Следующий набор директив RewriteCond определяют условия, при которых происходят дальнейшие преобразования. В приведенном примере добавлено три исключения: не файл (!-f), не ссылка (!-l) и не директория (!-d), которые уже существуют без преобразования.

Другими словами, если на сайте есть файл filename.html и к нему идёт обращение, то будет открыт именно этот файл, а не передан запрос обработчику ЧПУ. Таким образом, мы решаем сразу ряд проблем.

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

Последняя директива RewriteRule, определяет правила для механизма преобразований. В нашем случае, это фрагмент URL-адреса начинающийся после доменного имени и заканчивающийся символом вопрос (?), если таковой есть. Он будет передана php-скрипту index.php в качестве значения переменной furl.

Другими словами, php-обработчик получает только ЧПУ, не исключая возможности получения и динамических параметров, методом POST и/или GET.

Разбор регулярного выражения в RewriteRule

Сделаю небольшое отступление и разберу используемое в примере регулярное выражение: ^(.*)$.

  • Символ галочки (^) обозначает начало строки запроса.
  • Круглые скобки предназначены для выделения групп регулярных выражений и извлечения подстроки.
  • Точка (.) означает не менее одного символа, за исключением символа перевода строки.
  • Звездочка (*) означает любое количество символов в строке, предшествующих ей.
  • Доллар ($) соответствует концу строки запроса.

Другими словами, мы извлекаем подстроку, состоящую из всех символов запроса, от начала и до конца.

Далее идет указание php-скрипта index.php от места расположения файла .htaccess. В качестве значения параметра furl здесь выступает первая (а в нашем случае и единственная) извлекаемая подстрока. Для этого в качестве значения указанна переменная регулярного выражения $1. Соответственно, если в регулярном выражении присутствует несколько извлекаемых подстрок, нужно указывать требуемый их номер очередности.

Отдельно хочу отметить, что регулярное выражение может быть и более сложным, но в нашем случае приведенного примера будет более чем достаточно.

Подведём итоги

В данной статье приведён рабочий пример, который позволяет передать PHP-обработчики фрагмент URL-адреса с целью динамического формирования нужного контента на запрос пользователя. Используемые в файле .htaccess директивы и регулярное выражение описаны в достаточной степени, чтобы решить поставленную задачу на осознанном уровне. На этом у меня всё. Спасибо за внимание. Удачи!
chuvyr.ru

Правильно настраиваем чпу для сайта htaccess

Если Вы умеете немного кодить и пишите свои скрипты, я вам расскажу как легко сделать ЧПУ (человеко понятный урл) с помощью .htaccess.

Что такое ЧПУ?

Например, у нас есть ссылка на страницу новостей с ID номером новости:

Чтобы сделать такой URL красивее и удобнее, придумали ЧПУ, т.е. представление адреса, например в таком виде:

Скажете не очень наглядно? А вот такой пример:

Сделать это очень просто. Для веб-серверов Apache, есть встроенный модуль mod_rewrite . На большинстве хостингов он есть, так же как и на денвере.

Создаем файл .htaccess и кладем его в корень сайта. Первой строкой в этом файле мы пишем:

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

RewriteEngine on
RewriteRule ^news/([0-9]+)/? news.php?id=$1 [L]

Он будет перенаправлять с http://site.ru/news/4/ сюда http://site.ru/news.php?id=4
Все эти условия обычно указываются в htaccess с помощью регулярных выражений.

По второму примеру, код будет выглядеть так:

RewriteEngine on
RewriteRule ^articles/([-a-zA-Z0-9_]+)/? index.php?do=article&name=$1 [L]

Т.е. с адреса http://site.ru/articles/kak-sdelat-chpu/ нас перебросит на http://site.ru/index.php?do=article&name=kak-sdelat-chpu . Точнее пользователь не увидит реального адреса, а увидит только наш ЧПУ.

Как видите, все достаточно просто — создаем файл htaccess, пишем две строчки и готово!

По регулярным выражениям меня не спрашивайте, я не шарю Знаю только:

[0-9]+ — это только для цифр

[-a-zA-Z0-9_]+ — это для латинских больших, маленьких, дефиса и подчеркивания

Если во соображаете в регулярных выражениях, Вам будет очень легко написать любое правило. А кто не соображает, тут нужно смотреть примеры, которые я привел и пробовать. Я вчера попробовал, получилось! Не сразу конечно, перерыл кучу инфы, но разобрался.

Надеюсь понятно описал. Будут вопросы, спрашивайте.

UPD by Hugo: Если использовать конструкцию [QSA,L], тогда ЧПУ сможет принимать GET запросы. Т.е. если мы будем без [QSA,L] передавать GET-параметр (http://site.ru /articles/kak-sdelat-chpu/ ?Get_param=1 ) то выкинет 404 ошибку. Чтобы этого не происходило и мы смогли принимать GET запросы, нужно:

RewriteRule ^news/([0-9]+)/? news.php?id=$1 [L]

Нужно написать [QSA,L] на конце:



Ниже приведен код файла .htaccess, который пригодится для создания понятных и простых ссылок на сайте. Чтобы не использовать GET запросы, и делать ссылки понятными и простыми.
Например вместо index.php?page=12&action=edit можно делать ссылки типа page/12/edit .

Пример кода файла htaccess для создания ЧПУ на php

Разберем его по частям

Устанавливаем кодировку UTF-8. Не является обязательным в данном примере:
AddDefaultCharset UTF-8

Включаем движок mod_rewrite в Apache сервере:
RewriteEngine on

Костыль, чтобы не обрабатывать второй запрос который отправляют браузеры к фавиконке сайта:
#Don’t favicon!
RewriteCond % !^favicon\.ico

Условие. Указывает что все существующие папки не будут обрабатываться регулярным выражением:
RewriteCond % !-d

Условие. Указывает что все существующие файлы не будут обрабатываться регулярным выражением:
RewriteCond % !-f

Условие. Проверяется существование этого пути и то что этот путь является символической ссылкой:
RewriteCond % !-l

» Как правильно разное

ЧПУ на PHP. Прочь от ModeRewrite правил. Единая точка входа и роутинг на PHP.

Человекопонятный URL (ЧПУ или роутинг) — одна из самых часто затрагиваемых тем на различных форумах, посвящённых языку PHP. Можно до бесконечности спорить, нужны ли красивые URL-адреса для SEO-оптимизации, но факт того, что веб-сайт с ЧПУ выглядит аккуратно и профессионально отрицать глупо.

выглядит опрятно и интуитивно понятно

Теория реализации ЧПУ на сайте с помощью файла htaccess ::: Блог RS

 

Думаю для начало необходимо поговорить о том зачем все это надо?

 

ЧПУ на сайте, в чем смысл?

 

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

  • Первые говорят, что такие адреса лучше воспринимаются человеком, как бы врезаются в память позволяя найти блог не через поисковик а прямиком через адресную строку. По мне так это чушь! вот адрес ссылки:
    http://rio-shaman.ru/post/dobro-pozhalovat-v-cms-rs-blog-v2.html
    Запомнили? Я думаю нет, а если даже и запомнили, то через неделю Вы не вспомните (естественно есть исключения, человек 10-12 но есть!)
  • Вторые кричат что ЧПУ повышает шанс пробиться в ТОП поисковиков, так как поисковики понимают транслит, и натыкаясь на ключевое слово в ссылке засчитывают его как ключевое слово. Это куда ближе к истине.

Насчет людей из первой группы, я не говорю, что они на все 100% не правы, но ссылки заточенные под поисковики, а таких в интернете больше (намного больше), не реально запомнить, слишком много букф, другое дело если ссылка имеет вид:

http://rio-shaman.ru/post/1/

Но вот только беда, ключевого слова в таких ссылках нет, стало быть такие ссылки только для красоты, а на красоте в ТОП поисковика не уедешь (поисковику по фиг на красоту, он юзабилити определяет по поведенческому фактору)

Подумав решил для себя вот что. ЧПУ необходим только как средство SEO оптимизации, так как 5 из 10 человек вообще не знают что такое url, 7 из 10 на адресную строку не смотрят, а делать эстетические ссылки ради меньшинства считаю не рентабельным. Поэтому при выборе, какие ссылки делать, я выбрал вот такие:

http://rio-shaman.ru/post/dobro-pozhalovat-v-cms-rs-blog-v2.html

Если Вам необходимы ссылки другого вида, то Вы сможете создать их аналогично моим (я имею ввиду по урокам реализации ЧПУ, цикла «создать блог с нуля», что я планирую опубликовать), там расхождения в реализации минимальные

 

Как же делается ЧПУ на сайте, или магия файла htaccess (mod rewrite)

 

В общем то все очень легко. Некоторыми настройками сервера можно управлять через файл htaccess. Все кто когда либо создавал свои проекты в сети, видели такие файлы в директории сайта. У сервера apache есть модуль, так называемый mod rewrite который позволяет из динамических ссылок создавать ЧПУ ссылки.

Я сильно не разбираюсь во всем этом бреде, модули, настройки и тому подобное. Знаю только то как включить этот модуль и превратить динамичный адрес в ЧПУ

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

После чего модуль mod rewrite можно считать включенным

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

 

Пример работы ЧПУ на моем движке

 

Сильно грузить Вас сегодня не буду, но дам пример из моего файла htaccess:

RewriteEngine on
RewriteRule ^post/([-a-z0-9]+.html)$ index.php?post=$1 [L]

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

http://rio-shaman.ru/post/dobro-pozhalovat-v-cms-rs-blog-v2.html

В ссылку вот такого вида

http://rio-shaman.ru/index.php?post=dobro-pozhalovat-v-cms-rs-blog-v2.html

То есть мы получаем следующее.

Пользователь в адресную строку прописывает (например щелчком мыши по ссылке на блоге) вот такую ссылку post/dobro-pozhalovat-v-cms-rs-blog-v2.html А сервер, для обработки, получает вот такую ссылку index.php?post=dobro-pozhalovat-v-cms-rs-blog-v2.html

Все счастливы, пользователь видит ссылку ЧПУ, а сервер видит динамическую, понятную ему каракозябру =))

После преобразований, скрипт блога находит в базе данных, в таблице blog, строчку, колонка которой равна «dobro-pozhalovat-v-cms-rs-blog-v2.html»

строка в базе данных

выводит из этой строчки id, заносит значение id в переменную blog. Хочу напомнить, что для вывода статьи из базы данных необходима именно эта переменная

формирование переменной blog

а дальше уже идет привычный алгоритм вывода текстов на страницу нашего блога

 

Что необходимо будет сделать для реализации ЧПУ на нашем блоге?

 

По мимо самого файла htaccess (этот файл самое простое в реализации ЧПУ) у нас сейчас нет колонки в базе данных, которая содержит имена ссылок (dobro-pozhalovat-v-cms-rs-blog-v2.html), поэтому нам необходимо будет создать такую колонку!

Необходимо будет написать функцию автоматического преобразование заголовков постов в трансилт, для генерации имен ссылок (dobro-pozhalovat-v-cms-rs-blog-v2.html)

Так же необходимо будет написать алгоритм с помощью которого по имени ссылки скрипт определит id записи.

Ну и самое сложное, это реализовать автоматическую смену ссылок на кнопках (ссылках) блога. Под раздачу попадет, например, модуль мини новостей и модуль меню.

Так же придется подумать о редиректе с несуществующих ссылок на страницу 404 ошибки.

 

Заключение

 

В общем работы до опы, но не будем отчаиваться, красивые ссылки требуют жертв =) Если Вам интересен мой блог, то подпишитесь на RSS ленту блога через ридер, или же по почте

Если у Вас есть какие вопросы то пользуйтесь формой ниже

Удачи Вам! На сегодня у меня все

Наглядное руководство по htaccess и mod_rewrite для новичков

Содержание статьи:

Автор: Патрик Элтофт
Перевод: Всеволод Козлов

Несмотря на то, что статей и руководств, освещающих .htaccess и mod_rewrite, в Сети, мягко говоря, немало, многие веб-мастера до сих пор испытывают нехватку знаний по этому вопросу. Многим из них просто непонятно то, что говорится в этих мануалах, т.к. там это все сложно для их понимания.

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

Не будем терять времени, приступаем!

Сперва давайте разберемся, что же такое файл .htaccess и mod_rewrite.

.htaccess – файл-конфигуратор Apache-серверов.

Mod_rewrite – модуль, используемый веб-серверами для преобразования URL’ов.

.htaccess представляет собой обычный текстовый документ, расширение которого htaccess. Данный файл обычно находится в корне сайта, однако Вы можете создавать и дополнительные .htaccess-файлы для различных директорий Вашего сайта.

Удаление дублей страниц

Простейший и в то же время чаще всего необходимый трюк – редирект дублей одной и той же страницы на основной ее адрес.

Яркий пример – главная страница любого сайта обычно доступна по 4-ем адресам:

  • http://www.site.ru/
  • http://site.ru/
  • http://www.site.ru/index.html
  • http://site.ru/index.html

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

Решение этой проблемы предельно простое и выглядит так:

Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^site.ru
RewriteRule (.*) http://www.site.ru/$1 [R=301,L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.html\ HTTP/
RewriteRule ^index\.html$ http://www.site.ru/ [R=301,L]

Таким образом, мы получим редирект всех страниц-дублей на http://www.site.ru/

Меняем расширение html на php

Иногда бывает так, что у Вас статичный веб-сайт, а Вам необходимо, чтобы на нем срабатывал какой-нибудь php-скрипт. Для этого Вам необходимо сказать серверу, чтобы он обрабатывал эту страницу как php-файл.

AddHandler application/x-httpd-php .html

Этот прием можно использовать и для других расширений файлов:

AddHandler application/x-httpd-php .xml
AddHandler application/x-httpd-php .asp

Задаем собственные страницы ошибок

О необходимости создания собственной страницы ошибок я уже неоднократно рассказывал:

Задать же собственную страницу ошибок можно следующим образом:

ErrorDocument 404 http://www.site.ru/404.php

Индексация директорий и поддиректорий

Чтобы избежать индексации поисковыми системами директорий и поддиректорий, необходимо прописать такую строку, к примеру:

DirectoryIndex index.php3

Лично я предпочитаю переадресовывать с пустых директорий либо на главную страницу сайта, либо на какую-либо другую подходящую страницу. Например, директорию www.site.ru/images/ можно переадресовать на www.site.ru, а www.site.ru/forum/ на www.site.ru/forum/index.php.

Переадресация страниц

Простое правило, позволяющее переадресовывать с одной страницы на другую:

redirect 301 /old-page.php http://www.site.ru/new-page.php

Переадресация Вашего фида на Feedburner

Если Вы хотите, чтобы на Ваш RSS-фид подписывались через Feedburner, то используйте следующий код:

RewriteCond %{HTTP_USER_AGENT} !FeedBurner
RewriteRule ^your-feed\.xml$ http://feeds.feedburner.com/your-feed [R,L]

Защита изображений от скачивания

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

RewriteEngine on
RewriteCond %{HTTP_REFERER} .
RewriteCond %{HTTP_REFERER} !^http://([^.]+\.)?site\. [NC]
RewriteCond %{HTTP_REFERER} !google\. [NC]
RewriteCond %{HTTP_REFERER} !search\?q=cache [NC]
RewriteCond %{HTTP_REFERER} !msn\. [NC]
RewriteCond %{HTTP_REFERER} !yahoo\. [NC]
RewriteCond %{REQUEST_URI} !^/hotlinker\.gif$
RewriteRule \.(gif|jpg|png)$ /hotlinker.gif [NC,L]

hotlinker.gif – изображение, которое будет отображаться у нерадивых веб-мастеров, вместо истинных изображений. Рекомендую в этом изображении отобразить Ваш логотип и ссылку на Ваш сайт.

Создание ЧПУ (человеко-понятных урлов) с помощью mod_rewrite

C его помощью можно преобразовать, например, www.site.ru/product.php?id=123 в www.site.ru/product/123 следующим образом:

RewriteEngine on
RewriteRule ^product/([^/\.]+)/?$ product.php?id=$1 [L]

В другом примере преобразуем www.site.ru/script.php?product=123 в www.site.ru/cat/product/123/:

RewriteRule cat/(.*)/(.*)/$ /script.php?$1=$2

Избавляемся от QUERY_STRING

Некоторые веб-мастера делают ссылки вида www.site.ru/index.php?source=blogstorm, чтобы знать, откуда идут посетители. Из-за этого появляется дублированный контент, от которого надо избавляться:

RewriteCond %{QUERY_STRING} ^source= RewriteRule (.*) /$1? [R=301,L]

Полезные материалы по теме

Оригинал статьи: Ultimate Guide to htaccess and mod_rewrite

Как на самом деле работает mod_rewrite. Пособие для продолжающих / Sprinthost corporate blog / Habr


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

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

Я предполагаю, что читатель уже знаком с тем, что такое mod_rewrite, и не буду описывать его основы, которые легко найти в интернете. Также нужно отметить, что в статье освещается работа mod_rewrite при использовании его директив в файле .htaccess. Отличия при работе в контексте <VirtualHost> изложены в конце статьи.

Итак, вы изучили mod_rewrite, составили несколько RewriteRule и успели столкнуться с бесконечными перенаправлениями, со случаем, когда правило почему-то не ловит ваш запрос, а также с непредсказуемой работой группы правил, когда последующее правило неожиданно изменяет запрос, кропотливо подготовленный правилами предыдущими.

Почему так происходит?

С чем работает RewriteRule


Первому RewriteRule передается путь от того места, где находится .htaccess, до запрошенного файла. Эта строка никогда не начинается со «/». Последующим RewriteRule передается результат предыдущих преобразований.

Чтобы досконально понять, как работает RewriteRule, необходимо сначала определить, с чем он работает. Рассмотрим, как Apache получает строку, которая изначально передается на обработку RewriteRule в .htaccess.

Когда только начинаешь работать с mod_rewrite, логично предполагаешь, что он работает со ссылками. Однако в случае с использованием mod_rewrite в .htaccess это не так. На самом деле в RewriteRule передается не ссылка, а путь до запрошенного файла.

Из-за внутренней архитектуры Apache в тот момент, когда в действие вступает .htaccess, mod_rewrite может оперировать только с путем до файла, который должен быть обработан. Это связано с тем, что до передачи в mod_rewrite запрос уже могли изменить другие модули (например, mod_alias), и итоговый путь до файла на сайте уже может не совпадать с исходной ссылкой. Если бы mod_rewrite работал с исходной ссылкой, он бы нарушал действие модулей, которые изменили запрос до него.

Поэтому в mod_rewrite передается абсолютный путь до файла, который должен быть обработан. Также mod_rewrite знает путь до .htaccess, в котором размещены правила RewriteRule. Чтобы сделать из пути до файла что-то похожее на ссылку, с которой планирует работать разработчик сайта, mod_rewrite отрезает от абсолютного пути часть до файла .htaccess.

Так вот, именно этот путь, от которого отрезан путь до .htaccess, передается в первый RewriteRule. Например:

  • Запрос: http://example.com/templates/silver/images/logo.gif
  • DocumentRoot: /var/www/example.com
  • Путь до файла: /var/www/example.com/templates/silver/images/logo.gif
  • .htaccess находится в: /var/www/example.com/templates/.htaccess
  • В первый RewriteRule будет передано: silver/images/logo.gif
  • Обратите внимание: «templates/» тоже отрезалось.

Путь до .htaccess отрезается вместе со слешем. Из этого есть следствие: строка, которая изначально передается на обработку RewriteRule никогда не начинается со «/».

Важно запомнить, что не делает RewriteRule. Она не обрабатывает имя сайта, аргументы, которые переданы в скрипт, да и ссылку обрабатывает не всю, если .htaccess размещен не в корне сайта. Всем этим занимается RewriteCond, которого кратко коснемся чуть позже. Итак:

# работать не будет - правило начинается со /
RewriteRule ^/index.php$ /my-index.php

# работать не будет - название сайта не анализируется RewriteRule
RewriteRule ^example.com/.* http://www.example.com

# работать не будет - аргументы ссылки не попадают в RewriteRule
RewriteRule index.php\?newspage=([0-9]+) news.php?page=$1

# Будет работать только если .htaccess находится там же, где находится папка templates,
# например, в корне сайта. То есть, если .htaccess находится в templates/.htaccess , правило
# работать НЕ БУДЕТ, потому что mod_rewrite отрежет путь до .htaccess и на вход RewriteRule
# строка попадет уже без "templates/"
RewriteRule ^templates/common/yandex-money.gif$ templates/shared/yad.gif



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

С чем работает RewriteRule, мы разобрались. Теперь посмотрим, как он работает.

Как работает RewriteRule


RewriteRule просто преобразовывает строку в соответствии с регулярными выражениями, и все. RewriteRule работает со строкой, а не со ссылкой или путем до файла.

Как мы выяснили выше, на вход RewriteRule попадает путь от .htaccess до запрошенного файла. Удобнее всего теперь абстрагироваться от путей и ссылок и рассматривать то, с чем работает RewriteRule, как обычную строку. Эта строка передается от RewriteRule к RewriteRule, видоизменяясь, если какое-то из RewriteRule сработало.

В общем виде, если исключить сложности с использованием флагов (некоторые из которых мы рассмотрим ниже) и сложности с составлением регулярных выражений (которых мы почти не будем касаться в этой статье), RewriteRule работает ОЧЕНЬ просто.

  1. Взяли строку.
  2. Сравнили с регулярным выражением в первом аргументе.
  3. Если есть совпадение — заменили всю строку на значение второго аргумента.
  4. Передали строку следующему RewriteRule.
Вот, в общем, и все. Чтобы наглядно проиллюстрировать, что RewriteRule работает именно со строкой, рассмотрим следующий фантастический пример:
# Запрос: http://mysite.com/info.html
# В первый RewriteRule попадет "info.html"

# Преобразовываем запрос в произвольную строку.
RewriteRule ^info.html$ "I saw a turtle in the hole. And it was dancing rock-n-roll. And it was smiling. All in all, it was a very funny doll."

# "info.html" -> "I saw a turtle..."

# Заменяем эту строку на внешнюю ссылку.
RewriteRule turtle https://example.com/information/index.html

# "I saw a turtle..." -> "https://example.com/information/index.html"

# Заменяем имя сайта!
RewriteRule ^(.*)example.com(.*)$ $1example.org$2

# "https://example.com/information/index.html" -> "https://example.org/information/index.html"

# Заменяем протокол!
RewriteRule ^https:(.*)$ ftp:$1

# "https://example.org/information/index.html" -> "ftp://example.org/information/index.html"

# Заменяем конечную ссылку.
RewriteRule ^(.*)/index.html$ $1/main.php

# "ftp://example.org/information/index.html" -> "ftp://example.org/information/main.php"



Как видите, RewriteRule все равно, с чем работать — она просто преобразовывает строку в соответствии с заданными ей аргументами. Если хотите, можете в строке хранить любые массивы данных, при желании, настойчивости и хорошем знании регулярных выражений можете хоть крестики-нолики на RewriteRule написать.

Здесь нужно сделать замечание: хоть RewriteRule и работает с чистой строкой, она все-таки ориентирована на работу со ссылками. Поэтому она будет по-особому реагировать на строки, начинающиеся на «https://» или аналоги (запомнит, что мы хотели сделать внешний редирект) и на символ «?» (посчитает следующие символы аргументами, которые нужно будет подставить к запросу). Однако сейчас нас это не интересует — важно понять, что в RewriteRule нет никакой магии — она просто берет строку и изменяет ее так, как вы ей сказали. Внешние редиректы и аргументы мы рассмотрим позже в статье, там тоже есть, о чем поговорить.

После того как все преобразования произведены и выполнено последнее RewriteRule, вступает в силу RewriteBase.

Для чего нужен RewriteBase


Если получившийся после преобразований запрос является относительным и отличается от исходного, RewriteBase добавит себя к нему слева. Нужно обязательно указывать RewriteBase в .htaccess. Его значение — путь от корня сайта до .htaccess.
RewriteBase выполняется только после всех RewriteRule, а не между ними.

Мы уже говорили выше о том, что в mod_rewrite, работающий в .htaccess, попадает абсолютный путь до запрошенного файла. Чтобы передать его в RewriteRule, mod_rewrite отрезает путь до .htaccess. Потом правила RewriteRule одно за одним последовательно изменяют запрос. И вот после того, как запрос изменен, Apache должен восстановить абсолютный путь до файла, который он должен в итоге обработать. RewriteBase фактически является хаком, который помогает восстановить исходный путь до файла.

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

После всех преобразований RewriteBase смотрит, относительный получился в итоге путь или абсолютный. В контексте Apache имеется в виду относительный или абсолютный путь, отсчитывая от корня сайта:

  • images/logo.gif — относительный.
  • /images/logo.gif — абсолютный (в начале слеш).
  • http://example.com/images/logo.gif — самый абсолютный из всех.
Если путь абсолютный, RewriteBase ничего не делает. А если относительный — RewriteBase дописывает себя слева. Это работает как для внутренних, так и для внешних редиректов:
# .htaccess находится в /images/
# RewriteBase указан /images/
RewriteBase /images/

# Запрос http://example.com/images/logo.gif
# На вход RewriteRule попадает "logo.gif"
RewriteRule ^logo.gif$ logo-orange.gif
# После RewriteRule: "logo.gif" -> "logo-orange.gif"
# После RewriteBase: "logo-orange.gif" -> "/images/logo-orange.gif"

# Запрос http://example.com/images/header.png
# На вход RewriteRule попадает "header.png"
RewriteRule ^header.png$ /templates/rebranding/header.png
# После RewriteRule: "header.png" -> "/templates/rebranding/header.png"
# После RewriteBase: ничего не меняется, так итоговый результат преобразований начинается со "/'.

# Запрос http://example.com/images/director.tiff
# На вход RewriteRule попадает "director.tiff"
# Используем внешний относительный редирект
RewriteRule ^director.tiff$ staff/manager/director.tiff [R=301]
# После RewriteRule: "director.tiff" -> "staff/manager/director.tiff"
# + mod_rewrite запомнил, что будет внешний редирект
# После RewriteBase: "staff/manager/director.tiff" -> "/images/staff/manager/director.tiff"
# mod_rewrite вспомнил про внешний редирект:
# "/images/staff/manager/director.tiff" -> http://example.com/images/staff/manager/director.tiff



Обычно после некоторого знакомства с mod_rewrite складывается следующая привычка: 1) в каждый .htaccess добавлять «RewriteBase /», 2) все перенаправления начинать со слеша: «RewriteRule news.php /index.php?act=news». Это помогает избавиться от артефактов работы RewriteBase, но так делать неправильно. Теперь, когда нам известно, что делает RewriteBase, можно сформулировать следующие корректные правила:
  1. RewriteBase должен совпадать с путем от корня сайта до .htaccess.
  2. Начинать перенаправления со «/» нужно только тогда, когда необходимо указать абсолютный путь от корня сайта до файла.


Что будет, если не указать RewriteBase? По умолчанию Apache делает его равным абсолютному пути на файловой системе до .htaccess (например, /var/www/example.com/templates/). Некорректность такого предположения Apache проявляется на внешних относительных редиректах:
# Запрос http://example.com/index.php
# DocumentRoot: /var/www/example.com/
# .htaccess находится в корне сайта, и в нем НЕ УКАЗАН RewriteBase.
# Поэтому по умолчанию RewriteBase равен абсолютному пути до .htaccess: /var/www/example.com/

# На входе RewriteRule - "index.php"
RewriteRule ^index.php main.php [R]
# На выходе: "index.php" -> "main.php"
# mod_rewrite запомнил, что нужен внешний редирект

# Закончились RewriteRule
# mod_rewrite все равно выполняет RewriteBase, так как у него есть значение по умолчанию.
# Получается: "main.php" -> "/var/www/example.com/main.php"

# Здесь mod_rewrite вспоминает, что был внешний редирект:
# "/var/www/example.com/main.php" -> http://example.com/var/www/example.com/main.php

# Получилось совсем не то, что имели в виду.



Итак, запрос прошел через все RewriteRule, после чего к нему, в случае необходимости, добавился RewriteBase. Должен ли теперь Apache отдать файл, на который показывает результирующий путь? Нет. Теперь получившийся запрос будет обрабатываться еще раз.

Как работает mod_rewrite. Флаг [L]


mod_rewrite запускает обработку запроса снова и снова, до тех пор, пока он не перестанет меняться. И флаг [L] не может это остановить.

При составлении более-менее сложных конфигураций mod_rewrite важно понимать, что изменение запроса не заканчивается на последнем RewriteRule. После того, как сработало последнее правило RewriteRule и был добавлен RewriteBase, mod_rewrite смотрит, изменился запрос или нет. Если запрос изменился, его обработка начинается заново с начала .htaccess.

Apache поступает так, потому что в процессе изменения запроса он мог быть перенаправлен в другую директорию. В ней может быть собственный .htaccess, который не участвовал в предыдущей обработке запроса. В этом же новом .htaccess могут быть правила, которые влияют на обработку запроса — как правила mod_rewrite, так и правила других модулей. Чтобы корректно обработать эту ситуацию, Apache должен запустить весь цикл обработки заново.

— Постойте, но ведь есть флаг [L], который останавливает обработку запроса mod_rewrite’ом!

Не совсем так. Флаг [L] останавливает текущую итерацию обработки запроса. Однако если запрос был изменен теми RewriteRule, которые все-таки успели отработать, Apache запустит цикл обработки запроса заново с первого RewriteRule.

# Запрос: http://example.com/a.html

RewriteBase /

RewriteRule ^a.html$ b.html [L]
RewriteRule ^b.html$ a.html [L]



Пример выше приведет к бесконечному циклу перенаправлений и к «Internal Server Error» в итоге. В этом примере бесконечный цикл очевиден, однако в более сложных конфигурациях может потребоваться покопаться в правилах, чтобы определить, какие запросы зацикливаются между собой.

Чтобы избежать подобных ситуаций, рекомендуется использовать флаг [L] только при необходимости. Необходимость может быть двух типов:

  1. Когда используется внешний редирект — [L,R=301] или [L,R=302]. В случае внешнего редиректа дальнейшая обработка запроса нежелательна (см. ниже про флаг [R]), и ее лучше остановить.
  2. Когда в .htaccess есть зацикливание, от которого не избавиться, и обработку запроса mod_rewrite’ом нужно принудительно прекратить. В этом случае используется специальная конструкция — см. в конце статьи советы на эту тему.

А вот приведенный ниже пример зацикливаться не будет. Попробуйте определить, почему, и какой в итоге файл будет отдан Apache’м.
# Запрос: http://example.com/a.html
# Начало .htaccess

RewriteBase /
RewriteRule ^a.html$ b.html
RewriteRule ^b.html$ a.html

# Конец .htaccess



Отгадка: В результате выполнения всех RewriteRule запрос меняется таким образом, что конечный результат равен исходному. Apache видит это и не запускает повторную обработку запроса. Будет возвращен файл a.html.

Как работает mod_rewrite. Флаг [R]


Флаг [R] не останавливает обработку запроса, возвращая сразу внешний редирект. Вместо этого он запоминает необходимость внешнего редиректа, и обработка запроса продолжается следующими RewriteRule. Рекомендуется всегда использовать с флагом [L].

Флаг [R] сообщает Apache, что нужно выполнить не внутренний, а внешний редирект. Чем отличается внешний редирект от внутреннего? Внутренний редирект просто изменяет путь до файла, который будет отдан пользователю, при этом пользователь считает, что получает тот файл, который он изначально запросил. При внешнем же редиректе Apache вместо содержимого файла возвращает пользователю статус ответа 301 или 302 и сообщает ссылку, по которой браузер должен обратиться для получения файла.

Казалось бы, при обработке флага [R] Apache должен сразу прекратить обработку RewriteRule и вернуть пользователю внешний редирект. Однако давайте вспомним фантастический пример из раздела «Как работает RewriteRule». В нем мы сначала указали флаг [R], обозначив необходимость внешнего редиректа, после чего продолжили изменять ссылку следующими RewriteRule.

Именно так и работает Apache при указании внешнего редиректа. Он просто «помечает» себе, что после выполнения всех правил необходимо вернуть статус 302 (по умолчанию), но при этом продолжает выполнение всех RewriteRule дальше по списку. Мы можем и дальше изменять запрос как нам нужно, единственное, что не получится — сделать редирект обратно внутренним.

Тем не менее, вряд ли вы хотите после отдачи внешнего редиректа каким-либо образом изменять его. Поэтому рекомендуется при употреблении флага [R] указывать его совместно с [L]:

# BlackJack переехал на красивое имя
RewriteRule ^bj/(.*) blackjack/$1 [R=301,L]

# Можно использовать просто внешнюю ссылку
RewriteRule ^bj/(.*) http://blackjack.example.com/$1 [L]



Вместо использования флага [R] можно указывать просто внешнюю ссылку. В этом случае Apache сам догадается, что необходимо сделать внешний редирект. Здесь, как и с в случае с явным указанием флага [R], рекомендуется использовать флаг [L].
  • Если внешний редирект ведет на тот же сайт, лучше использовать флаг [R] без указания полной ссылки (иными словами, использовать относительный внешний редирект). Это сделает правило независимым от имени сайта.
  • Если же внешний редирект ведет на другой сайт, иначе, как указав полную внешнюю ссылку, это сделать не получится.

Как работает mod_rewrite. Указание параметров запроса и флаг [QSA]


Изменение параметров запроса в RewriteRule не изменяет строку, с которой работает следующий RewriteRule. Однако при изменении параметров изменяется переменная %{QUERY_STRING}, с которой может работать RewriteCond.

Используемая терминология: «параметры» — параметры запроса, «аргументы» — аргументы RewriteRule.

С помощью RewriteRule можно изменять не только путь до файла, который будет обрабатываться, но и параметры запроса GET, которые будут ему передаваться. Это часто используется для передачи обработки ЧПУ в общий скрипт-обработчик, например:

RewriteBase /

# Запрос: http://example.com/news/2010/07/12/grand-opening.html
# На входе: "news/2010/07/12/grand-opening.html"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После RewriteRule: "news/2010/07/12/grand-opening.html" -> "index.php"
# %{QUERY_STRING}: "" -> "act=news&what=2010/07/12/grand-opening.html"



В момент, когда правило RewriteRule встречает вопросительный знак во втором аргументе, оно понимает, что происходит изменение параметров в запросе. В результате происходит следующее:
  1. RewriteRule заменяет строку, с которой оно работает, на часть второго аргумента до вопросительного знака. Обратите внимание, что новые параметры запроса не попадают в строку, с которой будут работать последующие правила RewriteRule.
  2. Часть второго аргумента после вопросительного знака попадает в переменную %{QUERY_STRING}. Если был указан флаг [QSA], параметры запроса будут добавлены в начало %{QUERY_STRING}. Если флаг указан не был, %{QUERY_STRING} полностью заменится параметрами запроса из RewriteRule.
Еще пара примеров:
RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/"



Скорее всего, правило выше работает неправильно, так как теряется аргумент page. Исправим это:
RewriteBase /

# Запрос: http://example.com/news/2010/?page=2
# На входе RewriteRule: "news/2010/"
RewriteRule ^news/(.*)$ index.php?act=news&what=$1 [QSA]
# После преобразования: "news/2010/" -> "index.php"
# Значение %{QUERY_STRING}: "page=2" -> "act=news&what=2010/&page=2"



Мы добавили только флаг [QSA], и правило стало работать корректно.

Важно понимать, что изменение параметров запроса изменяет %{QUERY_STRING}, который может использоваться в дальнейшем в RewriteCond. Это нужно учитывать при составлении последующих правил, проверяющих аргументы.

— Конечно, изменяется, ведь запрос уходит на повторную обработку Apache’м!

Нет, %{QUERY_STRING} изменяется сразу же. Доказательство приводить не буду — про параметры и так уже написано больше, чем интересно читать 🙂

Что же делать, чтобы проверить в RewriteCond именно те параметры запроса, которые передал пользователь, а не модифицированные RewriteRule’ами? Смотрите советы в конце статьи.

RewriteCond и производительность


Сначала проверяется совпадение запроса с RewriteRule, а уже потом — дополнительные условия RewriteCond.

Пару слов стоит сказать о том, в каком порядке mod_rewrite выполняет директивы. Так как в .htaccess сначала идут RewriteCond, а потом RewriteRule, кажется, что mod_rewrite сначала проверяет все условия, а потом приступает к выполнению RewriteRule.

На самом деле все происходит наоборот. Сначала mod_rewrite проверяет, подходит ли текущее значение запроса под регулярное выражение RewriteRule, а уже потом будет проверять все условия, перечисленные в RewriteCond.

Так что если у вас в RewriteRule регулярное выражение на две страницы и вы, задумавшись о производительности, решили ограничить выполнение этого правила дополнительными RewriteCond, знайте — ничего не получится. В этом случае лучше использовать флаги RewriteRule [C] или [S], чтобы пропустить более сложное правило, если более простые проверки не сработали.

Переменные и флаги RewriteCond, остальные флаги RewriteRule и прочее


Читайте документацию.

Мы познакомились с принципами работы RewriteRule, RewriteBase, флагов [L], [R] и [QSA], а также разобрали механизм обработки запросов внутри mod_rewrite. Из незатронутого остались: другие флаги RewriteRule, директивы RewriteCond и RewriteMap.

К счастью, эти директивы и флаги не таят в себе каких-либо загадок и работают именно так, как описано в большинстве учебников. Для их понимания достаточно почитать официальную документацию. В первую очередь рекомендую изучить список переменных, которые можно проверять в RewriteCond — %{QUERY_STING}, %{THE_REQUEST}, %{REMOTE_ADDR}, %{HTTP_HOST}, %{HTTP:header} и т. д.)

Разница в работе mod_rewrite в контексте .htaccess и в контексте VirtualHost


В контексте <VirtualHost> mod_rewrite работает с точностью до наоборот.

Как я говорил в начале статьи, все описанное выше касается применения mod_rewrite в контексте .htaccess. Если же mod_rewrite используется в , он будет работать по-другому:
  • В <VirtualHost> в RewriteRule попадает весь путь запроса, начиная от первого слеша, заканчивая началом параметров GET: «http://example.com/some/news/category/post.html?comments_page=3» -> «/news/category/post.html». Эта строка всегда начинается со /.
  • Второй аргумент RewriteRule также необходимо начинать со /, иначе будет «Bad Request».
  • RewriteBase не имеет смысла.
  • Проход правил происходит только один раз. Флаг [L] действительно заканчивает обработку всех правил, описанных в <VirtualHost>, без каких-либо последующих итераций.

Советы и решения


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

Составление регулярных выражений


Старайтесь составлять регулярные выражения так, чтобы они наиболее узко определяли именно те запросы, которые вы хотите модифицировать — чтобы правила RewriteRule случайно не сработали для другого запроса. Например:
# Начинайте все регулярные выражения с "^" (признак начала строки)
# и заканчивайте "$" (признак конца строки):
RewriteRule ^news.php$ index.php
# Даже если в этом нет необходимости - для универсальности и лучшего понимания конфигурации:
RewriteRule ^news/(.*)$ index.php

# Если под маску должны попадать только цифры - укажите это явно.
# Если какие-то цифры постоянны, укажите их явно.
# Если в оставшейся части запроса не могут присутствовать слеши, ограничьте их присутствие.
# Не забывайте экранировать "." (точки).
# Следующее правило нацелено на запросы вида http://example.com/news/2009/07/28/b-effect.html
RewriteRule ^news/20[0-9]{2}/[0-9]{2}/[0-9]{2}/[^/]+\.html index.php



Впрочем, о регулярных выражениях на одном известном сайте есть целый раздел.

Изменение внешних редиректов


Несмотря на то, что mod_rewrite позволяет изменять с помощью RewriteRule даже внешние редиректы, вплоть до протокола, я крайне не рекомендую делать это. В статье пример с изменением внешних редиректов используется только чтобы отвязаться от таких понятий как «ссылки» и «файлы» и более явно показать, что RewriteRule работает с простой строкой.

Не думаю, что разработчики mod_rewrite предполагали, что кто-то будет так делать, поэтому возможны всякие артефакты. Не делайте так, пожалуйста.

Как остановить бесконечный цикл


Иногда логика перенаправлений на сайте такова, что без специальных действий mod_rewrite воспринимает их как бесконечный цикл перенаправлений. Возьмем следующий пример.

На сайте была страница /info.html. Специалист по SEO решил, что поисковые системы будут лучше индексировать эту страницу, если она будет называться /information.html и попросил сделать внешний редирект с info.html на information.html. Однако разработчик сайта по каким-то своим соображениям не может просто переименовать info.html в information.html и сделать редирект — ему нужно, чтобы данные обязательно отдавались непосредственно из файла info.html. Он пишет следующее правило:

# сделать внешний редирект
RewriteRule ^info.html information.html [R,L]
# но по запросу /information.html все равно отдать info.html
RewriteRule ^information.html info.html


… и сталкивается с бесконечным циклом. Каждый запрос /information.html получает внешний редирект снова на /information.html.

Решить эту проблему можно как минимум двумя способами. На Хабре был уже описан один из них — нужно установить переменную окружения и на основании ее значения прекращать перенаправления. Код будет выглядеть следующим образом:

RewriteCond %{ENV:REDIRECT_FINISH} !^$
RewriteRule ^ - [L]

RewriteRule ^info.html$ information.html [R,L]
RewriteRule ^information.html$ info.html [E=FINISH:1]



Обратите внимание, что к имени переменной mod_rewrite добавляет ‘REDIRECT_’.

Второй способ — проверить в THE_REQUEST, что именно было запрошено пользователем:

# Внешний редирект происходит только если пользователь запросил info.html.
# Если же info.html - это результат внутреннего перенаправления, правило срабатывать не будет.
RewriteCond %{THE_REQUEST} "^(GET|POST|HEAD) /info.html HTTP/[0-9.]+$"
RewriteRule ^info.html$ information.html [R,L]

RewriteRule ^information.html$ info.html


Анализ исходного запроса пользователя — борьба с раскрытием ссылок Apache


При обработке запроса Apache раскрывает закодированные (URL-encoded) символы из первоначального запроса. В некоторых случаях это может быть нежелательно — разработчик хочет проверять именно первоначальный, немодифицированный запрос пользователя. Сделать это можно, проверяя в RewriteCond переменную %{THE_REQUEST}:
RewriteCond %{THE_REQUEST} ^GET[\ ]+/tag/([^/]+)/[\ ]+HTTP.*$
RewriteRule ^(.*)$ index.php?tag=%1 [L]


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

Рекомендуемая документация


Официальная документация Apache и особенно Technical details. Да-да.

Большое спасибо за внимание!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *