Friendly URL and 301 redirect - .htaccess

I'm trying to rewrite a URL so that it's user/search engine friendly, then 301 redirect the original URL to the new one.
At the moment the posts generate like this:
example.com/blog/post.php?s=nice-post
But I'd like them to look like this:
example.com/blog/nice-post
Here's what I've got so far:
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{QUERY_STRING} ^s=(.+)$
RewriteRule post.php /%1? [R=301,L]
RewriteCond %{REQUEST_URI} !post.php
RewriteRule ^([a-zA-Z0-9_-]+)$ post.php?s=$1
Unfortunately, this clashes with the 404 redirect, sending all pages not found to the blank post.php file, and I can't work out why. Is there a better way of approaching the URL rewrite/redirect?
Thanks for having a look :)

Elaborating on tdammers' suggestion about header()
in your post.php, before outputting anything, decide if it's a valid post or not (for example by looking its id up in the database).
if( !$valid ) {
header( 'HTTP/1.0 404 Not Found' );
echo "404";
exit;
}
i.e. if the page was found invalid, PHP sends out a 404 header to the browser to notify it that this is a missing page. Unfortunately, there's no straightforward way to redirect to Apache's default 404 page, so you'll have to output something yourself -- but since you already have a custom 404 page, you may just include() that.

Going to assume you've got these rules in an htaccess file in your /blog/ directory. Try adding a RewriteBase and removing the leading slash from your query string backreference:
RewriteEngine On
RewriteBase /blog/
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{QUERY_STRING} ^s=(.+)$
RewriteRule post.php %1? [R=301,L]
RewriteCond %{REQUEST_URI} !post.php
RewriteRule ^([a-zA-Z0-9_-]+)$ post.php?s=$1

Related

Apache redirect directive not acting as final rule

I am trying to achieve a simple redirect - from /news to /insights
I have the following in my .htaccess file:
redirect 301 /news /insights
<IfModule mod_rewrite.c>
RewriteEngine On
# Send would-be 404 requests to Craft
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC]
RewriteRule (.+) index.php?p=$1 [QSA,L]
</IfModule>
Whenever I've used the redirect directive before, any matched URLs would be redirected and no further rewrites in the file would be processed. That is to say, going to /news would send you to /insights, and the rewrite to index.php would not be processed.
However, with this current setup, going to /news sends me to /insights?p=news, so for some reason the rewrite to index.php is still being processed.
Furthermore, if I comment out the index.php rewrite, then I get sent to /insights as expected.
This isn't how I've usually experienced this working so am unsure why it's doing this.
I have also tried the following:
RewriteEngine On
RewriteRule "^/news" "/insights" [R=301,L]
This simply results in a 404 instead of redirecting, which I also do not understand.
I am aware I could do the following:
RewriteEngine On
RewriteCond %{REQUEST_URI} "^/news"
RewriteRule ^ /insights [R=301,L]
which does work, however, I don't really want to have multi-line rewrites for lots of URLs, and would like to understand why the other 2 examples do not work.
You just need to insert this rule before last catch-all rule.
RewriteRule ^/?news/?$ /insights [R=301,L,NC]
Place it just below RewriteEngine On line so that mod_rewrite engine executed this rule before other rule.
Make sure to test it in a new browser.

php - Htaccess as fake directories

I am making a mini blog that could make it's url looks like this:
From: http://127.0.0.1/index.php?post=the-story-of-us
To: http://127.0.0.1/view/the-story-of-us
I have tried this but i'm getting 404 not found.
RewriteEngine on
RewriteCond %{THE_REQUEST} ^(GET|POST|HEAD)\ /index\.php\?post=([^&]+)
RewriteRule ^ /view/%2/? [L,R=301]
Your current rule only handles the case: Redirect old url to new url.
(By the way, +1 for using THE_REQUEST to avoid a redirect loop)
You also need to handle the case: Rewrite (internally) new url to old url.
Here is how your htaccess should look like
RewriteEngine On
# Redirect /index.php?post=XXX to /view/XXX
RewriteCond %{THE_REQUEST} \s/index\.php\?post=([^&\s]+)\s [NC]
RewriteRule ^ /view/%1? [L,R=301]
# Internally rewrite back /view/XXX to /index.php?post=XXX
RewriteRule ^view/([^/]+)$ /index.php?post=$1 [L]
I do not udnerstand your RewriteCondition, but the RewriteRule should look like this:
RewriteEngine on
RewriteBase /
RewriteRule ^view/(.*)/? ./index.php?post=$1 [L,R=301]

Force a 404 page for certain URL parameters

How do I force a 404 error through htaccess for URLs that contain "mobile=no"?
This question is not the same as a previously answered question. This one deals with returning a 404 for URLs that contain a certain parameter. In my case, "mobile=no".
RewriteCond %{QUERY_STRING} ^mobile=no$
RewriteRule ^(.*)$ 404.html [R=404,L,NC]
Try this :
RewriteEngine on
RewriteCond %{THE_REQUEST} \?mobile=no [NC]
RewriteRule ^ - [R=404,L]

(htaccess) Rewrite English names of php files to their Dutch equivalents

