.htaccess exclude subdirectory - .htaccess

I have the following opencart .htaccess:
Options +FollowSymlinks
Options -Indexes
<FilesMatch "\.(tpl|ini|log)">
Order deny,allow
Deny from all
</FilesMatch>
RewriteEngine On
RewriteRule ^sitemap.xml$ index.php?route=feed/google_sitemap [L]
RewriteRule ^googlebase.xml$ index.php?route=feed/google_base [L]
RewriteRule ^download/(.*) /index.php?route=error/not_found [L]
RewriteRule ^image-smp/(.*) index.php?route=product/smp_image&name=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !.*\.(ico|gif|jpg|jpeg|png|js|css)
RewriteRule ^([^?]*) index.php?_route_=$1 [L,QSA]
I'm currently replacing the old store which used to be in x-cart. I moved it to:
example.com/old/
What I'm trying to do is to have this old store still accessible when users go to:
example.com/old/ or example.com/old/admin/
(Reason being there's still some old customer orders needing to be processed. )
The main problem is that when I go to those urls, the root .htaccess overrides these and give the opencart 404 page.
Anyone know how to tamper with the htaccess to get both CMS working on the same domain?

Found the problem. This current setup will read html and php pages if they exist, otherwise the rules set in the root htaccess will take effect. The reason I wasn't able to get the files to work was because of permissions, which ended up costing me quite a bit of time tinkering.
For future people who land on this page, make sure you have your directory permissions set to 755 and file permissions set to 644.
For directories:
find /path/to/base/dir -type d -exec chmod 755 {} +
For Files:
find /path/to/base/dir -type f -exec chmod 644 {} +

Related

CakePHP [.htaccess], static files as the root of project

I would like to be able to access static files at the root of my project, in a folder at the same level of app/. It's because that is the only directory to wich I have the permission to read-write files on my server, so our images are uploaded there.
So if someone writes this URL:
www.mysite.com/img-rw
It displays images in the folder at [project-root]/my-rw-dir
Any ideas on how to edit .htaccess files for something like this to be done?
Thanks
Taking into account that this is a course project (as the OP said in comments) and you are NOT concerned about security flaws, here is what you could do.
By default CakePHP has 3 nested .htaccess files:
/.htaccess (Project root folder)
/app/.htaccess
/app/webroot/.htaccess
The first (topmost) of them is the first to respond when you try to access www.mysite.com:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ app/webroot/ [L]
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
Clearly, this sends the user request right into the /app/webroot folder. We could use the conditional check that exists in /app/webroot/.htacess to, instead of promptly redirecting to webroot, check if the given URL matches to a file or folder. In order to do so, you'll need to update the parent (/.htaccess) file:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d # Checks if the given URL matches to a folder
RewriteCond %{REQUEST_FILENAME} !-f # Checks if the given URL matches to a file
#RewriteRule ^$ app/webroot/ [L] # This line is commented, should be removed
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
This way, the request will only be redirected to /app/webroot if none of the conditions are met. If you need only to return files, than you could remove RewriteCond %{REQUEST_FILENAME} !-d, which verifies if the URL matches to a folder ( -d = directory).
A cleaner version that would only check for files should look like this:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) app/webroot/$1 [L]
</IfModule>
With this tweak, accessing www.mysite.com/image.jpg should return the file image.jpg hosted at your project root (/image.jpg).
For anyone wondering, this works great :
.htaccess (project root)
<IfModule mod_rewrite.c>
RewriteEngine on
# This folder is a subfolder of project root but contains static images
# Accessed like so: www.mysite.com/imgrw/[file name]
RewriteRule ^imgrw/(.*)$ /dir-at-root-level/img/$1 [L]
# Everything else is handled by cakephp webroot
RewriteCond %{REQUEST_URI} !(dir-at-root-level) [NC]
RewriteRule ^(.*) app/webroot/$1 [L]
</IfModule>

Root folder change (.htaccess)

