htaccess - Rewriterule redirects to wrong URL - regex

I have a simple rewrite:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?p=$1 [QSA]
Anything that is not an existing file should be forwarded to index.php. However, there's a directory, images, there are sevenal images in it, but no index.php|html. When I open localhost/images, without a closeing slash (localhost/images/ works fine), it redirects me to localhost/images/?p=images. How should I solve that?

That is happening because of the mod_dir module that runs after mod_rewrite adding a trailing slash to directories. You should add a condition to avoid rewriting directories in your rule. Also add a trailing slash using a redirect rule:
RewriteEngine on
# add a trailing slash to directories
RewriteCond %{DOCUMENT_ROOT}/$1 -d
RewriteRule ^(.*?[^/])$ %{REQUEST_URI}/ [L,R=302]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?p=$1 [QSA,L]

Related

How to do this complicated thing with mod_rewrite?

I'm hopeless when it comes to regex and/or the RewriteEngine, so my hours of researching and trying things have been pretty fruitless so far.
I'm trying to use the RewriteEngine to accomplish behavior that will follow these rules:
If the requested URL...
...points to an existing file e.g. domain.com/existing_file.ext
do no rewrites
...is empty, or contains only trailing slash(es) e.g. domain.com/
rewrite to index.php?var=example
...points to an existing directory that is not root (with or without trailing slashes) e.g. domain.com/existing_directory
rewrite to index.php?var=REQUESTED_DIRECTORY_PATH/example where REQUESTED_DIRECTORY_PATH is everything after domain.com (preferably always without a trailing slash)
...is not empty, but doesn't point to an existing file or directory e.g. domain.com/no_such_file_or_directory
rewrite to index.php?var=REQUESTED_URL, where REQUESTED_URL is everything after domain.com
This is what I've got so far:
# /
RewriteRule ^$ index.php?var=example [QSA,L]
# /directory_name/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+[^/])$ /index.php?var=$0/example [QSA,L]
# /not_a_valid_file_or_dir/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?var=$0 [QSA,L]
Which to me seems to almost do what I want, except for when I try to access domain.com/existing_directory (with or without a trailing slash). In this case I get redirected to domain.com/existing_directory/ (with a slash), while I would like to be end up at domain.com/index.php?var=existing_directory/example.
Thanks to helpful comments from Bananaapple, and a bit of Googling, I managed to accomplish what I wanted.
Firstly, I had to turn DirectorySlash off, and secondly I needed to remove the [^/] from the regex. So the final relevant code would look something like this:
DirectorySlash Off
# /
RewriteRule ^$ index.php?var=example [QSA,L]
# /directory_name/
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.+)$ /index.php?var=$0/example [QSA,L]
# /not_a_valid_file_or_dir/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?var=$0 [QSA,L]
Thanks for the help.

HTACCESS Rewrite: Ignore another rewrite rule

