Статьи

Использование файлов htaccess для красивых URL-адресов

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

Хотя некоторые утверждают, что симпатичные URL-адреса помогают в ранжировании в поисковых системах, споры здесь очень жесткие, мы все согласны с тем, что красивые URL-адреса упрощают работу для наших пользователей и повышают уровень профессионализма и полировки любого веб-приложения. Я мог бы рассмотреть все теоретические причины этого, но мне больше нравятся примеры из реальной жизни. Нравится нам это или нет, мы все должны признать, что Twitter является чрезвычайно популярным веб-приложением, и отчасти это объясняется тем, как он форматирует URL-адреса. Я могу сообщить любому знающему, что мое имя пользователя Twitter — noahhendrix, и они знают, что мой профиль можно легко найти по адресу twitter.com/noahhendrix . Эта, казалось бы, простая концепция имеет огромное влияние на популярность вашего приложения.

Чтобы взглянуть на вещи в перспективе, мы можем взглянуть на другой популярный сайт социальной сети Facebook . С момента запуска сайта в 2004 году система профилей выросла и развивалась, чтобы лучше приспосабливаться к пользователям, но одной явной дырой был URL-адрес профиля. Со времени моей регистрации в Facebook мой профиль был по адресу http://www.facebook.com/profile.php?id=1304880680 . Это довольно полный рот, и совсем недавно кажется, что Facebook понял это, и они запустили тщеславные URL Facebook. Теперь я могу поделиться своим профилем в Facebook, сказав людям, что мое имя пользователя Facebook — «noahhendrix», и, как они знают, их можно найти по адресу facebook.com/noahhendrix . Хотя есть вероятность, что у нас не будет такого популярного приложения, как Facebook, мы все же можем позаимствовать несколько страниц из их книги.

Краткий обзор, прежде чем мы углубимся в код, в сегодняшнем уроке мы рассмотрим два немного разных метода создания красивых URL-адресов с использованием HTACCESS. Разница между методами заключается в том, что Apache или PHP делают тяжелую работу, чтобы разбить URL-адрес для разбора. Я хочу отметить, что учебники по mod_rewrite почти так же стары, как и сам интернет, и это не первый случай . В конце я буду использовать один из методов для создания простого приложения, чтобы показать, как эти решения будут выглядеть на реальном веб-сайте (а не на 100% качества продукции). Сервис, который мы создадим, является укороченным URL-адресом, который может отражать функциональность таких сайтов, как bit.ly , TinyURL или su.pr. Так что без пуха давайте посмотрим на код.

Во-первых, мы можем поместить весь наш код в файлы Apache .htaccess. Это может выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
Options +FollowSymLinks
 RewriteEngine On
 
 RewriteCond %{SCRIPT_FILENAME} !-d
 RewriteCond %{SCRIPT_FILENAME} !-f
 
 RewriteRule ^users/(\d+)*$ ./profile.php?id=$1
 RewriteRule ^threads/(\d+)*$ ./thread.php?id=$1
 
 RewriteRule ^search/(.*)$ ./search.php?query=$1

Давайте начнем с вершины и продолжим наш путь, чтобы лучше понять, что здесь происходит. Первая строка устанавливает окружение, чтобы оно следовало за символическими ссылками, используя директиву Options . Это может или не может быть необходимым, но некоторые веб-хосты используют символические ссылки (аналог псевдонима в MacOSX или ярлыки Windows) для распространенных ошибок HTTP-запросов, и обычно это файлы с символическими ссылками, или, по крайней мере, так я понимаю причину. Далее мы сообщаем Apache, что собираемся использовать Rewrite Engine . Следующие две строки очень, очень важны, они ограничивают перезапись URL только теми путями, которые на самом деле не существуют. Это предотвращает соответствие приведенных ниже правил example.com/images/logo.png, например. Первая предотвращает существующие каталоги с флагом ! -D, а вторая с ! -F означает игнорирование существующих файлов.

Следующие три строки являются собственно командами перезаписи URL. Каждая строка создает правило, которое пытается сопоставить шаблон регулярных выражений с входящим URL-адресом. Регулярные выражения, по крайней мере для меня, представляют собой сложный набор правил, которые нужно запомнить, но я всегда нахожу полезным использовать это руководство по собственному пути Джеффри из Nettut и рекомендованного им инструмента . Я обнаружил, что легко набрать примеры URL, которые мы хотим сопоставить, а затем попытаться взломать шаблон.

