.htaccess rewrite seems to fail on longer strings - apache

Options +FollowSymLinks
RewriteEngine on
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [L,R=301]
RewriteRule files/name/(.*).(pdf)$/ download.php?file=$1.$2&tkn=token
RewriteRule files/name/(.*).(pdf)$ download.php?file=$1.$2&tkn=token
RewriteRule files/name2/(.*).(pdf)$/ download2.php?file=$1.$2&tkn=token
RewriteRule files/name2/(.*).(pdf)$ download2.php?file=$1.$2&tkn=token
The folders name and name2 contain identical files. download.php and download2.php are identical.
The files/name/(.*) rewrite rule will redirect nearly all files to download.php, but fails on, what seems to be long file names. Two files I know it has failed on are:
abcdefghijklmn-abcdefghij.pdf
Pbcdefg ab abc Abdefghij 2.PDF
The files/name2/(.*) rule catches all files, including the two that are failing in the first rule. Literally, if I go to http://www.domain.com/files/names/abcdefghijklmn-abcdefghij.pdf, the server will serve me the file directly. If I go to http://www.domain.com/files/names2/abcdefghijklmn-abcdefghij.pdf, (just add 2 to names), the server will redirect me to http://www.domain.com/download2.php?file=abcdefghijklmn-abcdefghij.pdf&tkn=token
I've been trying to get this to work for hours, and I have no idea why the first rule won't work. Is there some weird idiosyncrasy I'm missing?

Try it this way and see how it works for you.
RewriteCond %{HTTP_HOST} ^domain.com [NC]
RewriteRule ^(.*)$ http://www.domain.com/$1 [L,R=301]
RewriteRule files/name2/(.*)\.pdf$ /download2.php?file=$1.pdf&tkn=token [R,L]
RewriteRule files/name/(.*)\.pdf$ /download.php?file=$1.pdf&tkn=token [R,L]

Related

How do I combine these two .htaccess rules?

I want to combine these two rules, but not sure how
RewriteRule ^([^\.]+)$ $1.html [L]
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
when I put both, I get the error "too many redirects"
My goal here is to combine them both,
the first rule is to remove file extensions (ex. html)
the second rule is: make every URL go to https://www.example.com, rather than https://example.com
With the additional information you now gave I would suggest this approach:
RewriteEngine on
RewriteCond %{HTTP_HOST} !^www\.example\.com$
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,END]
RewriteRule ^/?(.+)\.html$ /$1 [R=301,END]
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^ %{REQUEST_URI}.html [END]
In general it is a good diea to start using a R=302 temporary redirection and only change that to a R=301 permanent redirection once everything works as expected. That prevents nasty caching issues ...

htaccess from https to http

I have these vales in my htacces file it all works fine except when i try to go back to http from https i have tried swapping the rules around with no success, any help would be awsome
I have tried all the sujestion with still no suucess so maybe i need to show you guys the entire thing.
Still not going back to http from https, here is the whole thing
Have i got the rules in the wrong order? im lost
<ifModule mod_rewrite.c>
RewriteEngine on
# For Sales:
RewriteRule ^shop/sales/?$ sales.php
# For the primary categories:
RewriteRule ^shop/([A-Z-Aa-z\+]+)/?$ shop.php?type=$1
# For specific products:
RewriteRule ^browse/([A-Za-z\+]+)/([A-Za-z\+\-]+)/([0-9]+)$ browse.php?type=$1&category=$2&id=$3
#For https pages:
#RewriteCond %{HTTPS} on
#RewriteRule ^(.*)$ http://%{HTTP_HOST}%{REQUEST_URI} [R=301,L=301]
#RewriteCond %{HTTPS} off
#RewriteRule ^(checkout\.php|final\.php|admin/(.*))$ https://{HTTP_HOST}/$1[R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s(.*)/index\.php [NC]
RewriteRule ^ /%1 [R=301,L]
</ifModule>
I am not able to test the rules, but I think you need to change the following:
In the first rule your flag is attached to the 2nd argument. This should create an internal error. Your second rule would rewrite all url's to their http equivalent, making an infinite loop. You need to make sure it doesn't match url's that you want to be in https. You can do this with %{REQUEST_URI} and a negation (!). As far as I am aware, L=301 is an invalid flag too. You probably meant to make it R=301.
RewriteCond %{HTTPS} off
RewriteRule ^(checkout\.php|final\.php|admin/(.*))$ https://{HTTP_HOST}/$1 [R,L]
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !/(checkout\.php|final\.php|admin/(.*))$
RewriteRule ^http://%{HTTP_HOST}%{REQUEST_URI} [R,L]
Last but not least an word of advice. Don't test your .htaccess with permanent redirects until everything works as expected. The browser will cache permanent redirects, not picking up further tries to make your .htaccess work as you want.

