Authorize only 2 files in .htaccess - apache

I would like to authorize only 2 things in .htaccess:
/favicon.ico -> deliver the file
/<anythingelse> -> index.php
Therefore, /logs/mylog.log and /hello.py should go to index.php, instead of displaying the raw content of these files (that do exist!).
How to do such a .htaccess?
I tried:
Solution #1 (seems to create an infinite loop):
RewriteEngine On
RewriteCond %{REQUEST_URI} !favicon\.ico$
RewriteRule ^(.*)$ index.php
Solution #2 (delivers the /logs/mylog.log and /hello.py file, this should not happen!):
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !favicon\.ico$
RewriteRule ^(.*)$ index.php

This will do it:
RewriteEngine On
RewriteCond %{REQUEST_URI} !=/favicon.ico
RewriteCond %{REQUEST_URI} !=/index.php
RewriteRule ^ index.php
Removed the lines checking if it was an existing file or directory, since you want those to get rewritten too.
Added a check that it is not already index.php to avoid a loop.
Changed the RewrieCond syntax to a simple comparison which is more legible.
Added forward slash at the start of the request uri matches or they wouldn't match.
Removed the capturing in the RewriteRule which you're not using.
Update
On further discussion in comments, this should work when a copy of the .htaccess file is placed in a subdirectory. Here is an update so that will work:
RewriteEngine On
RewriteRule !^(?:favicon\.ico|index\.php)$ index.php [END]
The RewriteCond directives couldn't be used without adding the directory name to them, since /index\.php$ was an option but would also match the file in a subdirectory. The above acheives the goal without having to be updated when copied around, albeit not very pretty.

Related

Redirecting all urls, including no path, to a file in subdirectory

I have checked a large amount of existing answers regarding .htaccess redirects. However none of them have helped me.
What I want to accomplish is redirecting all request urls to /api/init.php. However I've only gotten so far to where my index page www.example.com simply gives me a file listing because of the missing index.php file, while every url request with a path is working.
How can I accomplish this with .htaccess without ending up with a directory listing on my landing page?
This is as far as I got:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /api/init.php?path=$1 [NC,L,QSA]
Well your site root is a directory, so this rule you have excludes existing directories. What you could do is only exclude existing files, and allow existing directories to be handled by the PHP script. Like this:
RewriteEngine on
RewriteCond %{REQUEST_URI} !=/api/init.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /api/init.php?path=$1 [L,QSA]
I removed the NC flag as it's not needed. I added a condition to prevent an unnecessary file-system check.
You don't have to pass the path on in a URL parameter, as you could get it from $_SERVER['REQUEST_URI'] in PHP (not the same as REQUEST_URI in mod_rewrite, in PHP it always has the original URI). If you wanted to do that then your rule becomes nice and simple:
RewriteEngine on
RewriteCond %{REQUEST_URI} !=/api/init.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /api/init.php [L]
Because the query string will just be passed on unaffected (so QSA is not needed).

Complex(?) htaccess rewriting / redirecting

It seems every few weeks I have to ask more .htaccess rewriting/redirecting questions. Every time I think I understand it, another wrench gets thrown into my project that shows that I don't.
EDIT: My original question wasn't very clear so the following is an attempt to be more concise.
As it stands, all of the .html files live in the root directory. eg: http://example.com/about.html
There aren't any sub-directories with the exception of normal ones like img, css, etc.
For tracking purposes, if someone types in http://example.com/random/ where "random" can be any string of characters, I'd want them to see the index.html file, without modifying the url. The directory "random" doesn't actually exist on the server at all.
The same goes for other pages like about.html. If someone types in http://example.com/random/about.html I'd want them to see the about.html page.
At the same time, I'd like http://example.com/random/about or http://example.com/about (missing file extension) to also show the about page.
However, if someone typed in a page that doesn't exist, I'd like for it to use the ErrorDocument
Example: I don't have a file named "pickups.html" so the following would all be 404s:
http://example.com/pickups.html
http://example.com/pickups
http://example.com/random/pickups.html
http://example.com/random/pickups
It would be nice if the end redirect/rewrite did have the file extension stripped off (because it looks nicer).
My thoughts are that any request ending with a / would just serve up the index.html file that exists at the site root. So that leaves the files.
My thought process is:
strip the file extension off of the request
check if that file with an extension exists at site root
if yes, display that page.
if no, 404.
My initial code (had help on it) was this:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)/(.*)$ /$2 [R=301,L]
I understand that in that code I'm grabbing everything after the last slash and serving it from the document root. Unfortunately, it doesn't account for files that do not exist.
Starting with existing files, they will be passed through unchanged. This also prevents rewrite loops.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
Next are existing files, requested as part of an optional, virtual subdirectory
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]
This splits the request into an optional prefix (.+/)? and the file part. If this file part exists, maybe with an appended .html, you're done.
Next comes anything with a trailing slash, just rewrite to index.html
RewriteRule /$ /index.html [L]
Anything else will be requests for non-existing files, which yield a 404 status code.
In order to remove an optional .html extension and remove an optional trailing slash / for existing files, we must insert two rules at the beginning
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]
These rules are similar to the other rules, except they do a redirect R|redirect instead of a rewrite, and have an additional condition to prevent a rewrite loop.
Putting everything together gives
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)\.html/?$ /$1$2 [R,L]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+?)/$ /$1$2 [R,L]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
RewriteCond %{DOCUMENT_ROOT}/$2 -f
RewriteRule ^(.+/)?(.+)$ /$2 [L]
RewriteCond %{DOCUMENT_ROOT}/$2.html -f
RewriteRule ^(.+/)?(.+)$ /$2.html [L]
RewriteRule /$ /index.html [L]

RewriteRule for unknown directory