I would like to rewrite the English names of php files to their Dutch equivalents.
For example: someurl.com/news.php?readmore=4#comments should become someurl.com/nieuws.php?leesmeer=4#kommentaar. The code from news.php should be executed but nieuws.php should be in the url the arguments should function as well.
I tried several htaccess examples but I can't get it to work.
Any help would be appreciated.
Edit: Working progress from answers below and final solution.
RewriteCond %{QUERY_STRING} ^readmore=(.*)$
RewriteRule ^news.php$ nieuws.php?leesmeer=%1 [R=301,L]
RewriteCond %{QUERY_STRING} !^norewrite[\w\W]*$
RewriteRule ^news.php$ nieuws.php [R=301,L]
RewriteRule ^nieuws.php$ news.php?norewrite [QSA]
RewriteCond %{QUERY_STRING} !^norewrite[\w\W]*$
RewriteRule ^search.php$ zoeken.php [R=301,L]
RewriteRule ^zoeken.php$ search.php?norewrite [QSA]
# make sure rewrite is activ
RewriteEngine On
# Rewrite a request for nieuws.php to news.php
RewriteRule ^nieuws.php$ news.php
Should do the trick.
Instad you could send all requests to an index.php and parse them there:
## Redirect everything to http://hostname/?path=requested/path
RewriteEngine On
RewriteRule ^([\w\W]*)$ index.php?path=$1 [QSA]
[QSA] makes sure you get the original get arguments too.
Now you have to parse the request in $_GET['path'] in you index.php and include the requested page.
eg:
if ($_GET['path'] == 'nieuws.php') {
include 'news.php';
} else if (empty($_GET['path'])) {
echo "HOME";
}
if you want to make make the user always sees nieuws.php in its address bar, even if he requested news.php, you could try the following:
RewriteEngine On
# Redirect news.php to nieuws.php if and only if the request comes from the client
# (suppose the client didn't set ?norewrite.)
RewriteCond %{QUERY_STRING} !^norewrite[\w\W]*$
RewriteRule ^news.php$ nieuws.php [R=301,L]
# Send news.php if nieuws.php was requested and prevent news.php from being redirected
# to back to nieuws.php by the rule above.
RewriteRule ^nieuws.php$ news.php?norewrite [L,QSA]
(R=301 means send a "moved permanently" redirect to the client, L means stop rewriting after this rule matched)
The hole thing with norewrite (you could use something else instead) is only needed to avoid an endles loop of rewriting between news and nieuws.
To translate the GET arguments, you can try the following code before the first line of the above code:
RewriteCond %{QUERY_STRING} ^readmore=(.*)$
RewriteRule ^news.php$ nieuws.php?lesseer=%1 [R=301,L]
Things after a the # in an url can't be changed in .htaccess, since they aren't send to the server at all. The only chance to change them is using JavaScript. (See lots of question here on manipulating them within JavaScript)
Try:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /news\.php
RewriteRule ^ /nieuws.php [L,R=301,QSA]
RewriteRule ^nieuws\.php$ /news.php [L,QSA]

Why isn't my .htaccess 301 redirect rule working?

I use URL rewriting on my redesigned website to give my pages tidier URLs.
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^$ index.php [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^.+/$ %{REQUEST_URI}index.php [L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+\.php|(.+/)?index)$ - [R=404,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{SCRIPT_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
This .htaccess file allows /filename to actually point to /filename.php. It all works fine.
However, I have now realised that I should set up 301 permanent redirects, so that the pages of the old website (before the redesign) can redirect to pages on the new site (for SEO and linking reasons). The pages have been reorganised, so multiple old pages will redirect to new pages, for example.
The old website did not use URL rewriting. Therefore, I want to create permanent redirects such as /about-page.php to /about, doing them manually with one rule per old page.
I have tried several things, such as...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^about-page.php$ about [R=301,L]
...or...
Redirect 301 /about-page.php /about
...but it always ends up either not working at all (giving me a 404 error when I attempt to access /old-filename.php, or breaks everything with internal server errors. It seems to work fine if I use Redirect 301 /about-page.html /about instead, but unfortunately the old URLs used .php extensions, not .html extensions.
I believe the problem is related to one of the other rules, which redirect requests for /xyz to /xyz.php, possibly creating some endless loop. But I can't figure out how to fix it.
Any advice? Thank you very much.
Edit: Final, working .htaccess file:
DirectoryIndex index.php #
RewriteEngine On
# -- Use a permanent redirect to point the old page to the new page.
# -- The RewriteCond is needed, or a redirect loop happens in certain cases.
# -- The full URL seems to be needed, or it redirects incorrectly.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^about-page.php$ http://www.mywebsite.com/about [R=301,L]
# -- Redirect most other .php files to a 404 error, to avoid duplicate content.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+\.php|(.+/)?index)$ - [R=404,L]
# -- Redirect requests without an extension, but for a valid file, to that file.
# -- I'm not sure what the RewriteCond lines are for, but they both seem necessary.
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{SCRIPT_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
DirectoryIndex index.php # -- this sets index.php to be default file for a folder
RewriteEngine On
# -- RewriteRule ^(.+\.php|(.+/)?index)$ - [R=404,L]
# -- dude this above line redirects all php files to 404 error
# -- so delete this, its a problem not solution
RewriteCond %{SCRIPT_FILENAME}.php -f
RewriteRule ^(.+)$ $1.php [L]
RewriteRule ^about-page.php$ /about [R=301,L]
This should work, comment if problem occurs

Resources