Url renaming using .htaccess file

Most are for redirections and removing file extensions or for dynamic urls.
The problem being I can't get a simple static url to rename
Options +FollowSymlinks
RewriteEngine On
RewriteRule ^fileThathasalongname file.html
What I currently have 'mysite.co.uk/fileThathasalongname.html'
What I want is 'mysite.co.uk/file/' while file = file.html
using:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteRule ^FileIWantToChange.html FriendlyNamed.html
Using this gives me the error multiple Choices
+++++++++++++++++Edit+++++++++++++++++++++++++
Thought i'd add my final version for people to look at, it may help, the anwser below is correct.
Options +FollowSymLinks -MultiViews
DirectorySlash Off
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME}/ -d
RewriteCond %{SCRIPT_FILENAME}.html !-f
RewriteRule [^/]$ %{REQUEST_URI}/ [R=301,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+)\.html$ /$1 [R=301,L]
RewriteRule ^FriendlyNamed.html FileIWantToChange.html [L]
RewriteCond %{SCRIPT_FILENAME}.html -f
RewriteRule [^/]$ %{REQUEST_URI}.html [QSA,L]
RewriteCond %{HTTP_HOST} ^www.mysire.co.uk [NC]
RewriteRule ^(.*)$ http://mysite.co.uk/$1 [L,R=301]
all works a charm!
I see multiple issues going on. Firstly the regular expression is matched against the friendly URL the user types in. So you need to swap your friendly url and file path with each other. The friendly or "fake" name goes on the left while the url to redirect to silently goes on the right. Also make sure you've set the directory base to /. Finally it's good to add an [L] to enforce it to be the last rule in case anything in the same file tries to rewrite the path. Due note that other htaccess files lower down, depending on the files location, will also be checked even when enforcing the rule has the last rule. Also junk the options part completely. Give this a try:
RewriteBase /
RewriteEngine On
RewriteRule ^FriendlyNamed.html FileIWantToChange.html [L]
RewriteRule ^fileThathasalongname.html file.html

How to avoid chain redirections using mod_rewrite?

