How to redirect all urls with .php? to only .php ?
I´m using
RewriteEngine On
RewriteRule ^(.+\.php)/.*$ http://%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/?secure/(.*) https://example.org$1 [R,L]
How can i prevent somone using urls that doesn´t exist on my server?
It´s all about blocking everything that comes after .php like ?123456789
Why should it be an issue if someone adds a query string to a URL? Unless your php scripts react to that, of course, but that is something you can control, can't you?
Nevertheless it certainly is possible to drop such query strings if you want to:
RewriteEngine on
RewriteCond %{QUERY_STRING} !^$
RewriteRule \.php$ %{REQUEST_URI} [QSD,R=301,L]
For this to work the apache rewrite module needs to be loaded into the http server, obviously.
It is a good diea to start with a R=302 temporary redirection first. And to only change that to a R=301 permanent redirection once everything works as desired. That prevents nasty caching issues for your users.
You should prefer to implement such rules in the actual http server's host configuration. If you have no access to that you can also use a distributed configuration file (".htaccess"), but that comes with a few disadvantages. And has to be enabled first.
This might sound like a stupid question to some, but I've only just noticed it while trying to implement an SSL certificate to my site.
There's a default value in the 'out of the box' .htaccess file:
# Rewrite "www.example.com -> example.com"
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
Am I right in thinking this code forces the removal of the www. part of the canonical links on my website?
If so - is this really best practice? Is that why the base_url example in the Config/App.php is http://example.com?
Secondly, as I mentioned, I'm trying to add this code to the .htaccess file to implement the SSL certificate and force https for every URL - but it's causing an error if I use www. (whereas it didn't cause an error before) and my speed tests are indicating redirects galore which is slowing everything down:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Is anyone able to point me in the right direction with the correct canonical link structure for the base_url in the Config/App.php file, whether I need to alter (or scrap) the first snippet of code, and how I can force https to work with my SSL certificate (and www. in my URLs).
I would much rather my URLs had the structure of https://www.example.com as opposed to https://example.com
Am I right in thinking this code forces the removal of the www.
Yes, but only for HTTP (not HTTPS) requests, as governed by the first condition %{HTTPS} !=on.
If you are implementing HTTPS then you should remove the first condition and change the RewriteRule substitution string to redirect to https://.... But if you are wanting to redirect to www then you'll need to reverse the logic also:
# Redirect "example.com -> www.example.com"
# (In fact, redirect hostname that does not start "www.")
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
Although, this particular method (as I've implied in the comment) will not necessarily work if you have other subdomains, unless you want all subdomains to have www sub-subdomains?!
Note that this is an external "redirect", not an internal "rewrite" as you'd stated in the comment.
If so - is this really best practice?
In terms of SEO or from a technical perspective? In terms of SEO there is no difference. Using a www subdomain can arguably have some technical benefits (isolating cookies and staging sites, etc.) - although this is mostly a matter of opinion and depends on your environment. It is really up to you. For some domain names, using a www subdomain just looks cumbersome.
But what is important is that you choose one or the other and redirect to the canonical URL in order to avoid potential duplicate content issues.
Using the domain apex (ie. no www subdomain) is simply CodeIgniters default.
force https for every URL - but it's causing an error if I use www.
To clarify, the SSL cert you implement must include both the domain apex, ie. exmaple.com and the www subdomain, ie. www.example.com. Otherwise, you will naturally get browser security warnings when requesting the "other" (non-SSL) hostname.
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
This code is generally OK to force HTTP to HTTPS (providing the SSL cert is installed on your application server, ie. you're not using a front-end SSL proxy or non-standard implementation). However, the order you put this rule in relation to the rule above will depend on whether you intend to implement HSTS or not.
If you are intending to implement HSTS then you will need to redirect to HTTPS on the same host first, before the redirect to www. This will result in an unavoidable double redirect when requesting the non-canonical http://example.com/ (but that is not "bad").
For example:
# 1. Redirect to HTTPS on the same host
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# 2. Redirect to non-www to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
If, however, you are not intending to implement HSTS then you can reverse the two rules above and get at most one redirect for any non-canonical URL request.
You need to update the CodeIgniter base_url to match your preference of www or not.
I have a client with an old website without 'pretty' URLs. So currently it looks like this:
http://www.domain.com/?w=42&a=5&b=3
The parameter values are numbers only.
Now they want to move the old site to a subdomain and main (www) domain would be home to a new website (WP with SEO friendly URLs).
Now what I would like to do is redirect all requests that come to the /?w=<num> (and ONLY those) to sub.domain.com/?w=<num>, so that existing links (mostly from Google) get redirected to the subdomain page, while the new page works serving new content thorough pretty URLs.
I tried this:
# This works, but redirects the entire www.domain.com
# to sub.domain.com no mather what
RewriteCond %{HTTP_HOST} ^www\.domain\.com$ [NC]
RewriteRule ^(.*)$ http://sub.domain.com/$1 [R=301,L]
# But this DOESN'T work
RewriteRule ^/?w(.*) http://sub.domain.com/?w$1 [R=301,L]
# Also tried to redirect 'by hand', but DIDN'T work either
Redirect 301 /?w=42 http://sub.domain.com/?w=42
What am I doing wrong? I searched high and low but always end up with this kind of suggestions. Or maybe I'm just searching for wrong keywords ...
Thank you!
You can't match against the query string inside a rewrite rule or a redirect directive. You need to match against the %{QUERY_STRING} variable. Try:
RewriteCond %{QUERY_STRING} (^|&)w=[0-9]+(&|$)
RewriteRule ^(.*)$ http://sub.domain.com/$1 [L,R=301]
Note that the query string gets automatically appended to the end of the rule's destination.
Just for documentation: If you want to redirect one directory (path) only if there is a URL parameter present, from one path to another, while maintaining the URL parameter, you can use this in your htaccess file:
# /programs/?id=1 to new path /loadprog/?id=1
RewriteCond %{REQUEST_URI} ^/programs/
RewriteCond %{QUERY_STRING} id=
RewriteRule ^programs\/$ /loadprog/$1 [R=301,L]
I am sure this will help others since I stumbled over the question above trying to find this answer.
Hi I'm struggling to achieve two things with .htaccess, presumably the same issue on each.
I am successfully setting a cookie called site-version to au or us.
If the cookie is set, I want http://www.example.com and http://www.example.com/ to redirect (internally) to http://www.example.com/home-au.html (if the cookie site-version=au). I also want to set an environment variable SITE_VERSION=au.
RewriteCond %{HTTP_COOKIE} site-version=(au|us) [NC]
RewriteRule ^/?$ /home-%1.html [NC,QSA,E=SITE_VERSION:%1]
The problem appears to be the regex on the RewriteRule. If I set this to .*, once it gives up looping it appears to set the environment variable successfully, although still not rewrite the request.
If the URL is http://www.example.com/a-specific-page.html or http://www.example.com/another-specific-page.html and the cookie is set, I want to redirect to http://www.example.com/a-specific-page-au.html or http://www.example.com/another-specific-page-au.html , ie, append the -au to the filename. (And set the environment variable.)
RewriteCond %{THE_REQUEST} ^(a-specific-page|another-specific-page)\.html$ [NC]
RewriteCond %{HTTP_COOKIE} site-version=au [NC]
RewriteRule ^(.*)\.html$ /$1-au.html [QSA,E=SITE_VERSION:au]
Later in htaccess I translate these URLs again so I don't want the L flag, however I also tried:
RewriteRule ^(.*)\.html$ index.php?q=$1-au.html [QSA,E=SITE_VERSION:au,L]
I have tried many minor variations on these themes, none trigger the rewrite.
EDIT: I've spotted a fundamental gap in my understanding. URL rewrites trigger another loop through .htaccess, so I need to present the whole file rather than fragments, which explains why the solution works but I'm still not getting environment variables.
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
########## Set the cookie if the user selects a new country #############
# The webpage submits the existing URL plus the site-version URL parameter. #
# The below strips the parameter and returns to the same URL with a cookie site-version. #
# Unless the site-version is uk (default) in which case the cookie is deleted. #
RewriteCond %{QUERY_STRING} ^.*site-version=(au|us|za|eu)$
RewriteRule (.*) $1? [co=site-version:%1:example.com:1051200:/,R,E=SITE_VERSION:%1,L]
RewriteCond %{QUERY_STRING} ^.*site-version=uk$
RewriteRule (.*) $1? [co=site-version:uk:example.com:-1:/,R,E=SITE_VERSION:uk,L]
#####################
# If the cookie is present and the URL is either a-page.html or another-page.html append -au eg, a-page-au.html #
RewriteCond %{HTTP_COOKIE} site-version=au [NC]
RewriteRule ^(a-page|another-page)\.html$ index.php?q=$1-au.html [NC,QSA,E=SITE_VERSION:au,L]
##########################
# Normal Friendly URLs rewrite, ie, cookie not detected or it isn't one of the listed URLs #
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
As in my comment, I've tested the first rules set without RewriteCond,
RewriteRule ^/?$ /home-%1.html [NC,QSA,E=SITE_VERSION:%1]
I obtained this:
http://www.example.com/ => http://www.example.com/home-.html
The second ruleset has an visible error: %{THE_REQUEST} ^(a-specific-page|another-specific-page).html$ [NC]
you can try use %{REQUEST_URI} instead of %{THE_REQUEST}. %{THE_REQUEST} involves the words GET or POST, etc.
So you might try this:
RewriteCond %{HTTP_COOKIE} site-version=(au|us) [NC]
RewriteRule ^/?$ /home-%1.html [NC,QSA,E=SITE_VERSION:%1]
RewriteCond %{HTTP_COOKIE} site-version=au [NC]
RewriteRule ^(a-specific-page|another-specific-page)\.html$ /$1-au.html [NC,QSA,E=SITE_VERSION:au]
Or set a visible Redirect by adding R flag as follows:
RewriteCond %{HTTP_COOKIE} site-version=(au|us) [NC]
RewriteRule ^/?$ /home-%1.html [R,QSA,E=SITE_VERSION:%1]
RewriteCond %{HTTP_COOKIE} site-version=au [NC]
RewriteRule ^(a-specific-page|another-specific-page)\.html$ /$1-au.html [R,NC,QSA,E=SITE_VERSION:au]
The full solution. This does the following:
Detects the URL parameter ?site-version, and if found, sets a cookie on the client called site-version, storing the country code (au, eu, za, etc), to last 2 years (1051200 minutes). It then removes the parameter from the URL and gets the user's browser to request the original URL again.
Except, if site-version=uk, this is the default setting for the website, so the cookie is deleted (see the -1 in the co flag).
Specific pages have local versions written of them. They are accessed by adding the country code to the URL. So the Australian version of costs.html is costs-au.html.
If the cookie is detected, which might be on a repeat visit, or it might be due to the redirect in step 1 above, the URL is examined. If the URL is one of the pages that has a local version, the country code is added to the URL. The URL is then passed to index.php - the common way to have pleasant-looking, search engine-friendly URLs. The rewriting of the URL triggers another iteration through .htaccess. (Nb. As far as I'm aware, the E= flags on these rules don't achieve anything as when .htaccess is reiterated through the environment variable is lost. E= flags are effectively invalid if the URL is changed, as they achieve nothing.)
If the cookie is detected, the value is stored in an environment variable called HTTP_SITE_VERSION. (Environment variables should always be prefixed with HTTP_, because servers running suexec ignore variables that don't start with HTTP_. suexec is an Apache feature that allows scripts to be run by a user other than the user running the Apache process, so is probably common among shared hosts.)
My PHP serves the altered URL, ie, costs-au.html, unaware that it has been changed. (FYI the browser URL is costs.html as this was an internal redirect.)
For all pages, regardless of whether they are in the list and have translations, the environment variable is set. PHP detects this with $site_version = getenv('HTTP_SITE_VERSION') (which returns false for UK as the cookie and variable aren't set and getenv returns false for missing vars) and displays the appropriate nuggets such as phone number or address.
So, the final, working solution is this (fix details below):
RewriteCond %{HTTP_HOST} !^www\.example\.com [NC]
RewriteRule (.*) http://www.example.com/$1 [R=301,L]
########## Set the cookie if the user selects a new country #############
# The webpage submits the existing URL plus the site-version URL parameter. #
# The below strips the parameter and returns to the same URL with a cookie site-version. #
# Unless the site-version is uk (default) in which case the cookie is deleted. #
RewriteCond %{QUERY_STRING} ^.*site-version=(au|us|za|eu)$
RewriteRule (.*) $1? [co=site-version:%1:example.com:1051200:/,R,E=HTTP_SITE_VERSION:%1,L]
RewriteCond %{QUERY_STRING} ^.*site-version=uk$
RewriteRule (.*) $1? [co=site-version:uk:example.com:-1:/,R,E=HTTP_SITE_VERSION:uk,L]
#############################
# Once the URLs have been rewritten, htaccess is iterated through again - re-iterating loses the environment variable to re-set it here
RewriteCond %{HTTP_COOKIE} site-version=(au|us|eu|za|uk) [NC]
RewriteRule .* - [NC,E=HTTP_SITE_VERSION:%1]
#####################
# If the cookie is present and the URL is either a-page.html or another-page.html append -au eg, a-page-au.html #
RewriteCond %{HTTP_COOKIE} site-version=au [NC]
RewriteRule ^(a-page|another-page)\.html$ index.php?q=$1-au.html [NC,QSA,E=HTTP_SITE_VERSION:au,L]
##########################
# Normal Friendly URLs rewrite, ie, cookie not detected or it isn't one of the listed URLs #
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
The fixes I needed: The two changes suggested by jacouh:
Put the string I want to match into the RewriteRule line instead of a RewriteCond. Silly oversight of mine.
Don't change the URL in two steps, go straight to index.php?q=.. rather than via the new URL, and add the L flag. If the URL is changed by any rule, the whole htaccess is re-iterated through. Doing everything in one step makes things much simpler.
But this was incomplete. When the URL was rewritten, a new iteration through .htaccess was triggered. This deletes all environment variables and prefixes headers with REDIRECT_.
So I also needed to add the setting of the environment variable in an iteration of .htaccess with no rewrites triggering. (When the htaccess file is iterated through again, which happens if any rule changes the URL, the environment variables disappear. Sorry to be verbose but this is confusing.) So I need an iteration of htaccess which does not change the URL in which to set the environment variable. Hence needing to add
RewriteCond %{HTTP_COOKIE} site-version=(au|us|eu|za|uk) [NC]
RewriteRule .* - [NC,E=HTTP_SITE_VERSION:%1]
This sets the environment variable on the iteration after the URL has been rewritten. Hey presto, worked on my server.
But when I rolled it out, even though the rewrites were happening, the variable disappeared again.
It turns out that on servers running suexec to protect PHP, environment variables need to be prefixed with HTTP_.
User clicks link (from their email): http://www.site.com/edit/wih293f73y
Browser window opens and gets them to the correct page.
But now the browser's address bar shows: http://www.site.com/editor.php?editCode=wih293f73y
Extra info:
My rewrite rule is:RewriteRule ^edit/([A-Za-z0-9-]+)/?$ editor.php?editCode=$1 [NC,L]
This problem ONLY occurs when the user has clicked a link. It works perfectly when you just type the pretty url into the address bar.
This problem ONLY occurs for links that include the www. - the link http://site.com/edit/wih293f73y works like a charm.
My .htaccess file includes the following code (from HTML5 boilerplate, which I wasn't aware of previously):
# Rewrite www.example.com → example.com
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
</IfModule>
If it's important, this occurs after my other rewrite rules.
I just took a look and it is apparent that your www rules is causing this. Question is do you want it be fixed? If you do then move this rule on top of all other rules and your problem should be fixed.
Move this to top of all other rules
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
You can use use the redirect directive
redirect 301 ^edit/([A-Za-z0-9-]+)/?$ editor.php?editCode=$1
There are some pros and cons to this strategy. The pros being;
It's super fast. You don't even need to load up your application for this to work.
It's minimal code.
Redirects are an intrinsic part of Apache (or any http server) and aren't going anywhere soon.
The cons being;
It's not part of your application proper. Should you decide to change logic or URLs, you'll have to change this, too.
It's slower, as you need to invoke php, as opposed to just having Apache issue the redirect.