htaccess rewrite rules to remove multiple subfolders from a URL - apache

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]

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).

Authorize only 2 files in .htaccess

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.

.htaccess affect other file url

I am trying to make .htaccess rule not affect other file url
example
my .htaccess rule is
RewriteEngine On
RewriteRule ^([^/]*)$ /tr/hp.php?q=$1 [L]
my site url is
mydomain.com/keywords
everything working good on keywords but when I try to open robots.txt
mydomain.com/robots.txt
OR
mydomain.com/images.jpg
any other file url
redirect on /tr/hp.php?q=filename
which .htaccess Rewrite Rule works on both?
Try :
RewriteEngine On
#--exclude real directories
RewriteCond %{REQUEST_FILENAME} !-d
#--and files
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)/?$ /tr/hp.php?q=$1 [L]
You also have to prevent matching any request pattern that carries a dot in it:
RewriteEngine On
RewriteRule ^([^/.]*)$ /tr/hp.php?q=$1 [L]
Certainly it is possible to further refine this pattern.
Alternatively some people like to prevent rewriting requests to files or folders that physically exist in the file system using RewriteCond:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
But that is something you have to decide upon. This does not help for example if resources like robots.txt are delivered in a dynamic manner...

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.

Apache mod_rewrite never rewrite for existing directory except directory is certain directory?

A website http://www.example.com/ runs on a CMS and everything goes through it by rules set in .htaccess. When visiting http://www.example.com/ the user is redirected to one of the following paths depending on the user's language settings:
http://www.example.com/en/
http://www.example.com/fr/
The /en/ and /fr/ directories don't really exist, they are processed by the CMS.
I am adding a new section (investors/) to the site but don't want it to go through the CMS for now, but I don't want the users to notice it.
The original .htaccess file has these lines:
# never rewrite for existing files, directories and links
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
# rewrite everything else to index.php
RewriteRule .* index.php [L]
I managed to make it not go through the CMS if the requested path begins with /en/investors/ or /fr/investors/:
# never rewrite for existing files, directories and links
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
# rewrite everything else to index.php
# except investors' section
RewriteRule ^(?!\/en\/investors|\/fr\/investors).+ index.php [L]
I uploaded my /en/investors/ and /fr/investors/ directories onto the server and they work fine, but now the home page is broken because the /en/ and /fr/ directories now exist. How can I add exceptions to that rule?
Simple add another rule to cover the 2 directories e.g.
RewriteRule ^(en|fr)/?$ index.php [L]