I am using rewrite rules for two purposes. First, I am able to rewrite the URL's to my .css and .js files so they can be processed through a minimize script. This has been working fine:
RewriteEngine on
RewriteRule ^assets/css/min/([a-zA-Z0-9\._-]+)/([a-zA-Z0-9\._-]+)/([a-zA-Z0-9\._-]+)\.css$ assets/css/min.php?style=$1&theme=$2&ver=$3 [L,QSA]
RewriteRule ^assets/js/min/([a-zA-Z0-9\._-]+)/([a-zA-Z0-9\._-]+)\.js$ assets/js/min.php?scripts=$1&ver=$2 [L,QSA]
However, now I added a rule to redirect all traffic for nonexistent pages to my index.php file (for MVC routing):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php/$1 [L]
RewriteBase /
The problem is, now that I have both of these rules in my HTACCESS file, I am no longer able to access my .css or .js files like:
http://domain.tld/assets/css/min/all/default/0.2.3.css
How can I get the rerouting to index.php to ignore the previous rule with my css and js rewriting?
You can use a negative lookahead in last rule to skip assets/ directory:
RewriteEngine on
RewriteRule ^assets/css/min/([\w.-]+)/([\w.-]+)/([\w.-]+)\.css$ assets/css/min.php?style=$1&theme=$2&ver=$3 [L,QSA]
RewriteRule ^assets/js/min/([\w.-]+)/([\w.-]+)\.js$ assets/js/min.php?scripts=$1&ver=$2 [L,QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(?!assets/)(.+)$ index.php/$1 [L,NC]
Also note that you can replace [a-zA-Z0-9_] with shorter \w

Unexpected behavior with custom .htaccess rewrite rules

So I have been working on some rewrite rules which aren't working as expected. These are some sample requests I am trying to rewrite:
/ -> /index.php?page=Home
/Home -> /index.php?page=Home
/Teaching/Foo -> /index.php?page=Teaching&id=Foo
/Teaching/Bar -> /index.php?page=Teaching&id=Bar
/Download/ue8 -> /index.php?action=Download&id=ue8
/Download/24a -> /index.php?action=Download&id=24a
(default) -> /index.php?page=Home
** OR ALTERNATIVELY **
(default) -> /index.php?page=FileNotFound
(and maybe rewrite the visible URL to /FileNotFound)
I mainly want to hide as much of the urls as possible and prevent both directory listing and direct access to my files located in specific folders and only allow access to downloadable files via /Download/FileId while having my usual pages for different lectures accesible via /Teaching/SomeLecture.
So far I have been using this snippet for the /Home and /Teaching stuff:
RewriteEngine On
RewriteBase /
# Redirect Trailing Slashes
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^Teaching/([A-Za-z0-9]*)$ index.php?page=Teaching&id=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^Home$ index.php?page=Home [L]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s(.*)/index\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php [L,R=301]
I am not completely sure about all of these directives and I noticed, that there are currently some flaws to it.
Trying to access a non-existant file, e.g. /Files/Bad/Path.pdf, forwards the user to /?page=Home which should be redirected either to /, /Home or display the contents of /index.php?page=FileNotFound without changing the URL at all or redirecting to /FileNotFound depending on the rule of (default). I am not really sure which solution might be the most suitable in this scenario.
Trying to access some folders which do exist results in an infinite redirection loop while folders which do not exist apparently redirect to /. In both cases it feels right to redirect to /FileNotFound I suppose?
Could you please work out a set of rules that might suit my needs in this case?
You have many redundant directives in your .htaccess. Replace all of your .htaccess with this:
# Turn off mod_spelling
<IfModule mod_speling.c>
CheckSpelling off
CheckCaseOnly off
</IfModule>
Options -MultiViews
RewriteEngine On
RewriteBase /
# block direct access to file and directories in these directories
RewriteCond %{REQUEST_URI} !\.(?:jpe?g|gif|bmp|png|tiff|css|js)$ [NC]
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^(Templates|Files) - [NC,F]
# remove index.php
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteRule ^(.*?)index\.php$ /$1 [L,R=301,NC,NE]
# Redirect Trailing Slashes
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
# Handle Front Controller
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(Download|Teaching)/([\w-]+)/?$ index.php?page=$1&id=$2 [L,QSA,NC]
RewriteRule ^(Home)?/?$ index.php?page=Home [L,NC,QSA]
Make sure to clear your browser cache before testing this.

.htaccess force server to add a trailing slash, except for links with extensions

I had an error in the past "404 Not Found" when writing www.website.com/page instead of www.website.com/page/
And I corrected it by adding the following code to the .htaccess file:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^(.*)$ %{REQUEST_URI}/ [L,R=301]
</IfModule>
But now, it didn't render an xml page, because a trailing slash was added to the link
Example: www.website.com/post-sitemap.xml/
I want to prevent any errors in the future by simply adding a command on the .htaccess so it doesn't add the slash to links ending with: .html .php .xml .css ... etc
Thank you
You can use this rule:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !\.[^.]+$
RewriteRule [^/]$ %{REQUEST_URI}/ [L,R=301]

Htaccess - replace .html with a forward slash

I want to redirect URLs of this form:
/page.html?variable=value&othervar=true&thirdvar=100
To this:
/page/?variable=value&othervar=true&thirdvar=100
So basically I just want to replace the .html in the middle of the URL with a forward slash, but I need to preserve the get string that comes with it. This is what I tried:
RewriteRule ^page.html(.+)$ /page/$1 [L,R=301]
But this doesn't appear to be working for me. I've made similar things work recently but I can't figure out what I'm missing here. Thanks for any input.
Enable mod_rewrite and .htaccess through httpd.conf and then put this code in your .htaccess under DOCUMENT_ROOT directory:
Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# external redirect from /example.html to /example
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s/+([^.]+)\.html [NC]
RewriteRule ^ /%1/ [R=301,L]
# internal forward from /example/ to //example.html
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule ^(.+?)/?$ /$1.html [L]