8

I am trying to use apache-rewrite rule to convert the below URL:

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

Into this format:

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

The number 24 is an id of a random row from a MySQL table, which also contains title and content fields.

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

I have the following rule inside my .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]

I also have a php code that generates a link like this:

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

However, I can't get the rewrite rule to change the path as the desired end result.

4

12 回答 12

4

替换(真实)URL 有一个数字 -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]

这就是你所需要的。要测试此示例,请在http://localhost/DIRECTORY/AID/的news.php中插入仅此代码

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

根据 OP 描述更新。可以使用任何名称代替This_is_news

RewriteEngine On
RewriteRule ^news/([0-9a-zA-Z-_]+)/?$ DIRECTORY/AID/news.php?news=$1 [NC,L]
于 2012-11-26T09:30:34.163 回答
2

首先,您需要更改 html 中的 href,以提供新的 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/>".; }
}

将生成像这样的网址http://localhost/news/24

请注意,我/DIRECTORY/AID从 url 中删除了 ,因为 htaccess 建议您希望它是 url,而不是您在文本中所说的。

但是现在获取到http://localhost/news/this_is_article_titleurl 的类型。this_is_article_title因为和 id之间没有相关性24,所以实现这一点的唯一方法是将 id 也添加到 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/>".; }
}

接下来是 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]

我认为应该这样做。

于 2012-12-01T20:51:38.213 回答
1

不幸的是,我无法用 PHP 或 Apache 回答您的问题(尽管我正在使用手动 REST 转换器在我当前的项目中创建 URL 地址),但据我了解,您希望您的用户输入http:/ /localhost/DIRECTORY/AID/article.php?a_id=24并且地址栏应该像http://localhost/DIRECTORY/AID/news/this_is_article_title 一样结束

我不完全确定这会给您带来什么好处,请记住,我的解决方案不允许您的最终用户键入 RESTful URL 并最终进入带有 QueryString 地址的页面。你需要一些额外的工作来做到这一点,甚至需要更多的工作来保持它与数据库同步(我建议使用一个脚本来定义 RESTFUL URL,在数据库中查询主题然后返回 ID 或页面内容。 ..但这是另一天的另一个堆栈溢出问题。

解决方案 我提出的解决方案需要 HTML5 文档类型和少量的 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)。

您可以停止鞭打可怜的 ol' htaccess 并继续您的项目:)

于 2012-12-01T12:02:12.063 回答
1

更改链接:

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=.... 现在在 pageDIRECOTORY/AID/news.php中,您应该获取id并检查它是否是数字文本,如果是文本,则将其与 匹配$row['title'],然后相应地加载页面。

笔记:

  1. 这假设 $row['title'] 在所有其他行中是唯一的。
  2. 标题不包含非 HTML 内容,在这种情况下,您必须对这些字符进行 URL 转义。

如果标题不是唯一的,那么您可能应该这样做news/{id}/{title},然后将其重写为DIRECTORY/AID/news.php?id={id}&title={title},然后您可以将其基于 ID 而不是标题。

希望有帮助。

于 2012-12-05T18:44:57.237 回答
1

这似乎是一个复杂的问题,因为你不知道它到底在哪里做错了。

我建议您将您想做的事情分成小部分,并在将它们组合在一起之前使它们各自正常工作。例如:

 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 

请注意,id 24 仍然保留在重写后的 url 中。这将使模式匹配更简单,并避免不必要的标题重复处理。

于 2012-12-05T15:02:11.123 回答
1

这是关于 URL-Rewrite 和 String-to-Id 算法的问题。

最重要的是,请记住,无论您的 url 通过 rewrite 模块发生什么变化,浏览器栏中的 url 始终包含诸如 id 或 string 之类的帖子参数(关于您的新闻)。

现在的问题。我们的目的只是重写 Url:

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

至:

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

使用 rewrite 模块,我们只能将其重写为:

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

这是 htaccess 部分,已经在htaccess-online-tester上进行了测试

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
...

所以网址:

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

也可以给我们消息。

最后,从上面的步骤中,如果我们输入 url

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

在浏览器栏中,它也可以给我们新闻。它与愚蠢的ID无关。虽然,上面的代码可能有一些错误,但不要把它放在你的产品服务器上。

于 2012-12-05T06:39:18.927 回答
1

如果您觉得您的.htaccess文件没有按预期工作,那么这是一个服务器配置问题,很可能与AllowOverrideApache 配置下的指令有关。

在您的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。您的回声线应类似于以下内容:

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

现在,由于您只能使用此 URL 重写方法检索标题,我们需要相应地配置您的 PHP 脚本以根据标题检索内容。如果您仍然只想使用“id”来检索记录,那么您的 Rewrite URL 应该以某种形式包含“id”。这种形式的典型例子是:

  • news/the_news_title_123
  • news/123_the_news_title
  • news/123/the_news_title
于 2012-12-06T05:35:09.610 回答
1

你能看看这是否有效吗?

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]

编辑:修复了正则表达式字符类定义。

于 2012-12-05T08:18:02.353 回答
1

您缺少 URL 的标题。如果您希望在 URL 中显示它,那么您也必须在链接中包含它,如下所示:

<a href="news.php?news_id=$id&title=$url_tile">
于 2012-12-05T08:24:40.373 回答
1

在 RewriteEngine On 之后放置 RewriteBase 它会在您开始重定向之前正确设置重写引擎

于 2012-11-26T12:30:37.860 回答
0

我无法发表评论,所以我必须回答。

阅读所有答案和您的问题,尚不清楚您想要什么。至少对我来说。你说,例如:

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

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

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

接下来似乎不太清楚的事情是浏览器栏中显示的内容是什么?唯一的答案是:输入的 URL。它不可能显示任何不同的东西。

简而言之:如果您希望http://localhost/DIRECTORY/AID/article/this_is_article_title显示在地址栏中,那就是您必须输入的内容。真正的 URL,即 SUBSTITUTION ( http://localhost/DIRECTORY/AID/article.php?a_id=24 ) 永远不会显示,也永远不会输入。这就是重定向的用途。

另一方面,也不清楚 news.php 提供的 ID 号如何转换为article/this_is_article_title 之类的字符串。¿ 这些字符串在哪里,有多少个 ID 号,应该使用哪种算法或公式来实现该转换,这些 ID 中的哪些是您在评论中提到的“根”以及如何识别它们等?您应该详细说明这一点,因为它似乎是即兴的,与您之前的评论不一致。

当然,我可能是错的。我只是想尝试帮助您解决问题。

天才们,请不要对这个答案投反对票,请阅读。我不是要回答这个问题,而且我离天才还差得很远。

于 2012-11-28T23:58:54.017 回答
-2

看起来你忘记了“news.php”前面的斜线。

于 2012-11-26T02:03:07.937 回答