Htaccess recursive file rewrite - apache

I would like to know if there is a better way to achieve this sort or redirection :
# Apache configuration
Options -Indexes
Options +FollowSymLinks
# Rewrite engine configuration
RewriteEngine On
RewriteBase /
# Force domain www (302 redirect)
RewriteCond %{HTTP_HOST} ^([^\.]+\.[^\.0-9]+)$
RewriteRule ^/?(.*)$ http://www.%1/$1 [L,R=302]
# Request redirection (/module/TLD/module/DOMAIN/module/SUB/data/public/...)
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^(.+)\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/%{REQUEST_URI} -f
RewriteRule ^/?(.+)$ /module/%3/module/%2/module/%1/data/public/$1 [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^(.+)\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/%{REQUEST_URI}/index.php -f
RewriteRule ^/?(.+)/?$ /module/%3/module/%2/module/%1/data/public/$1/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^(.+)\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/%{REQUEST_URI}/index.html -f
RewriteRule ^/?(.+)/?$ /module/%3/module/%2/module/%1/data/public/$1/index.html [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^(.+)\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/index.php -f
RewriteRule ^/?$ /module/%3/module/%2/module/%1/data/public/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^(.+)\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/index.html -f
RewriteRule ^/?$ /module/%3/module/%2/module/%1/data/public/index.html [L]
# Request redirection (/module/TLD/module/DOMAIN/data/public/...)
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/%{REQUEST_URI} -f
RewriteRule ^/?(.+)$ /module/%2/module/%1/data/public/$1 [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/%{REQUEST_URI}/index.php -f
RewriteRule ^/?(.+)/?$ /module/%2/module/%1/data/public/$1/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/%{REQUEST_URI}/index.html -f
RewriteRule ^/?(.+)/?$ /module/%2/module/%1/data/public/$1/index.html [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/index.php -f
RewriteRule ^/?$ /module/%2/module/%1/data/public/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.]+)\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/index.html -f
RewriteRule ^/?$ /module/%2/module/%1/data/public/index.html [L]
# Request redirection (/module/TLD/data/public/...)
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/%{REQUEST_URI} -f
RewriteRule ^/?(.+)$ /module/%1/data/public/$1 [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/%{REQUEST_URI}/index.php -f
RewriteRule ^/?(.+)/?$ /module/%1/data/public/$1/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/%{REQUEST_URI}/index.html -f
RewriteRule ^/?(.+)/?$ /module/%1/data/public/$1/index.html [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/index.php -f
RewriteRule ^/?$ /module/%1/data/public/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{HTTP_HOST} ^.+\.([^\.0-9]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/index.html -f
RewriteRule ^/?$ /module/%1/data/public/index.html [L]
# Request redirection (/data/public/...)
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{DOCUMENT_ROOT}/data/public/%{REQUEST_URI} -f
RewriteRule ^/?(.+)$ /data/public/$1 [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{DOCUMENT_ROOT}/data/public/%{REQUEST_URI}/index.php -f
RewriteRule ^/?(.+)/?$ /data/public/$1/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{DOCUMENT_ROOT}/data/public/%{REQUEST_URI}/index.html -f
RewriteRule ^/?(.+)/?$ /data/public/$1/index.html [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{DOCUMENT_ROOT}/data/public/index.php -f
RewriteRule ^/?$ /data/public/index.php [L]
RewriteCond %{REQUEST_URI} !^/index.php
RewriteCond %{DOCUMENT_ROOT}/data/public/index.html -f
RewriteRule ^/?$ /data/public/index.html [L]
# Request redirection (main index file)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ /index.php [L,PT]
For exemple, i redirect a request like http://www.testdomain.com/test/file.css to these possibles paths :
/module/com/module/testdomain/module/www/data/public/test/file.css
/module/com/module/testdomain/data/public/test/file.css
/module/com/data/public/test/file.css
/data/public/test/file.css
If none of these paths are correct, i fall back to /index.php. And, for a request with empty uri, i try to dispatch it like http://www.testdomain.com/index.html or http://www.testdomain.com/index.php. Is there a better way to achieve this sort of rewriting ?

What you are trying to do is verbose and somewhat bizarre, and the bizarre nature is what caught my interest. :-) However, I assume that you must have your reasons.
One advantage of being verbose is that you can define exactly what you want to achieve and in one .htaccess file, so if it aint' broke ... Though you are doing quite a few regexp and stat probes in this logic chain, so I am nore sure that I would recommend this as a general approach.
Also any 'options' would also impact the semantics of what you are trying to achieve, but you could use the recursive nature of the rewrite engine to advantage, for example if /module/TLD/module/DOMAIN/module/SUB/data/public/ then the URI must be interpreted in that context, hence something like
# If we have a file match, then we're done
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Skip the four directory rewrites except on first pass
RewriteCond %{ENV:REDIRECT_PASS} !=""
RewriteRule ^ - [E:PASS=OK, SKIP=5]
RewriteRule ^ - [E:PASS=OK]
# Redirect to correct subdirectory
RewriteCond %{HTTP_HOST} ^(.+)\.([^.]+)\.([^.\d]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%3/module/%2/module/%1/data/public/ -d
RewriteRule ^.*$ /module/%3/module/%2/module/%1/data/public/$0 [L]
RewriteCond %{HTTP_HOST} ^.+\.([^.]+)\.([^.\d]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%2/module/%1/data/public/ -d
RewriteRule ^.*$ /module/%2/module/%1/data/public/$0 [L]
RewriteCond %{HTTP_HOST} ^.+\.([^.\d]+)$
RewriteCond %{DOCUMENT_ROOT}/module/%1/data/public/ -d
RewriteRule ^.*$ /module/%1/data/public/$0 [L]
RewriteRule ^.*$ /data/public/$0 [L]
# Etc ... your URIs now include the correct prefix.
Note
A bare ^ always matches
A bare - in the subst string means leave unchanged
Don't include leading / in PER_DIR (eg. .htaccess patterns
$0 is the entire match string -- saves using brackets if you want the whole thing
You don't need to escape . inside a [] selector.
Read up on setting and using environment variables. If you set the variable PASS then this appears as REDIRECT_PASS after an internal redirect.
You will also need to enable rewrite logging and go through your logs to debug this. Have fun.

Related

Too many redirection CSS

I obtain error style.css:1 GET https://www.example.com/cs_CZ net::ERR_TOO_MANY_REDIRECTS
Could be related to my htaccess?
RewriteEngine On
AddDefaultCharset utf-8
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteRule ^\.htaccess$ - [F]
RewriteCond %{REQUEST_URI} =""
RewriteRule ^.*$ /public/index.php [NC,L]
RewriteCond %{REQUEST_URI} !^/public/.*$
RewriteRule ^(.*)$ /public/$1
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^.*$ - [NC,L]
RewriteRule ^public/.*$ /public/index.php [NC,L]
EDIT:
After #RavinderSingh13 changes I have error with permissions
Have your htaccess file in following way, please do make sure to clear your browser cache before testing your URLs.
RewriteEngine On
AddDefaultCharset utf-8
##Placing rules for non-https URLs here to apply https on URLs.
##Fixes: Added NE flag in rules here.
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
##Placing rules for non www URLs here to apply www on URLs.
##Fixes: Added NE flag in rules here.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ http://www.%{HTTP_HOST}/$1 [R=301,L,NE]
##Rules for files to block those urls.
##Fixes: Added L flag to the rules.
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [F,L]
RewriteRule ^\.htaccess/?$ - [F]
##Removed condition RewriteCond %{REQUEST_URI} ="" here as its not required.
RewriteRule ^/?$ /public/index.php [L]
##Rules for non public uris to handle here.
RewriteCond %{REQUEST_URI} !^/public [NC]
RewriteRule ^(.*)/?$ /public/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(public)/.*$ /$1/index.php [QSA,NC,L]

How to rewrite URL by Htaccess with basic parameters in core PHP

Hello all i am having a issue with this URL rewrite.
my current URL is like this
domain.com/professional?seo=ACCOUNTIFY-SERVICES-&-ADVISORS&id=3173
here the page name professional can be changed to any page like i will have the similer url with other page names.
Desired URL
domain.com/professional/ACCOUNTIFY-SERVICES-&-ADVISORS/3173
i know that i can do this by htaccess for sure
here is my htaccess file
RewriteEngine On
RewriteBase /
Options All -Indexes
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteRule ^ - [L]
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
</IfModule>
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^(.*)$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]
# remove index.php
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteCond %{REQUEST_URI} ^(.*/)index\.php$ [NC]
RewriteRule ^ %1 [L,R=301,NE]
# To externally redirect /dir/file.php to /dir/file
RewriteCond %{REQUEST_METHOD} !POST
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,NE,L]
# To internally forward /dir/file to /dir/file.php
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
Header set Access-Control-Allow-Origin "*"
please suggest me the changes needs to be done here to achieve the desired url.
Thank you so much for any help.
i have been reading some answers here and if i find a solution i will post here.
You can use these rules:
RewriteEngine On
RewriteBase /
Options All -Indexes
RewriteCond %{REQUEST_METHOD} POST [NC]
RewriteRule ^ - [L]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L,NE]
# external redirect from actual URL to pretty one
RewriteCond %{THE_REQUEST} \s/+([^.]+)(?:.php)?\?seo=([^\s&]+)&cat=([^\s&]+)&id=([^\s&]+)\s [NC]
RewriteRule ^ /%1/%2/%3/%4? [R=301,L,NE]
RewriteCond %{THE_REQUEST} \s/+([^.]+)(?:.php)?\?seo=([^\s&]+)&id=([^\s&]+)\s [NC]
RewriteRule ^ /%1/%2/%3? [R=301,L,NE]
# remove index.php
RewriteCond %{THE_REQUEST} /index\.php [NC]
RewriteCond %{REQUEST_URI} ^(.*/)index\.php$ [NC]
RewriteRule ^ %1 [L,R=301,NE]
# To externally redirect /dir/file.php to /dir/file
RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,NE,L]
# internal forward from pretty URL to actual one
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/([^/]+)/([^/]+)/([^/]+)/?$ $1.php?&seo=$2&cat=$3&id=$4 [L,QSA]
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/([^/]+)/([^/]+)/?$ $1.php?&seo=$2&id=$3 [L,QSA]
# To internally forward /dir/file to /dir/file.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.+?)/?$ $1.php [L]
Header set Access-Control-Allow-Origin "*"

incorrect redirect from http to https

trying to go https, but when I use the following in my .htaccess I get redirect problem error
here is what I have in my .htaccess
RewriteEngine On
RewriteBase /
RewriteCond %{HTTP} on [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} https [OR]
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
#Uncomment lines below when uploading to the live server
RewriteCond %{HTTP_HOST} !^(www\.)example\.com$ [NC]
RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^.*$ index.php [QSA,L,NC]
#Uncomment lines below when uploading to the live server
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?example.com/.*$ [NC]
RewriteRule \.(gif|jpg|png|tif|js|css|xls|xlsx|zip|rar|pdf|ods|ots)$ - [F]
Please help
Your first rule has many erroneous [OR] conditions and that is causing redirect loop.
Change your first rule to this:
RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://www.%1%{REQUEST_URI} [R=302,L,NE]
And test after clearing your browser cache.

htaccess mod_rewrite: Simplifying URL

I've been having trouble with the following rewrite. I'm certain mod_rewrite is enabled but not sure where I am going wrong.
I'm try to change the following pattern:
/profile/?userid=157&username=FirstL
to:
/profile/FirstL
I've tried many different rules, but the two I felt were the closest to being correct aren't working at all. My current failures below:
RewriteEngine On
RewriteCond %{THE_REQUEST} \ /profile/+\?userid=$([^&\ ]+)&username=$([^&\ ]+)
RewriteRule ^ /%1? [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^/]+)$ /profile/?userid=$1&username=$2 [L,QSA]
 
RewriteEngine On
RewriteRule ^([^/]*)$ /profile/?userid=$1&username=$2 [L]
Full htaccess:
Options +FollowSymLinks -Multiviews
RewriteEngine On
RewriteCond %{THE_REQUEST} \ /profile/+\?userid=$([^&\ ]+)&username=$([^&\ ]+)
RewriteRule ^ /profile/%1/%2? [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^profile/([^/]+)/([^/]+)$ /profile/?userid=$1&username=$2 [L,QSA]
RewriteBase /
DirectorySlash Off
RewriteRule ^admin$ /admin/index.php [L,E=LOOP:1]
RewriteCond %{ENV:REDIRECT_LOOP} !1
RewriteRule ^admin/index.php$ /admin [R=301,L]
# remove .php
RewriteCond %{THE_REQUEST} ^GET\ (.*)\.php\ HTTP
RewriteRule (.*)\.php$ $1 [R=301]
# remove index
RewriteRule (.*)/index$ $1/ [R=301]
# remove slash if not directory
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /$
RewriteRule (.*)/ $1 [R=301]
# add .php to access file, but don't redirect
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteCond %{REQUEST_URI} !/$
RewriteRule (.*) $1\.php [L]
#Force non-www:
RewriteCond %{HTTP_HOST} www.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
You're losing the userID part of the URL, so when you try to internally rewrite that back, there's nothing there:
RewriteRule ^([^/]+)$ /profile/?userid=$1&username=$2 [L,QSA]
This rule says the first match is the "userid" and the second match is the "username", and you only have one match, and on top of that, it doesn't even begin with "profile".
You'll need to include the userid somewhere in the URL, otherwise there's no way to extract it.
RewriteEngine On
RewriteCond %{THE_REQUEST} \ /profile/+\?userid=([^&\ ]+)&username=([^&\ ]+)
RewriteRule ^ /profile/%1/%2? [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^profile/([^/]+)/([^/]+)$ /profile/?userid=$1&username=$2 [L,QSA]

How to exclude a subdirectory from an Apache URL rewrite condition

I have the following rewrite conditions applied to the root directory of my Apache2 webserver (in apache.conf)
<IfModule mod_rewrite.c>
Options +FollowSymlinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
RewriteRule "(^|/)\." - [F]
</IfModule>
I have a subdirectory, www.domain.com/subdir that I don't want these rewrites to apply to. How can I exclude subdir from these options?
Actually you just need to move up your last rule of skipping files/directories. Try this code:
Options +FollowSymlinks
RewriteEngine On
# if request is not for a file/directory
RewriteCond %{SCRIPT_FILENAME} -d [OR]
RewriteCond %{SCRIPT_FILENAME} -f
# then skip from rewrites
RewriteRule ^ - [L]
# add www to hostname
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{SERVER_ADDR} !=127.0.0.1
RewriteCond %{SERVER_ADDR} !=::1
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# forward all the requests to `/index.php
RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]
Right after this line
RewriteEngine On
Add:
RewriteRule ^/subdir/ - [L]
or
RewriteCond %{THE_REQUEST} \ /+subdir/
RewriteRule ^ - [L]