So I'm trying to get a mod_rewrite rule to redirect requests to a php-script with an .htaccess file. The thing is, I want it to work regardless of where I put the project on a webserver (the .htaccess file and the php-script are always in the same folder).
The rewrite itself is very simple. If the script and the .htacess are in the directory /path/to/project and the user visits:
/path/to/project/somestring
it should be rewritten to:
/path/to/project/index.php?t=somestring
This should work for every subdirectory at any level in the webserver. So:
If the php-script and the .htaccess files are in the root:
/somestring2
should be rewritten to:
/index.php?t=somestring2
If the php-script and the .htaccess file are in /subdirectory:
/subdirectory/somestring3
should be rewritten to:
/subdirectory/index.php?t=somestring3
So the RewriteRule should perform the same rewrite action regardless of where the project lives within the server. The string that is to become a GET-parameter can consist of those characters: [a-zA-Z0-9]. If there are other GET-parameters in the requested URL, they should be appended as well (hence the QSA flag). This is what I've tried:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*/)([a-zA-Z0-9])/? $1index.php&t=$2 [L,QSA]
However, this results in a 404 error. How can I alter it to do what I want?
Try :
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*/)?([A-Za-z0-9]+)/?$ /$1index.php?t=$2 [NC,L,QSA]
Note that a leading slash in rewrite pattern is not required in the RewriteRule context.

.htaccess - Rewrite subfolder to parent with access to other files in the parent

I am trying to create a RewriteRule which would allow me to hide the subfolder name from the URL. It seems pretty straightforward, although I would also like to retain access to the files in the parent folder, and I can't work out how to achieve this and whether this would be possible at all. To make it a bit more clear, my file tree is as follows:
[root]
L[parent]
file1
L[subfolder]
file2
So what I am trying to do, is to be able to rewrite http://example.com/parent/subfolder/file2 to http://example.com/parent/file2 while still having access to http://example.com/parent/file1. So far I found possible solutions here and here, but neither of them work as expected. I also had a look at the Apache Aliases, but I am not sure I can use them in this case. Any suggestions please?
Edit: Here is the current .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /pico/
RewriteRule sitemap\.xml \?sitemap
RewriteRule ^parent?$ parent/ [R=301,L] ## Redirects the old file to the index with the same name
RewriteRule ^parent/subfolder/?$ parent/ [R=301,L] ## Redirects the index of the subfolder to the parent
RewriteRule ^old-folder/?$ parent/subfolder/new-file1 [R=301,L] ## Redirects the old index to a new file in the subfolder
RewriteRule ^old-folder/old-file parent/new-file [R=301,L] ## Redirects the files in the old folder to a new file in the parent
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
RewriteRule ^parent/([^/]+)/?$ parent/subfolder/$1 [L]
</IfModule>
# Prevent file browsing
Options -Indexes
The rules with the comments are just examples, since I am moving the old content to the new site while changing the structure, so there are many more repeating rules just like the examples above.
Did you just try this? Put this in an .htaccess file in the root.
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^parent/([^/]+)/?$ /parent/subfolder/$1 [L]
Edit:
Based on your comment I'm explaining what I put above. You said you wanted anything that is in the parent/subfolder to be read as if it is in the parent location directly. So that means http://example.com/parent/file2 does NOT really exist. Because it actually exists in http://example.com/parent/subfolder/file2.
That is the purpose of the conditions. It checks to make sure that any request for /parent/whatever is NOT a real file and NOT a real directory, and if that is true it rewrites it to /parent/subfolder/whatever. So it is what you asked for but you're not using the rules the way I gave them to you. All you did was add the rewriterule line to the bottom of your file and it will never execute because this rule
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
will execute before RewriteRule ^parent/([^/]+)/?$ /parent/subfolder/$1 [L] and then it will never run. You can't just provide pieces of your .htaccess rules when asking a question because some rules will take precedent over others depending on their order. You need to provide all your rules as you just now did.
So you need to change your rules to this.
RewriteRule sitemap\.xml \?sitemap
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^parent/([^/]+)/?$ /parent/subfolder/$1 [L]
RewriteRule ^parent?$ parent/ [R=301,L] ## Redirects the old file to the index with the same name
RewriteRule ^parent/subfolder/?$ parent/ [R=301,L] ## Redirects the index of the subfolder to the parent
RewriteRule ^old-folder/?$ parent/subfolder/new-file1 [R=301,L] ## Redirects the old index to a new file in the subfolder
RewriteRule ^old-folder/old-file parent/new-file [R=301,L] ## Redirects the files in the old folder to a new file in the parent
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]

htaccess rewrite rules to remove multiple subfolders from a URL

Due file system sub-directory constraints I will most likely reach I want to separate the /users folder into /users/a/username, /users/b/username, /users/c/username, etc.
So the data on the server for a user would be in:
www.domain.com/users/a/username/, www.domain.com/users/b/username/, etc
I want the URL to be:
www.domain.com/users/username/
Optionally to avoid duplicate content a 301 redirect from www.domain.com/users/a/username/ to www.domain.com/users/username/ would also be good.
Currently I have a rewrite for a single sub-directory (see below) but I'm confused how this can be done efficiently for all of the alphabetical sub-directories.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^users/(.*)$ users/a/$1 [L,NC]
I have checked this site and all seem to hide the first sub-directory e.g. domain.com/folder1/filename.html => domain.com/filename.html but nothing in more depth.
Put this code in your htaccess (which has to be in root folder)
Options -Indexes -MultiViews
RewriteMap lowercase int:tolower # this line in your apache file configuration
RewriteEngine On
RewriteCond %{THE_REQUEST} \s/users/[a-z]/([^/\s]+)\s
RewriteRule . /users/%1/? [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^users/([A-Za-z])([^/]+)/$ /users/${lowercase:$1}/$1$2/ [L]