Первым аргументом является шаблон между кареткой и знаком доллара. Мы сообщаем Apache, что мы хотим, чтобы URL запрашивали каталог пользователя (искусственный каталог, фактически не должен существовать), за которым следовали / и любая длина чисел. Скобка создает группу захвата, вы можете использовать столько, сколько хотите, они служат переменными, которые мы затем можем перенести в нашу перезапись. Звездочка означает, что пользователь может ввести все, что он хочет, и это не повлияет на перезапись, это в первую очередь для обработки косой черты, поэтому example.com/users/123 такой же, как example.com/users/123/ для пользователей будет ожидать.

Второй аргумент — это путь, который мы хотим вызвать, в отличие от первого, это должен быть настоящий файл. Мы просим Apache найти в текущем каталоге файл profile.php и отправить вместе с ним параметр id = $ 1 . Помните группу захвата ранее? Вот где мы получаем переменную $ 1, группы захвата начинаются с одной. Это создает URL-адрес на сервере, например example.com/profile.php?id=123 .

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

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

1
2
3
4
5
6
7
Options +FollowSymLinks
 RewriteEngine On
 
 RewriteCond %{SCRIPT_FILENAME} !-d
 RewriteCond %{SCRIPT_FILENAME} !-f
 
 RewriteRule ^.*$ ./index.php

Все то же самое, что и выше, за исключением последней строки, поэтому мы перейдем к ней. Вместо того, чтобы создавать группу захвата, мы просто указываем Apache захватить каждый URL и перенаправить его в index.php . Это означает, что мы можем выполнять всю нашу обработку URL в PHP, не слишком полагаясь на строгие пути URL в HTACCESS. Вот что мы могли бы сделать в верхней части нашего файла index.php для анализа URL:

1
2
3
4
5
6
7
<?php
   #remove the directory path we don’t want
   $request = str_replace(«/envato/pretty/php/», «», $_SERVER[‘REQUEST_URI’]);
 
   #split the path by ‘/’
   $params = split(«/», $request);
 ?>

Первая строка не нужна, если ваше приложение не находится в корневом каталоге, как мои демонстрации. Я удаляю бессмысленную часть URL, о которой не хочу беспокоиться PHP. $ _SERVER [‘REQUEST_URI’] — это глобальная серверная переменная, которую PHP предоставляет и хранит URL запроса, обычно она выглядит так:

1
/envato/pretty/php/users/query

Как видите, это в основном все после доменного имени. Затем мы разделяем оставшуюся часть виртуального пути и разделяем его символом /, что позволяет нам получать отдельные переменные. В моем примере я только что распечатал массив $ params в теле, конечно, вы захотите сделать что-то более полезное.

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

01
02
03
04
05
06
07
08
09
10
<?php
      #keeps users from requesting any file they want
      $safe_pages = array(«users», «search», «thread»);
       
      if(in_array($params[0], $safe_pages)) {
        include($params[0].».php»);
      } else {
        include(«404.php»);
      }
    ?>

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

Теперь, когда мы убрали мыльную коробку, давайте двигаться дальше. Затем мы проверяем, находится ли запрошенный файл в массиве $ safe_pages , и, если он есть, мы включаем в противном случае страницу 404 не найдена. На включенной странице вы увидите, что у вас есть доступ к массиву $ params, и вы можете получить из него все данные, которые необходимы в вашем приложении.

Это отлично подходит для тех, кто хочет немного больше контроля и гибкости. Очевидно, он требует немного дополнительного кода, поэтому, вероятно, лучше для новых проектов, которые не требуют обновления большого количества кода для соответствия новым форматам URL.

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

Как видите, это очень просто, у нас есть только 4 столбца:

  • id : уникальный идентификатор, используемый для ссылки на определенные строки
  • короткий : уникальная строка символов, добавленная в конец нашего URL, чтобы определить, куда перенаправить
  • URL : URL-адрес, на который перенаправляется короткий URL-адрес
  • create_at : простая отметка времени, поэтому мы знаем, когда этот URL был создан

