Перенаправить 404 на похожие URL-адреса
У меня есть сайт с рассказами в нем. Я могу иметь несколько типов историй в нескольких категориях, например:
- Дети
- романс
- SciFi
- действие
- thriler
- квесты
Истории доступны с помощью URL-адресов, например:
www.example.com/action/story-name-action/
www.example.com/romance/story-name-romance/
а первый параметр (действие) и второй (story-name-action) перенаправляются с помощью .htaccess с использованием правил. Эта часть работает очень хорошо.
В последнее время я получаю несколько десятков 404 с разных сайтов, и вот что я хочу сделать, но я не знаю, как:
Если кто-то печатает, например: /action/story-nme-ction
, я хочу перенаправить на: action/story-name-action/
Есть ли эффективный способ реализовать это?
Ответы
Ответ 1
О человеке, о человеке!
То, о чем вы просите, не просто и вам нужно иметь мощный компьютер, но результаты просто потрясающие.
Вот что я предлагаю сделать:
- Для правильной обработки 404 у вас есть перенаправление
ErrorDocument
в конфигурации vhost. Моя выглядит так: ErrorDocument 404 /404.php
;
- При наличии 404 Apache вызовет
/404.php
со всеми аргументами (какой плохой URL и т.д., dump $_SERVER
, чтобы увидеть это). Вы должны проверить, есть ли только два выражения в URL /
i.e. http://mysite.com/(expr1)/(expr2)/
- Если нет, тогда сделайте классический 404.
- Если да, выполните SOUNDEX поиск с MySQL (в вашем
404 Php
файле). См. Образец запроса здесь.
- Затем, в этом "специальном" случае 404, сделайте предложение, например google, т.е.: "вы имели в виду
/action/story-name-action/
? если это так, щелкните по ссылке".
Это тяжелая работа, но она интересна и показывает ваше мастерство. Очень немногие сайты делают это (я просто знаю google на самом деле).
Вот демо на моей французской таблице, которая может дать вам обзор того, как это работает:
mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Machiniste cinéma');
+-------+--------------------+
| id | description |
+-------+--------------------+
| 14018 | Machiniste cinéma |
+-------+--------------------+
1 row in set (0.06 sec)
mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Mchiniste cinéma');
+-------+--------------------+
| id | description |
+-------+--------------------+
| 14018 | Machiniste cinéma |
+-------+--------------------+
1 row in set (0.06 sec)
mysql> SELECT * FROM job WHERE
SOUNDEX( description ) LIKE SOUNDEX('Machnste cinema');
+-------+--------------------+
| id | description |
+-------+--------------------+
| 14018 | Machiniste cinéma |
+-------+--------------------+
1 row in set (0.06 sec)
mysql>
Ответ 2
Если вы не уверены в URL-адресе, к которому пользователь действительно хотел перейти, использование перезаписи/перенаправления на определенный URL-адрес - очень плохая идея.
Взяв ваш пример, предположим, что вы хотите обрабатывать каждый случай, когда две буквы могут быть удалены, с 17 символами в последней части URL-адреса, что 17 * 16 = 272 комбинации, в то время как может быть возможно сопоставить несколько ' false "с одним регулярным выражением, вам потребуется много правил перезаписи.
Лучшим решением было бы реализовать 404-обработчик с использованием PHP (так как вы включили этот тег в свой q), чтобы создать список (скажем) 10 лучших URL-адресов, пути которых имеют кратчайшее левенштайнское расстояние от запрашиваемого пути, наряду со ссылкой по умолчанию и поддерживающим текстом. (Есть реализаций на основе mysql - попробуйте Google для URL-адресов). Обработчик NB должен по-прежнему возвращать статус 404. NB HTML-контент должен быть более чем минимальной длины, чтобы подавить сообщение об ошибке "MSI".
Ответ 3
Если вы знаете, какие могут быть возможные правильные URL-адреса, вы можете использовать:
levenshtein($givenURL, $possibleURL)
Пример из документации PHP, комментарии удалены для краткости:
$input = 'carrrot';
$words = array('apple','pineapple','banana','orange',
'radish','carrot','pea','bean','potato');
$shortest = -1;
foreach ($words as $word) {
$lev = levenshtein($input, $word);
if ($lev == 0) {
$closest = $word;
$shortest = 0;
break;
}
if ($lev <= $shortest || $shortest < 0) {
$closest = $word;
$shortest = $lev;
}
}
echo $shortest == 0 ? "Exact match found: $closest\n" : "Did you mean: $closest?\n";
Выходы:
Слово ввода: carrrot
Возможно, вы имели в виду: carrot?
Это хорошо, когда вы думаете, что люди, возможно, пропустили письмо или добавили лишний, но это может упасть, когда люди искренне не знают, как записать слово и придумали что-то творческое!
Если вы предпочитаете маршрут soundex()
, посмотрите metaphone()
.
Мне нравится идея использовать metaphone()
рядом с levenshtein()
или similar_text()
, так как она возвращает фонетическое представление слова, и вы все же хотите видеть, насколько это похоже на ваш оригинал.
Примеры:
metaphone('name') = NM
metaphone('naaaaaameeeeeeee') = NM
metaphone('naiym') = NM
metaphone('naiyem') = NYM
В то время как много орфографических ошибок вернет одинаковое совпадение, последний пример показывает, что вы действительно хотите найти ближайшее совпадение с чем-то вроде levenshtein()
Для эффективности, если вы используете другой файл 404, в котором перезаписываемые файлы пытались сопоставить этот шаблон и сбой, чем вы используете для остальной части сайта, это действительно не должно быть значительным накладным расходами.
Если вы получаете то же самое 404 от одного и того же реферера, (и не можете заставить их изменить ссылку), возможно, стоит просто поставить статический переписать в этом случае.
Ответ 4
Существует несколько решений:
- Определите источник ошибочных URL-адресов. Этого просто не должно быть, и я не могу представить, почему это происходит. Связаны ли другие люди в другом месте, и они сделали опечатку (игнорируя существование копии и пасты)? Вы можете видеть, откуда это взялось (referer) и связаться с ними?
- Добавьте идентификатор в URL-адрес, поэтому
/action/123/story-name-action
, где вы просматриваете статью по идентификатору, а не по его заголовку (бонус: добавляет возможность создания нескольких историй одной категории с тем же названием)
- Сделайте нечеткий поиск в названии, используя что-то вроде soundex и перенаправить пользователя на наиболее подходящий заголовок или показать обзорную страницу с похожими названиями, такими как @symcbean.
Я предпочитаю идентификатор, хотя.
Ответ 5
Мы перенаправляем перенаправления на страницу поиска для URL-адреса, например: наш поиск имеет "предложенную" функцию.
Ответ 6
Поскольку значения (предположительно) вытягиваются из MySQL на основе заголовка, вы можете поместить индекс FULLTEXT
в столбец заголовка и использовать MySQL MATCH()
, чтобы найти наиболее релевантное совпадение и перенаправить пользователя к этому.
Хотя это будет отнюдь не идеальное решение - тип интеллекта, требуемый для этого с любой реальной степенью точности, опасно приближается к Тест Тьюринга.