In my "public_html" directory I have the following structure:
- root
- index.html
- blog
- index.html
- lab
- index.html
- wp
- (WORDPRESS FILES)
The "lab" and "wp" directories are just subdomain directories ("http://lab.tomblanchard.co.uk" and "http://wp.tomblanchard.co.uk") which work fine.
Basically I want the main domain ("http://tomblanchard.co.uk") to point to the "root" directory without any actual redirecting, for example, I want "http://tomblanchard.co.uk" to point to the "index.html" file within the "root" directory, I want "http://tomblanchard.co.uk/blog" to point to the "index.html" file within the "root/blog" directory and so on.
I have kind of achieved this with the following code in my ".htaccess" file:
# Add directives
RewriteEngine on
# Remove ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
# Change root directory to "root" folder
Options +FollowSymLinks
RewriteCond %{REQUEST_URI} !(.*)root
RewriteRule ^(.*)$ root/$1 [L]
The only problem is that things like "http://tomblanchard.co.uk/root/" and "http://tomblanchard.co.uk/root/blog/" still work when really they shouldn't even be able to be accessed (404).
If anyone has any idea on how to sort this or has a stronger method of doing this it would be greatly appreciated.
Update
Finally got it working how I wanted it after hours of researching, I used the following:
# Add directives
RewriteEngine on
# Change root directory to "root" folder
RewriteCond %{THE_REQUEST} ^GET\ /root/
RewriteRule ^root/(.*) /$1 [L,R=301]
RewriteRule !^root/ root%{REQUEST_URI} [L]
The order of directives in mod_rewrite is important, as each rule sees the output of the previous rule as its input to test. You need to do 3 (or possibly 4) things, in order:
Deny access to any URL beginning /root/ (we have to do this first, else everything will be denied!)
It's generally good practice to ensure each URL has only one valid form, so URLs which do specify .html should cause a browser redirect to the non-.html form. This needs to happen before other rewrites, otherwise you can't tell the difference between a .html from the browser and one you've added virtually.
Look up any URL not denied above in the /root/ directory, rather than the configured DocumentRoot
Look up any URL not pointing at a directory under the URL + .html, if that file exists. This has to come after other rewrites, or the "file exists" check will always fail.
# General directives
Options +FollowSymLinks
RewriteEngine on
# Deny URLs beginning /root/, faking them as a 404 Not Found
RewriteRule ^root/ [R=404]
# Additional rule to strip .html off URLs in the browser
RewriteRule ^(.*)\.html$ $1 [R=permanent,L]
# Rewrite everything remaining to the /root sub-directory
# (Host condition was in your post originally, then edited out; this is where it would go)
RewriteCond %{HTTP_HOST} ^(www\.)?tomblanchard\.co\.uk$
RewriteRule ^(.*)$ root/$1
# Handle "missing" ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
PS: Note my careful language to describe (internal) rewrites, as opposed to (browser) redirects: the rule you have is not removing .html from anything, it is adding it, thus allowing the page to be accessed if someone else removes it. Since you are often modifying both within a set of rules, it's important to keep clear in your head the distinction between the URL the browser has requested, and the virtual URL Apache will ultimately serve.
You are not defining any rule to block /root address so how do you want to block it when there is nothing to do that?
Try this:
# Add directives
RewriteEngine on
RewriteCond %{REQUEST_URI} .root [NC]
RewriteRule (.*) / [L,R=404]
# Remove ".html" extension from URLs
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
# Change root directory to "root" folder
RewriteCond %{HTTP_HOST} ^tomblanchard.co.uk$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www.tomblanchard.co.uk$
RewriteCond %{REQUEST_URI} !.root
RewriteRule (.*) /root/$1 [L,R=301,QSA]
This is not tested so if it wouldn't work, play around with it to get your need.

.htaccess Rewrite redirecting URLs

In my .htaccess file, I've got the fairly standard
RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?p=$1 [NC]
and I only need this to happen to files in my root directory. However, if I go to the URL of one of my subdirectories (with or without a index.php file), such as www.foo.com/bar, then I am redirected to www.foo.com/bar/?p=bar - how do I prevent the addition of ?p=bar?
You can try making the rule only execute for non directories as below
#if it is not a directory
RewriteCond %{REQUEST_FILENAME} !-d
#then send it to index.php
RewriteRule ^([a-zA-Z0-9_-]+)$ index.php?p=$1 [NC,L]
You can put .htaccess files into the sub-directories.
# /bar/.htaccess
AllowOverride none
This should prevent the .htaccess inheritance.

Deny direct access to files or directory using .htaccess