Далее давайте рассмотрим шесть файлов, которые нам нужно создать для этого приложения:

  • .htaccess: перенаправляет все короткие URL-адреса на serve.php
  • create.php: проверяет URL, создает шорткод, сохраняет в БД
  • css / style.css: содержит основную информацию о стилях
  • db_config.php: хранить переменные для соединений с базой данных
  • index.php: лицо нашего приложения с формой для ввода URL
  • serve.php: ищет короткий URL и перенаправляет на реальный URL

Это все, что нам нужно для нашего основного примера. Я не буду подробно описывать index.php или css / style.css, потому что они не имеют PHP и являются статическими файлами.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# index.php
—-
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html>
  <head>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″ />
    <title>Makes URLs Shrtr</title>
    <link type=»text/css» rel=»stylesheet» href=»./css/style.css» />
    </head>
    <body>
     <div id=»pagewrap»>
     <h1>shrt<span class=»r»>r
      
     <div class=»body»>
       <form action=»./create.php» method=»post»>
        
         <span class=»instructions»>Type your URL here
         <input name=»url» type=»text» />
         <input type=»submit» value=»shrtr» />
        
       </form>
     </div>
        
     </div>
    </body>
</html>

Единственное, что действительно интересно отметить, это то, что мы отправляем форму с полем с именем URL для create.php .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# css/style.css
—-
/* reset */
* {
  font-family: Helvetica, sans-serif;
  margin: 0;
  padding: 0;
}
 
