Повторная запись URL-адреса Apache не работает должным образом

Я пытаюсь использовать правило apache-rewrite для преобразования приведенного ниже URL-адреса:

http://localhost/foo/bar/news.php?id=24

В этом формате:

http://localhost/foo/bar/news/foo-bar

Число 24 является id случайной строки из таблицы MySQL, которая также содержит поля title и content .

 MariaDB [blog]> select * from articles; +----+---------+----------+ | id | title | content | +----+---------+----------+ | 1 | foo-bar | bla bla | +----+---------+----------+ 1 row in set (0.00 sec) 

У меня есть следующее правило внутри моего .htaccess :

 RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-l ^news/([A_Za_z0_9_]+)$ DIRECTORY/AID/news.php?id=$1 [QSA,L] 

У меня также есть PHP-код, который генерирует ссылку:

 $link = "<a href='news.php?id={$row['id']}'></a>"; echo $link; 

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

Solutions Collecting From Web of "Повторная запись URL-адреса Apache не работает должным образом"

Прежде всего, вам нужно будет изменить href в html, чтобы дать новый формат url

 function news_preview() { $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5 "; $result = mysql_query($query) or die(mysql_error()); while($row=mysql_fetch_array($result)) { echo "<a href=\"/news/$row[id]\"> ". substr($row['title'], 0,26)."...</a><br/>".; } } в function news_preview() { $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5 "; $result = mysql_query($query) or die(mysql_error()); while($row=mysql_fetch_array($result)) { echo "<a href=\"/news/$row[id]\"> ". substr($row['title'], 0,26)."...</a><br/>".; } } 

Воля будет генерировать URL-адреса, такие как http://localhost/news/24

Обратите внимание, что я удалил /DIRECTORY/AID из URL-адреса, так как htaccess предлагает вам, чтобы это было URL-адресом, в отличие от того, что вы указали в тексте.

Но теперь перейдите на http://localhost/news/this_is_article_title тип url. Поскольку между this_is_article_title и id 24 нет никакой корреляции, единственный способ достичь этого – либо добавить идентификатор к URL-адресу, либо получить PHP-версию статьи с этим заголовком в базе данных.

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

Поэтому я пойду с первым решением. Мы будем генерировать URL-адреса, подобные этому

http://localhost/news/24/this_is_article_title

Сначала часть php

 function news_preview() { $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5 "; $result = mysql_query($query) or die(mysql_error()); while($row=mysql_fetch_array($result)) { $url = "/news/$row[id]/".preg_replace('/[^a-zA-Z0-9-_]/', '_', $row['title']); echo "<a href=\"$url\"> ". substr($row['title'], 0,26)."...</a><br/>".; } } в function news_preview() { $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5 "; $result = mysql_query($query) or die(mysql_error()); while($row=mysql_fetch_array($result)) { $url = "/news/$row[id]/".preg_replace('/[^a-zA-Z0-9-_]/', '_', $row['title']); echo "<a href=\"$url\"> ". substr($row['title'], 0,26)."...</a><br/>".; } } 

Далее идет часть htaccess.

 RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-l RewriteRule ^news/([0-9]+)/([A-Za-z0-9_-]+)$ DIRECTORY/AID/news.php?id=$1 [QSA,L] 

Это должно сделать это, я думаю.

В URL-адрес замены (Real) есть номер -Code-, чтобы идентифицировать ссылку (согласно вашему описанию): http: //localhost/DIRECTORY/AID/news.php? News = 42

В этом случае этот код составляет 42 , но URL-адрес, который вы хотите отобразить, не имеет его. Без этого числа мы получим ошибку 404 всегда. Это похоже на ввод только: http: //localhost/DIRECTORY/AID/news.php? News =

Необходимо изменить URL-адрес, который вы хотите отобразить, например, добавив код после «/». Может быть дефис и т. Д., Но регулярное выражение должно быть соответствующим образом изменено.

Вот пример ввода: http: // localhost / news / 42 / для перехода на http: //localhost/DIRECTORY/AID/news.php? News = 42 :

 RewriteEngine On RewriteRule ^news/([0-9]+)/?$ DIRECTORY/AID/news.php?news=$1 [NC,L] 

Это все, что вам нужно. Чтобы проверить этот пример, вставьте этот только код в news.php по адресу http: // localhost / DIRECTORY / AID /

 <?php if ( $_GET[ 'news' ] == '42' ) { echo "HERE I AM<br /><br />"; } ?> 

ОБНОВЛЕНО в соответствии с описанием ОП. Вместо This_is_news можно использовать любое имя:

 RewriteEngine On RewriteRule ^news/([0-9a-zA-Z-_]+)/?$ DIRECTORY/AID/news.php?news=$1 [NC,L] 