I'm playing with .htaccess and I was wondering if with just an .htaccess inside the root directory is possible to block all the request from a browser directed on existing files or directories.
Let's try this example:
RewriteEngine On
RewriteBase /~my_user/my_base/
RewriteRule ^list/$ list.php [L]
RewriteRule ^element_of_list/([a-zA-Z0-9\-]+)/$ element.php?elem_id=$1 [L]
Now, if I write http://127.0.0.1/~my_user/my_base/list/, this is wroking fine but if I write http://127.0.0.1/~my_user/my_base/list.php it's still working. I don't want that. I want the user to obtain a 404 error in the last case.
We have /etc/apache2/mods-enabled/userdir.conf
<IfModule mod_userdir.c>
UserDir public_html
UserDir disabled root
<Directory /home/*/public_html>
AllowOverride All
Options Indexes FollowSymLinks
<Limit GET POST OPTIONS>
Order allow,deny
Allow from all
</Limit>
<LimitExcept GET POST OPTIONS>
Order deny,allow
Deny from all
</LimitExcept>
</Directory>
</IfModule>
My first try was to use RewriteCond:
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^(.*)$ 404.php [L]
But it's not working. Every request ends up redirected to 404.php
UPDATE
So I've managed to create the filter for directories:
RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !^/~my_user/my_base/$ [NC]
RewriteRule ^(.*)$ 404.php [L]
What it does is to check if the requested path (REQUEST_FILENAME) exists and it's a directory AND if it's not my RewriteBase which is basically index.php, then redirect to 404.php
I'm still trying to find something that does the same thing for files. I know I can selectively do that using extensions filename but I want an universal filter for files.
If I've understood your requirements correctly, you're looking to do something like this:
# This is a real directory...
RewriteCond %{REQUEST_FILENAME} -f [OR]
# Or it's a real file...
RewriteCond %{REQUEST_FILENAME} -d
# And it's not 404.php...
RewriteCond $0 !=404.php
# And it's not the root
RewriteCond $0 !=""
# And it's not any of the above due to an internal redirect...
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# So cause a 404 response (you could redirect to 404.php if you want)
RewriteRule ^.*$ - [R=404,L]
# Set the 404 error document
ErrorDocument 404 /~my_user/my_base/404.php
Keep in mind that this blocks everything that exists, so any images, stylesheets, or scripts will be sent to the 404 page too. If you just want to block access to the PHP files, Gumbo's solution is more appropriate. I think in that case you'll need another RewriteCond though to prevent looping:
# Make sure the reason this request has a .php is because it was requested
# by the user (and not due to a redirect)
RewriteCond %{THE_REQUEST} ^[A-Z]+\s/[^\s]+\.php
# Make sure we aren't on 404.php already
RewriteRule %{REQUEST_URI} !404\.php$
# We aren't, so redirect to 404.php
RewriteRule ^ 404.php [L]
Try this rule:
RewriteCond %{THE_REQUEST} ^[A-Z]+\ /[^?\ ]*\.php[/?\ ]
RewriteRule .*\.php$ 404.php [L]
This will rewrite all requests whose paths contain a .php internally to 404.php.

.htaccess Multiple redirects

this is my directory structure
/home
/template
/classifieds
/listings
I want to hide /template and want to show all files under template on home. like /home/template/home.php should be www.example.com/home.php or /home/template/style.css should be www.example.com/style.css
And Someone trying to access example.com/template/.php should be thrown back to example.com/.php if it exists or 404.php if it doesnt.
This was my htaccess to handle that.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^/template/.*php
RewriteRule . /$1 [NC,R]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
Options -Indexes
And my php code
if (!file_exists("template/" . $page))
include_once "template/404.php";
else
include_once "template/" . $page;
However
I have added more things like /classified and /listings should be listed as it is, i.e example.com/classified/*.php
Now when I try to access /answers/home.php it directly opens the home.php rather than opening index.php
This is my new code
if (!file_exists($segments[1] . '/' . $page))
include_once "template/404.php";
else
include_once $segments[1] . '/' . $page;
SO what should be the htaccess like ?
I know this is not a direct answer to your question, but it seems to make more sense to logically organize your file structure to match your web structure. I would suggest:
/home
/public_html
/classifieds
/listings
404.php
index.php
From what I can tell in your post, there is absolutely no reason to be using mod_rewrite at all.
But if you really want to know:
RewriteCond %{REQUEST_URI} !^/classifieds/
RewriteCond %{REQUEST_URI} !^/listings/

Resources