Apache URL Re-writing not functioning properly

2019-02-21 22:42发布

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.

12条回答
欢心
2楼-- · 2019-02-21 23:17

If you feel your .htaccess file is not working as intended then this is a server configuration issue and most likely to do with the AllowOverride directive under the Apache configuration.

In your http.conf file find the section which looks something as follows:

<Directory>
    Options FollowSymLinks
    AllowOverride None
</Directory>

Change the AllowOverride directive to allow All.

<Directory>
    Options FollowSymLinks
    AllowOverride All
</Directory>

The next thing is to ensure that the mod_rewrite module is enabled for your XAMPP install. Search for the following line:

#LoadModule rewrite_module modules/mod_rewrite.so

Remove the # so it looks like so:

LoadModule rewrite_module modules/mod_rewrite.so

Restart the Apache service after saving all your changes.

Also ensure you are using the RewriteBase directive in your .htaccess configuration as follows:

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]

The next thing is to ensure your links are pointing to the Rewrite URL. Your echo line should be something like the following:

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

Now since you can only retrieve titles with this URL rewrite method we need to configure your PHP script accordingly to retrieve the content based on the title. If you still want to use "id" only for retrieving the record then your Rewrite URL should contain the "id" in it in some form. Typical examples of this form are:

  • news/the_news_title_123
  • news/123_the_news_title
  • news/123/the_news_title
查看更多
一夜七次
3楼-- · 2019-02-21 23:22

You are missing the title of the URL. If you wish to show that in URL, then you must include it in the link as well, like this:

<a href="news.php?news_id=$id&title=$url_tile">
查看更多
劳资没心,怎么记你
4楼-- · 2019-02-21 23:23

First of all, you would need to change the href in the html, to give the new url format

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/>".; }
}

The will generate urls like http://localhost/news/24

Note that I removed the /DIRECTORY/AID from the url, as the htaccess suggest you want that to be url, as opposed to what you stated in the text.

But now the get to the http://localhost/news/this_is_article_title type of url. Because there is no correlation between this_is_article_title and the id 24, the only way to achieve this is by either adding the id to the url too, or to have the php lookup the news-article with this title in the database.

This last solution however has some problems, as the you can't just us the title in a url. You have to escape characters. Also you'll have to add a index for the title row in the DB for better performance.

So I'll go with the first solution. We will generate urls like this

http://localhost/news/24/this_is_article_title

First the php part

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/>".; }
}

Next comes the htaccess part.

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]

That should do it I think.

查看更多
【Aperson】
5楼-- · 2019-02-21 23:24

Unfortunately I'm unable to answer your question in PHP or Apache (although I am using a hand-rolled REST converter to create URL addresses on my current project), but from what I understand, you want your user to type out http://localhost/DIRECTORY/AID/article.php?a_id=24 and the address bar should end up like http://localhost/DIRECTORY/AID/news/this_is_article_title.

I'm not entirely sure what benefits this provides for you, and please bear in mind my solution will NOT allow your end-user to type the RESTful URL and end up at the page with the QueryString address. You'd need some extra legwork to do this, and even more legwork to keep it in sync with the DB (I'd recommend a script that deseminates the RESTFUL URL, queries the DB for the topic then returns the ID or page content ... but that's an different Stack Overflow question for another day.

SOLUTION My proposed solution requires HTML5 doctype and a very light sprinkling of Javascript.

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

What this does is it changes the URL in the address bar without triggering a page redirect, reload or anything else. This javascript can be dynamically written with your PHP so as the page is served, the address is updated. The higher up in the document it is, the faster the change.

Here's a jsFiddle link: http://jsfiddle.net/uT3RP/1/

Unfortunately they run the code in an iframe so it doesn't control the main address bar, so I included an alert displaying what the address bar location would say, for proof. It's not the most elegant of solutions. I wouldn't even recommend doing what you're doing without the failsafes of making sure the URL displayed can be used to get to the same page. Disclaimer aside ... your problem is solved with 1 line of js and a doctype change (if you aren't using HTML5).

You can stop flogging poor ol' htaccess and get on with your project :)

查看更多
来,给爷笑一个
6楼-- · 2019-02-21 23:25

Can you see if this works?

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 : Fixed the regex character class definitions.

查看更多
狗以群分
7楼-- · 2019-02-21 23:28

This is a problem about URL-Rewrite and String-to-Id Algorithm.

Above all, please remember that what ever your url changes by rewrite module, the url in the browser bar always contains the post param like id or string(about your news).

Now to the question. Our purpose is just to rewrite the Url:

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

to:

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

With the rewrite module, we can only rewrite it to:

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

and here is the htaccess part, alrealdy tested on a htaccess-online-tester

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

The remaining work is build a algorithm for mapping the title to the news which rewrite module cannot help us(especially you manually rewrite the url one by one). We can use php code below:

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

So the url:

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

can give us the news also.

Finally, from the steps above, if we type url

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

in the browser bar, it can be also give us the news. And it has none bussiness about the stupid ID. And Though, there maybe some bugs with the code above, do not put it on your product server.

查看更多
登录 后发表回答