/* site */
html, body { background-color: #008AB8;
a { color: darkblue;
 
  #pagewrap {
    margin: 0 auto;
    width: 405px;
  }
   
    h1 {
      color: white;
      margin: 0;
      text-align: center;
      font-size: 100px;
    }
      h1 .r { color: darkblue;
     
    .body {
      -moz-border-radius: 10px;
      -webkit-border-radius: 10px;
      background-color: white;
      text-align: center;
      padding: 50px;
      height: 80px;
      position: relative;
    }
     
      .body .instructions {
        display: block;
        margin-bottom: 10px;
      }
      .body .back {
        right: 15px;
        top: 10px;
        position: absolute;
      }
       
      .body input[type=text] {
        display: block;
        font-size: 20px;
        margin-bottom: 5px;
        text-align: center;
        padding: 5px;
        height: 20px;
        width: 300px;
      }

Это все очень общее, но делает наше приложение немного более презентабельным.

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

01
02
03
04
05
06
07
08
09
10
# db_config.php
—-
<?php
 
  $database = «DATABASE_NAME»;
  $username = «USERNAME»;
  $password = «PASSWORD»;
  $host = «localhost»;
 
?>

Вам нужно заменить значения тем, что работает в вашей базе данных, и хост, вероятно, является localhost , но вам нужно дважды проверить это с вашим хостинг-провайдером, чтобы убедиться. Вот дамп SQL таблицы, url_redirects, которая содержит всю информацию, которую мы показали выше:

01
02
03
04
05
06
07
08
09
10
11
12
— Table structure for table `url_redirects`
 
CREATE TABLE IF NOT EXISTS `url_redirects` (
  `id` int(11) NOT NULL auto_increment,
  `short` varchar(10) NOT NULL,
  `url` varchar(255) NOT NULL,
  `created_at` timestamp NOT NULL default CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `short` (`short`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Далее давайте посмотрим на код, необходимый для создания нашего короткого URL.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# create.php
—-
<?php
  require(«./db_config.php»);
   
  $url = $_REQUEST[‘url’];
   
  if(!preg_match(«/^[a-zA-Z]+[:\/\/]+[A-Za-z0-9\-_]+\\.+[A-Za-z0-9\.\/%&=\?\-_]+$/i», $url)) {
    $html = «Error: invalid URL»;
  } else {
     
    $db = mysql_connect($host, $username, $password);
     
      $short = substr(md5(time().$url), 0, 5);
     
      if(mysql_query(«INSERT INTO `».$database.»`.`url_redirects` (`short`, `url`) VALUES (‘».$short.»‘, ‘».$url.»‘);», $db)) {
        $html = «Your short URL is<br />shrtr.me/».$short;
      } else {
        $html = «Error: cannot find database»;
      }
     
    mysql_close($db);
  }
?>
 
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html>
  <head>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″ />
    <title>Makes URLs Shrtr</title>
    <link type=»text/css» rel=»stylesheet» href=»./css/style.css» />
    </head>
    <body>
     <div id=»pagewrap»>
     <h1>shrt<span class=»r»>r
      
     <div class=»body»>
       <?= $html ?>
       <br /><br />
       <span class=»back»><a href=»./»>X</a>
     </div>
        
     </div>
    </body>
</html>

Теперь мы становимся немного сложнее! Сначала нам нужно включить переменные подключения к базе данных, которые мы создали ранее, затем мы сохраняем параметр URL, отправленный нам формой создания, в переменную с именем $ url . Затем мы делаем магию регулярных выражений, чтобы проверить, действительно ли они отправили URL, если нет, мы храним ошибку. Если пользователь ввел действительный URL-адрес, мы создаем соединение с базой данных, используя переменные соединения, которые мы включаем в верхней части страницы. Затем мы генерируем случайную 5-символьную строку для сохранения в базе данных, используя функцию substr . Строка, которую мы разделили, представляет собой хэш md5 текущего времени () и объединенного $ url . Затем мы вставляем это значение в таблицу url_redirects вместе с фактическим URL-адресом и сохраняем строку для представления пользователю. Если не удается вставить данные, мы храним ошибку. Если вы переместитесь вниз в HTML-часть страницы, все, что мы делаем, это распечатываем значение $ html , будь то ошибка или успех. Это, очевидно, не самое элегантное решение, но оно работает!

Итак, у нас есть URL в базе данных, давайте работать над serve.php, чтобы мы могли фактически перевести короткий код в редирект.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
  require(«./db_config.php»);
 
  $short = $_REQUEST[‘short’];
 
  $db = mysql_connect($host, $username, $password);
    $query = mysql_query(«SELECT * FROM `».$database.»`.`url_redirects` WHERE `short`='».mysql_escape_string($short).»‘ LIMIT 1″, $db);
    $row = mysql_fetch_row($query);
 
    if(!empty($row)) {
      Header(«HTTP/1.1 301 Moved Permanently»);
      header(«Location: «.$row[2].»»);
    } else {
      $html = «Error: cannot find short URL»;
    }
 
  mysql_close($db);
?>
 
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html>
  <head>
    <meta http-equiv=»Content-Type» content=»text/html; charset=utf-8″ />
    <title>Makes URLs Shrtr</title>
    <link type=»text/css» rel=»stylesheet» href=»./css/style.css» />
    </head>
    <body>
     <div id=»pagewrap»>
     <h1>shrt<span class=»r»>r
 
     <div class=»body»>
       <?= $html ?>
       <br /><br />
       <span class=»back»><a href=»./»>X</a>
     </div>
 
     </div>
    </body>
</html>

Этот файл очень похож на create.php, в который мы включаем информацию базы данных и храним отправленный нам короткий код в переменной с именем $ short . Затем мы запрашиваем у базы данных URL этого короткого кода. Если мы получим результат, мы перенаправим на URL, а если нет, выведем ошибку, как раньше.

Что касается PHP, это все, что нам нужно сделать, но в данный момент, чтобы поделиться коротким URL-адресом, пользователи должны ввести его, http://shrtr.me/server.php?short=SHORT_CODE не очень красиво, не так ли? Давайте посмотрим, не сможем ли мы включить какой-нибудь код mod_rewrite, чтобы сделать это лучше.

Из двух методов, о которых я писал в начале урока, мы будем использовать Apache, потому что это приложение уже создано без учета разбора URL. Код будет выглядеть примерно так:

1
2
3
4
5
6
7
8
Options +FollowSymLinks
 RewriteEngine On
 
 RewriteCond %{SCRIPT_FILENAME} !-d
 RewriteCond %{SCRIPT_FILENAME} !-f
 
 
 RewriteRule ^(\w+)$ ./serve.php?short=$1

Переходя к RewriteRule, мы направляем любой трафик, у которого еще нет реального файла или каталога, в serve.php и помещаем расширение в переменную GET. Не плохо, не иди попробуй это сам!

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