How to rewrite clean URLs with .htaccess - .htaccess

I have the following .htaccess rule for language setting:
RewriteRule ^en/?$ /index.php?lang=en [NC,L,R=301]
RewriteRule ^fr/?$ /index.php?lang=fr [NC,L,R=301]
RewriteRule ^de/?$ /index.php?lang=de [NC,L,R=301]
However, when I input the clean URL for example example.com/fr, then the URL redirects to example.com/index.php?lang=fr in the browser.
How can the URL remain clean?
I tried the following, but it does not work either, the URL does not remain clean:
RewriteRule ^/([^/]+)/? /index.php?lang=$1 [L,QSA,NC]

RewriteRule ^en/?$ /index.php?lang=en [NC,L,R=301]
RewriteRule ^fr/?$ /index.php?lang=fr [NC,L,R=301]
RewriteRule ^de/?$ /index.php?lang=de [NC,L,R=301]
To prevent the external redirect you just need to remove the R flag. This then becomes an internal rewrite and the URL remains as example.com/fr in the browsers address bar. For example:
RewriteRule ^en/?$ /index.php?lang=en [NC,L]
To make this more concise when the number of languages are limited then you can combine these three directives into one using alternation in the regex:
RewriteRule ^(en|fr|de)/?$ /index.php?lang=$1 [NC,L]
$1 is a backreference to the captured language id: "en", "fr" or "de".
You will need to clear your browser cache before testing as any erroneous 301s are likely to have been cached by the browser.
RewriteRule ^/([^/]+)/? /index.php?lang=$1 [L,QSA,NC]
This would never match in a .htaccess context, simply because of the slash prefix on the RewriteRule pattern. So this wouldn't have done anything. (You may have seen a cached response if the request was still redirected?). This should read:
RewriteRule ^([^/]+) /index.php?lang=$1 [L,QSA,NC]
The trailing /? on the pattern is superfluous. However, this matches any path segment. eg. example.com/about or example.com/foo/bar, etc.

Related

Need Assistance for this Htaccess Rewrite Rule

I have a problem with my .htaccess, a short explanation I would like to set http://example.com/newest on my website. However, it always redirects to http://example.com/postname. Where I just need the exact "newest" page. Here is my code:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteBase /
RewriteRule ^[^/]+$ %{REQUEST_URI}/ [L,R=301]
RewriteRule ^/category/(.*)$ page.php?f=$1
RewriteRule ^/search/(.*)$ search.php?f=$1
RewriteRule ^(.*)/$ post.php?f=$1 <- If this is removed, my post htaccess will not work
RewriteRule ^newest/$ index.php?f=newest <- I want to execute this code
I really don't know what this is called, I have been looking for the whole stackoverflow but I did not get any answer. Please remain me if this is a duplicate question.
As Mohammed implied in comments, your directives are in the wrong order. The line above your "newest" rewrite is a catch-all and rewrites all requests, so the last line will never match.
http://example.com/newest
Note that your rules imply that your URLs should end in a trailing slash. So, you should be linking to http://example.com/newest/ (with a trailing slash), not http://example.com/newest, otherwise your users will get a lot of unnecessary redirects.
However, you appear to be under the belief that the RewriteCond directive applies to all the directives that follow. This is not the case. It only applies to the first RewriteCond directive. You also need some L flags to prevent further processing.
You also have a slash prefix on the "category" and "search" rewrite patterns, so these would never match in a .htaccess context.
Try something like the following instead:
RewriteEngine On
RewriteBase /
# Don't process the request further if it maps to an existing file
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Append trailing if omitted
# Although strictly speaking this only redirects if there are no slashes at all in the URL
RewriteRule ^[^/]+$ %{REQUEST_URI}/ [L,R=301]
RewriteRule ^category/(.*)$ page.php?f=$1 [L]
RewriteRule ^search/(.*)$ search.php?f=$1 [L]
RewriteRule ^newest/$ index.php?f=newest [L]
RewriteRule ^(.*)/$ post.php?f=$1 [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]

SEO Url for Profiles