Разместить RewriteBase сразу после RewriteEngine On. Он будет правильно переписывать движок, прежде чем вы начнете перенаправление

К сожалению, я не могу ответить на ваш вопрос в PHP или Apache (хотя я использую конверт REST с ручным каталогом для создания URL-адресов в моем текущем проекте), но из того, что я понимаю, вы хотите, чтобы ваш пользователь набирал http: / /localhost/DIRECTORY/AID/article.php?a_id=24, и адресная строка должна заканчиваться так : http: // localhost / DIRECTORY / AID / news / this_is_article_title .

Я не совсем понимаю, какие преимущества вам это дает, и, пожалуйста, имейте в виду, что мое решение НЕ позволит вашему конечному пользователю набирать URL RESTful и заканчиваться на странице с адресом QueryString. Для этого вам понадобится дополнительная работа, и еще больше работы, чтобы синхронизировать ее с БД (я бы рекомендовал сценарий, который освобождает RESTFUL URL, запрашивает БД для темы, затем возвращает идентификатор или содержимое страницы. .. но это другой вопрос переполнения стека еще на один день.

РЕШЕНИЕ Мое предлагаемое решение требует HTML5 doctype и очень легкого разбрызгивания Javascript.

 history.replaceState(null, "history title here", "news/this_is_article_title"); 

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

Вот ссылка jsFiddle: http://jsfiddle.net/uT3RP/1/

К сожалению, они запускают код в iframe, поэтому он не контролирует основную адресную строку, поэтому я включил предупреждение о том, что скажет местоположение адресной строки, для доказательства. Это не самые элегантные решения. Я бы даже не рекомендовал делать то, что вы делаете, без сбоев, чтобы убедиться, что отображаемый URL-адрес можно использовать для перехода на ту же страницу. Отказ от ответственности … ваша проблема решена с помощью 1 строки js и изменения doctype (если вы не используете HTML5).

Вы можете прекратить порку бедных людей и продолжить свой проект 🙂

Это проблема с URL-Rewrite и String-to-Id Algorithm.

Прежде всего, помните, что когда ваш URL изменяется с помощью переписывающего модуля, url в панели браузера всегда содержит post param как id или строку (о ваших новостях).

Теперь на вопрос. Наша цель – просто переписать Url:

 http://localhost/DIRECTORY/AID/news/this_is_article_title 

чтобы:

 http://localhost/DIRECTORY/AID/news.php?a_id=24 

С переписанным модулем мы можем только переписать его на:

 http://localhost/DIRECTORY/AID/news.php?title=this_is_article_title 

и вот часть htaccess, alrealdy, протестированная на htaccess-online-тестере

 RewriteRule ^DIRECTORY/AID/news/([A-Za-z0-9_]+)$ DIRECTORY/AID/news.php?title=$1 [QSA,L] 

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

 <?php //write url reflect to news title. function build_news_url_by_title(){ $query = "SELECT * FROM news ORDER BY id DESC LIMIT 5"; $result = mysql_query($query) or die(mysql_error()); while($row = mysql_fetch_array($result)){ echo "<a href=\"news/".strtr(substr($row['title'], 0,26), " ", "_")."\">".substr($row['title'], 0,26)."</a>"; } } function get_news_by_title($title){ $real_title = strtr($title, "_", " "); $query = "SELECT * FROM news WHERE title LIKE %".$real_title."% LIMIT 1"; return mysql_query($query) or die(mysql_error()); } $title = $_POST['title']; $news = get_news_by_title($title); //some code return the news ... 

Итак, URL:

 http://localhost/DIRECTORY/AID/news/this_is_article_title 

может также дать нам новости.

Наконец, из приведенных выше шагов, если мы наберем url

 http://localhost/DIRECTORY/AID/news/this_is_article_title 

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

Вы видите, работает ли это?

 RewriteEngine On RewriteBase /DIRECTORY/AID/ RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-l ^news/([A-Za-z0-9_]+)$ news.php?id=$1 [QSA,L] 

EDIT: Исправлены определения классов символов регулярных выражений.

Вам не указан заголовок URL-адреса. Если вы хотите показать это в URL-адресе, вы должны включить его в ссылку, например:

 <a href="news.php?news_id=$id&title=$url_tile"> 

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

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

  1. Make sure .htaccess file is readable and can do some simple thing, preventing directory indexing for instance. 2. Make sure you can redirect something with simple html code. 3. Make sure you can run Felipe's example code successfully. From here you can get good picture of what is going on. 

И в качестве примечания:

Чаще всего переписывать:

 http://localhost/DIRECTORY/AID/news.php?a_id=24 TO --> http://localhost/DIRECTORY/AID/news/24_this_is_article_title 

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

Измените ссылку:

 echo "<a href=\"news.php?news=$row[id]\"> ". substr($row['title'], 0,26)."</a> 

в

 echo "<a href=\"news/$row['title']\">".$row['title']."</a>" 

Таким образом, ссылка будет идти в news/$row['title'] вместо news.php?id=... И теперь, на странице DIRECOTORY/AID/news.php , вы должны получить id и проверить, является ли это числом или текстом, а в текстовом сопоставлении с $row['title'] а затем загружать страницу соответственно.

Заметки:

  1. Это предполагает, что $ row ['title'] уникален во всех остальных строках.
  2. Заголовок не содержит не HTML-контент, и в этом случае вам придется URL-адрес Escape этих символов.

Если заголовок не будет уникальным, вы должны, вероятно, делать news/{id}/{title} а затем переписывать его в DIRECTORY/AID/news.php?id={id}&title={title} а затем вы может основывать его на идентификаторе вместо названия.

Надеюсь, это поможет.

Если вы чувствуете, что ваш файл .htaccess не работает AllowOverride образом, это проблема с конфигурацией сервера и, скорее всего, связана с директивой AllowOverride в конфигурации Apache.

В вашем файле http.conf найдите раздел, который выглядит следующим образом:

 <Directory> Options FollowSymLinks AllowOverride None </Directory> 

Измените директиву AllowOverride чтобы разрешить All .

 <Directory> Options FollowSymLinks AllowOverride All </Directory> 

Следующее – убедиться, что модуль mod_rewrite включен для вашей установки XAMPP. Найдите следующую строку:

 #LoadModule rewrite_module modules/mod_rewrite.so 

Удалите # чтобы он выглядел так:

 LoadModule rewrite_module modules/mod_rewrite.so 

Перезагрузите службу Apache после сохранения всех изменений.

Также убедитесь, что вы используете директиву RewriteBase в конфигурации .htaccess следующим образом:

 RewriteEngine On RewriteBase /DIRECTORY/AID/ RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-l ^news/([A-Za-z0-9_]+)(/)?$ news.php?title=$1 [QSA,L] 

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

 echo "<a href=\"news/" . $row['title'] . "\"> " . substr($row['title'], 0, 26) . "...</a><br />"; 

Теперь, поскольку вы можете получать только заголовки с помощью этого метода перезаписи URL-адресов, нам необходимо настроить ваш PHP-скрипт соответственно для получения содержимого на основе заголовка. Если вы все еще хотите использовать «id» только для получения записи, ваш URL-адрес перезаписи должен содержать «id» в нем в той или иной форме. Типичными примерами этой формы являются:

  • news/the_news_title_123
  • news/123_the_news_title
  • news/123/the_news_title

Я не могу комментировать, поэтому я должен ответить.

Читая все ответы и ваш вопрос, неясно, чего вы хотите. По крайней мере для меня. Вы говорите, например:

http://localhost/DIRECTORY/AID/article.php?a_id=24 to

http://localhost/DIRECTORY/AID/article/this_is_article_title

Но я думаю, это не совсем правильно, если вы не хотите

http://localhost/DIRECTORY/AID/article.php?a_id=24

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

Я предполагаю, что вы хотите ввести дружественный URL:

http://localhost/DIRECTORY/AID/article/this_is_article_title , поэтому вопрос должен быть наоборот:

http://localhost/DIRECTORY/AID/article/this_is_article_title TO

http://localhost/DIRECTORY/AID/article.php?a_id=24

Следующее, что кажется неясным, – это то, что отображается в панели браузера? Единственный ответ: введенный URL. Ни в коем случае это не может показать ничего другого.

Вкратце: если вы хотите, чтобы http: // localhost / DIRECTORY / AID / article / this_is_article_title отображался в баре addres, это то, что вам нужно ввести. Настоящий URL-адрес, ЗАМЕНА ( http: //localhost/DIRECTORY/AID/article.php? A_id = 24 ), никогда не отображается и никогда не вводится. Это перенаправление.

С другой стороны, неясно, как ожидается, что идентификационные номера, предоставленные news.php, будут преобразованы в строки, такие как article / this_is_article_title . ¿Где эти строки, сколько идентификационных номеров, какой алгоритм или формула следует использовать для достижения этого преобразования, какие из этих идентификаторов являются «root», как вы упомянули в комментарии, и как их можно идентифицировать и т. Д.? Вы должны подробнее рассказать об этом, потому что он кажется импровизированным и несогласованным с вашими предыдущими комментариями.

Конечно, я ошибаюсь. Я просто угадываю, чтобы попытаться помочь с вашим вопросом.

Пожалуйста, гении, не делайте этого, ответьте, не читайте. Я не пытаюсь ответить на вопрос, и я действительно далек от гения.

Похоже, вы забыли косую перед «news.php».