Basicly i'm working on my site to be SEO-friendly. I wanted to achieve following:
Rewrite urls to pretty ones
Remove multiple slashes (eg. example.com/////something/// to example.com/something/
Redirect www version to a non-www version.
Hide index.php file from all urls
Redirect from old (/?id=something/ to new urls /something/)
I came up with this .htaccess code:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
RewriteRule ^index.php(.*)$ /$1 [R=301]
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
...and though it's working it has a side effect: chain redirects, eg. example.com/?id=something////// -> example.com/something////// -> example.com/something/
So is there a way to rewrite or modify this code so it'll be redirecting just once to the preferred version of the url?
Trying to interpret what you want, let's look at the rules in your question:
.1 Can't understand the purpose of this:
RewriteCond %{THE_REQUEST} //
RewriteRule .* $0 [R=301]
.2 This rule-set in your question removes www and converts the query string ?id=val to /val, but only when the incoming URI has www AND there is a query string as both conditions must be met:
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [NC]
RewriteCond %{QUERY_STRING} ^id=([a-z0-9\/-]+)
RewriteRule ^(.*)$ http://example.com/%1? [R=301]
.3 This rule
RewriteRule ^index.php(.*)$ /$1 [R=301]
Hides index.php, but only when it is in the root directory. Example:
http://www.example.com/index.php?id=val
Does not work when it is in a subdirectory. Example:
http://www.example.com/folder/index.php?id=val
.4 Can't understand the purpose of this:
RewriteRule ^([a-z0-9\/-]+)$ /?id=$1 [L]
I suggest this instead:
RewriteEngine On
RewriteBase /
#Redirects all www to non-www
RewriteCond %{HTTP_HOST} www\.example\.com$ [NC]
RewriteRule ^(.*)/?$ http://example.com/$1 [R=301,L]
#Hides "index.php" keeping the query if present
RewriteRule ^(.*)/index\.php$ $1/ [R=301,QSA,L]
#Converts query string `?id=val` to `/val`
RewriteCond %{QUERY_STRING} id=([^/]+)
RewriteRule .* /%1? [R=301,L]
Remember spiders will "adapt" to the correct new structure after a few months, and the problem may ultimately be a whole lot less severe than what it looks like initially. You can leave all the .htaccess code in place, knowing it always be there to correct any "old" references yet will in fact hardly ever actually be used.
I've never found an easy way to avoid multiple round trips back to the client when "fixing up" a URL to be in some sort of canonical form. mod_rewrite seems to be more focussed on the "local" redirect case where the client has no idea that the content it got back came out of a file structure that doesn't perfectly match that implied by the URL.
It is possible to save up all the URL mods locally, then provoke only one round trip to the client that delivers all the URL corrections all at once by setting everything in newly created "environment" variables then at the end asking basically "has anything changed?" However doing so is notably verbose and rather awkward and quite error-prone and has never become a "recommended technique".

htaccess for redirect to SSL

For the past few hours (days) I have been having some trouble redirecting a
page to SSL.
My setup is as follows: I have the following .htaccess for an e-commerce site
on Apache 2.2.16 on Debian (all required mods enabled)
RewriteEngine On
RewriteBase /shop
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
all requests are passed to index.php which acts as my controller and includes
other .php files as necessary.
I now want to use HTTPS for the checkout process which is a php script
cleverly called checkout.php
I thought it would be as easy as changing my .htaccess to:
RewriteEngine On
RewriteBase /shop
RewriteCond %{SERVER_PORT} !^443$
RewriteCond %{SERVER_URI} checkout\.php
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
RewriteCond $1 !^(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ index.php?/$1 [L]
so that checkout.php is not processed by index.php.
Apparently it is not that simple. I could probably do it by using a hardcoded
https link to checkout but I would prefer to do it with mod_rewrite.
If anyone can share some insight into
this it would be really appreciated.
Thanks in advance
There are a few problems. First, the pattern in your first RewriteRule
RewriteRule ^checkout.php?/$1 https://localhost/shop/checkout.php?/$1 [L,R]
is written incorrectly. $1 isn't meaningful there (it's a capture result, but no capture has happened yet), and also the query string (part of the request after the ?) isn't part of what's matched, as the RewriteRule documentation says.
Second, I think you meant to use REQUEST_URI instead of SERVER_URI.
So I think you want something like this:
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/checkout\.php
RewriteRule .* https://localhost/shop/checkout.php [L,R]
RewriteCond %{REQUEST_URI} !^/(index\.php|products|img|theme\.php|checkout\.php)
RewriteRule ^(.*)$ /index.php?/$1 [L]
A few notes:
You don't need to match or add back in the query string in the first RewriteRule; mod_rewrite will automatically add it back in.
It's conventional to test RewriteCond %{HTTPS} off instead of
RewriteCond %{SERVER_PORT} !443, as #Jon Lin suggests.
You may want to add the QSA flag in your second RewriteRule.