Preface
I'm trying to re-write a URL for a profile page. All of my application pages have a .html extension, so I'm trying to match just letters, numbers, -, and ..
So these would be valid
site.com/steve
site.com/steve-robbins
site.com/steve.robbins
But these wouldn't be
site.com/steve.html
site.com/steve-robbins.php
Assume I have a check in place so that custom URLs don't have .html or .php on the end.
Problem
I'm currently using this but it's not working
RewriteRule ^([a-zA-Z0-9\.-]+)$ profile.php?url=$1 [L]
It should set url to steve, but it's setting it to profile.php
What am I doing wrong?
My complete .htaccess
Options +FollowSymLinks
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP_HOST} ^[^.]+\.[^.]+$
RewriteRule ^(.*) http://www.%{HTTP_HOST}/$1 [R=301]
#
# LOGIN
#
RewriteRule ^([a-z0-9]{255})/activate\.html$ login.php?activate=$1 [L]
RewriteRule ^logout\.html$ login.php?logout [L]
#
# SETTINGS
#
RewriteRule ^change-([a-z]+)\.html$ account-settings.php?$1 [L]
RewriteRule ^([a-zA-Z0-9\.-]+)$ profile.php?url=$1 [L]
# SEO friendly URLs
RewriteRule ^([a-zA-Z0-9-_.]+)\.html$ $1.php [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([a-zA-Z0-9-_.]+)\.php
RewriteRule ^([a-zA-Z0-9-_.]+)\.php$ $1.html [R=301]
Add this to the top of your rules (under the RewriteBase / directive):
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
That should stop it from looping. The rewrite engine will keep re-applying all the rules until the URI going in (sans query string) is the same as the URI that comes out of the rules. That's why the value of url is profile.php.
I'm kind of a beginner in interpreting mod_rewrite rules but if I understand it correctly your rule is matched and than matched again, either add something to the url matching scheme like /profile/user or add a condition to not redirect if already redirected
Try adding a leading slash to the redirect like this:
RewriteRule ^([a-zA-Z0-9.-]+)$ /profile.php?url=$1 [L]
The reason you're getting a url value of profile.php is because the [L] flag is kinda misleading when it comes to the .htaccess file. In the server config files it does exactly what you'd think, but in the .htaccess file it stops reading rules at that rule, but then goes through the rules again until path is unchanged by any of the rules. By adding the leading /, your rule will not match the second time around as you exclude / from the regex. I spent a while struggling with this feature myself.

.htaccess mod_rewrite 301 redirect with a pattern

I've changed my URL structure to remove the category from the URLs of item pages.
I need some way of redirecting all the old pages to the new pages, using mod_rewrite. I have already a quite elaborate and messy .htaccess file.
What I'd need is to redirect:
http://example.com/category-name/item-name/ to this http://example.com/download-item-name/
Right now, I've got this in the htaccess file.
RewriteEngine on
RewriteBase /
RewriteCond %{HTTP_HOST} !^example.com$ [NC]
RewriteRule ^(.*)$ http://example.com/$1 [R=301]
RewriteRule ^download-([^/]*)/screenshots/$ /screenshots.php?screenshots=$1 [L]
RewriteRule ^download-([^/]*)/screenshots/([^/]*)/$ /screenshots.php?screenshots=$1&shot=$2
#and now without trailing slash, so request will hit script which can do redirect.
RewriteRule ^download-([^/]*)/screenshots/([^/]*)$ /screenshots.php?screenshots=$1&shot=$2 [L]
RewriteRule ^feed/([^/]*)/$ /feed/?category=$1 [L]
RewriteRule ^download-([^/]*)-software/$ /category.php?category=$1 [L]
#this needs to stay above the below rule
RewriteRule ^download-([^/]*)/$ /software.php?shortname=$1 [QSA]
RewriteRule ^download-([^/]*)/([^/]*)/$ /software.php?shortname=$1&lang=$2 [QSA]
#and now without trailing slash, so request will hit script which can do redirect.
RewriteRule ^download-([^/]*)$ /software.php?shortname=$1 [QSA]
RewriteRule ^download-([^/]*)/([^/]*)$ /software.php?shortname=$1&lang=$2
RewriteRule ^downloading/([^/]*)/$ /download.php?downloading=$1
RewriteRule ^downloading/([^/]*)/([^/]*)/$ /download.php?downloading=$1&lang=$2 [L]
RewriteRule ^download/([^/]*)/([^/]*)/$ /send.php?key=$1&s=$2 [QSA]
RewriteRule ^FQ-([^/]*)/$ /content.php?page=$1 [L]
RewriteCond %{REQUEST_URI} ^(/[^/]+)(/.*)?$
RewriteCond %{DOCUMENT_ROOT}/categories%1/ -d
RewriteRule . /categories%{REQUEST_URI} [QSA]
Options -Indexes
FileETag None
ErrorDocument 404 http://example.com/404/
ErrorDocument 403 http://example.com/
#Some redirects
Redirect 301 /audio-video-players-codecs/zoom-player-max/ http://example.com/download-zoom-player-max/
Redirect 301 /audio-video-players-codecs/zoom-player-premium/ http://example.com/download-zoom-player-premium/
Redirect 301 /audio-video-players-codecs/zoom-player-pro/ http://example.com/download-zoom-player-pro/
Your .htaccess is messy because of simple things:
Rule #1: avoid mixing Redirect and RewriteRules directives. This will only confuse things. There's always a possibility to replace Redirect by RewriteRules directives.
Rule #2: if you don't need RewriteBase / (which is often the case, because the base is often /), don't write it. This will only confuse things. The shorter the better (that's what she tells me (just kiddin')).
Rule #3:: ^(.*)$ is the same as (.*). Here too, this makes things clearer.
Rule #4:: special rule for you: you can reduce by 2 almost all your RewriteRules using a thing like ^downloading/([^/]*)(/([^/]*))?/ which makes the second argument empty but match both one or two arguments (just valid in your Php that you can get an empty second argument). The shorter the better.
Then to answer your question: to redirect: http://example.com/category-name/item-name/ to this http://example.com/download-item-name/
RewriteRule ^category-([a-zA-Z]+)/item-([a-zA-Z]+)/ ^download-item-$2/ [QSA,R]
This should work
My favorite tool to check for regexp:
http://www.quanetic.com/Regex (don't forget to choose ereg(POSIX) instead of preg(PCRE)!)

Trying to add trailing slash with htaccess, results in a absolute path

What I'm trying to achive is to have all urls on my page look like http://domain.com/page/, no extensions, but a trailing slash. If a user happends to write http://domain.com/page or http://domain.com/page.php it will redirect to the first url. After some googling i found this code, and it's close to working, but when you leave out the trailing slash in your request the url becomes something like http://domain.com/Users/"..."/page/ and therefor returns a 404.
My .htaccess looks like this:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} ^GET\ /[^?\s]+\.php
RewriteRule (.*)\.php$ /$1/ [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_FILENAME} !(.*)/$
RewriteRule (.*)/$ $1.php [L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule .*[^/]$ $0/ [L,R=301]
I've been trying to add an additional rule but I really don't get any of this and I haven't been able to find any answers.
For a scenario like this one, the .htaccess author has to consider both what the browser URL bar should display and what file the web server should return/execute. Note also that each external redirect starts the processing of the rewrite directives over.
With that in mind, start by taking care of which file is returned when the URL is in the correct format:
RewriteEngine on
RewriteRule ^/?$ /index.php [L]
RewriteRule ([^./]+)/$ /$1.php [L]
Then, deal with URLs with no trailing slash by redirecting them with [R=301]:
RewriteRule ^/(.*)\.[^.]*$ http://www.example.com/$1/ [R=301,L]
RewriteRule ^/(.*)$ http://www.example.com/$1/ [R=301,L]
Note that the first of these two rules should also take care of the case where there is a filename (like something.php) but also a trailing slash by eliminating the filename extension and re-adding the slash.
Keep in mind that, if your internal directory structure does not match what the web server is serving (as is often the case in shared hosting scenarios), you will likely need to add a RewriteBase directive immediately after the RewriteEngine directive. See the Apache docs for an explanation.

Resources