How avoid infinite loop when htaccess rewrites to a copy of same htaccess-file? - apache

I have this htaccess file:
RewriteEngine On
RewriteCond %{HTTP_HOST} =test.example.com [NC]
RewriteRule ^((?!test/).*)$ test/$1 [L,NC]
And a completely identical copy of the same file in the "test" directory. So, of course, this leads to an infinite loop when the first file pass you to the second file running the rules again.
I have tried add the rule RewriteCond %{REQUEST_URI} !^test [L,NC] in hope that REQUEST_URI stood for the real path and not the new "alias". However, it didn't worked.
Is there any way to maybe check which directory we are in to use in a condition? Or any other solution to this problem? With the basis to keep the both file's codes identical.

If you're already in test directory there is no point to rewrite again to test directory using a relative path. It will be better to determine the RewriteBase dynamically and use absolute paths for rewriting:
RewriteEngine On
# generate BASE dir in env variable %{ENV:BASE}
RewriteCond %{REQUEST_URI}::$1 ^(.*?/)(.*)::\2$
RewriteRule ^(.*)$ - [E=BASE:%1]
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{HTTP_HOST} =test.example.com [NC]
RewriteRule ^(.*)$ %{ENV:BASE}test/$1 [L,NC]
RewriteCond %{ENV:REDIRECT_STATUS} ^$ is used to prevent rewriting after first rewriting of the rule since %{ENV:REDIRECT_STATUS} becomes 200 after that.

Okay, weird, but I now got it to work - simply like this:
RewriteCond %{HTTP_HOST} =test.example.com [NC]
RewriteCond %{REQUEST_URI} !test [NC]
RewriteRule ^((?!test/).*)$ test/$1 [L,NC]
Edit: Seems like it only works for the startpage. On other pages, the beginning trailing slash of the path is being removed.

Related

htaccess to hide subdirectory without changing base root, and with exception of another subdirectory

I have a website https://example.com
which has 2 subdirectories, https://example.com/admin and https://example.com/store.
I want to hide /store from URL so my requests would look like:
https://example.com/shop.php?id=someid
But Also, I want https://example.com/admin/index.php to work.
I found some answers that achieve both 1 and 2 but they change base root so all my css,js, images don't load
So far I have:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^store/(.*) /$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule !^store/ store%{REQUEST_URI} [L]
This achieves 1 but not 2.
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule ^store/(.*) /$1 [L,R=301]
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteRule !^store/ store%{REQUEST_URI} [L]
In the second rule... exclude the /admin subdirectory (as well as /store) in the RewriteRule pattern. And add a condition to exclude requests that contain a file extension (ie. .css, .js, .png, etc.). For example:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteCond %{REQUEST_URI} !\.\w{2,4}$
RewriteRule !^(store|admin)($|/) store%{REQUEST_URI} [L]
Alternatively (although marginally less efficient), exclude any request that already maps to a physical file:
RewriteCond %{HTTP_HOST} ^(www\.)?example.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule !^(store|admin)($|/) store%{REQUEST_URI} [L]
This rule assumes you have another .htaccess file in the /store subdirectory that also uses the rewrite engine. (But if that is the case then the first rule isn't actually doing anything.)
Unless you are hosting multiple domains/sites then you don't need the first condition that checks the requested Host.

Remove subfolder of a folder from Url by Htaccess?

I have a URL structure like this -
https://example.com / folder / subfolder / files.html
I have many files in the subfolder. I want to remove the 'subfolder' from the URL.
I have tried some of the StackOverflow solutions. but not succeeded.
Also please tell me where to paste the .htaccess code. in the .htaccess file which is located in 'folder' or in 'subfolder'.
edit
folder/htaccess
RewriteEngine On
RewriteCond {REQUEST_FILENAME} !-f
RewriteCond {REQUEST_FILENAME} !-d
RewriteRule ^(.+)/?$ /folder/subfolder/$1 [L]
subfolder/htaccesss
RewriteEngine On
RewriteRule (.+) /folder/$1 [L,R]
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.html [NC]
RewriteRule ^ %1 [R,L,NC]
RewriteCond %{REQUEST_FILENAME}.html-f
RewriteRule ^ %{REQUEST_URI}.html[L]
You can use the following rule in your /folder/. htaccess :
RewriteEngine On
RewriteCond {DOCUMENT_ROOT}/$1 -f [OR]
RewriteCond {DOCUMENT_ROOT}/$1 -d
RewriteRule ^(.+)/?$ /folder/subfolder/$1 [L]
If the rule above fails to work, then use the following instead
RewriteEngine On
RewriteCond %{REQUEST_URI} !/folder/subfolder/
RewriteRule ^(.+)/?$ /folder/subfolder/$1 [L]
Remember to place the rule at the top of your htaccess or before other directives and put it in htaccess in your /folder directory.
EDIT :
If you also want to redirect your old URLs to the new one , for example /folder/subfolder/file.html to /folder/file.html , put the following rule in htaccess in folder/subfolder
RewriteEngine On
RewriteRule (.+) /folder/$1 [L,R]
Remember to place the code above in htaccess in your subfolder and when you are sure the rule is working, change R to R=301 to make the redirection permanent as it avoids the duplicate content issues in search engines.
Edit :
If the above solution isn't working for you, as you said in comments you are getting 404 error on redirection. The error is there because the requested file is being rewritten to a non-existentpath/folder/file.html. You can solve this by removing your/folder/subfolder/. htaccessfile and only use one single htaccess in/folder/` with the following contents :
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^subfolder/(.+)/?$ /folder/$1 [L,R]
RewriteCond %{REQUEST_URI} !/folder/subfolder/
RewriteCond %{REQUEST_URI} !\.(css|js|jpg|gif|png|jpeg)$
RewriteRule ^(.+)/?$ /folder/subfolder/$1 [L]

Not able to track htaccess issue, How to implement IF ELSE in htaccess

I have a problem with htaccess to execute a rule and if rule matches then do not check for another rule. which i am trying to figure out from last few hours. Below is the sample code
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} ^/projectname/$
#RewriteCond %{REQUEST_URI} !projectname/(storage)$
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} projectname/(storage)$
RewriteRule ^(.*)$ /projectname/storage/$1 [L]
Rewritecond %{REQUEST_URI} projectname/(.*)$
#RewriteCond %{REQUEST_URI} !projectname/(storage)$ [NC]
RewriteCond %{REQUEST_URI} !\.(html?|png|woff|ttf|eot|svg|woff2|jpg|gif|xml|rss|png|css|js|json)$ [NC]
RewriteRule ^(.*)$ /projectname/#/$1 [NE,R=301,L]
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [L]
I want to load everything from projectname/abc/dist folder but not for the case when i have storage inside url then i want to load the data from storage folder only.
So as per rules defined here everything works fine but when i have storage inside url/src for image it still checks /projectname/abc/dist/storage/xxxx.png instead of checking /projectname/storage/xxxx.png as defined in htaccess rule.
I have tried using [S=5] skip with storage rule in htaccess does not works from reference http://httpd.apache.org/docs/2.4/rewrite/flags.html.
Also as per my understanding [L] is the last so it should stop the htaccess after storage rule but it does not.
I have tried implementing IF ELSE in htaccess but the examples i tried for IF ELSE does not help even.
reference https://blogs.apache.org/httpd/entry/new_in_httpd_2_4
reference http://httpd.apache.org/docs/2.4/rewrite/flags.html (check Skip IF ELSE stanza)
Any Idea would be useful.
You want to load from 'projectname/abc/dist'-folder EXCEPT when there is 'storage' anywhere in the requested URI?! If I got that right, that might help:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !storage
RewriteRule ^(.*)$ /projectname/abc/dist/$1 [END,P]
I added [P] for 'proxy' assuming that you don't want to show the customer he is rewritten by your server. If you don't mind seeing them, just leave that out.
First of all, L|last doesn't mean stop all processing.
If you are using RewriteRule in either .htaccess files or in sections, it is important to have some understanding of how the rules are processed. The simplified form of this is that once the rules have been processed, the rewritten request is handed back to the URL parsing engine to do what it may with it.
See also Ruleset Processing for how this works.
To load from /project/abc/dist, except when there's storage in the URL, you must first check for storage
RewriteCond %{REQUEST_URI} /storage/
RewriteRule /([^/]*$ /project/storage/$1 [L]
And then
RewriteRule ^(.*)$ /project/abc/dist/$1 [L]
Finally, to prevent a rewrite loop, prefix the rules with
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
Everything together
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
RewriteCond %{REQUEST_URI} /storage/
RewriteRule /([^/]*$ /project/storage/$1 [L]
RewriteRule ^(.*)$ /project/abc/dist/$1 [L]

Check URL and stop processing using htaccess

I want to check URL using htaccess. Developer might want run special file - specialfile.php. I use htaccess:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} /specialfile\.php$
RewriteRule .* [L] #don't change adress
RewriteRule ^$ public/index.html [NC,L]
RewriteRule (.*) public/$1 [NC,L]
My idea was: if rewriteCond %{REQUEST_URI} !/specialfile.php$ true than htaccess should use RewriteRule .* [L] - that should mean that specialfile.php will be run and this all. But it doesn't work because it runs next rule: RewriteRule (.*) public/$1 [NC,L].
I think you are using the RewriteCond not correctly. The conditions only affect the next RewriteRule that follows.
Check out the example on the Apache Homepage. Since your 2nd RewriteRule is evalutated, I think your conditions are not correct. To get a litte bit more information about the rewriting, you should increase the log level. This is also documented here.
Your 2nd rule ^$ matches only an empty request btw. That's why it probably does not work as you expect it to.

.htaccess redirect loop issue

If I go to domain.com, site redirects to domain.com/en, which is expected. But then the last rule kicks in and throws it in a loop making my url look something like this:
http://domain.com/en/?lang=en&request=&site=basecamp&lang=en&request=&site=basecamp&lang=en&request=&site=basecamp&lang=en&request=&site=basecamp
.htaccess file
Options +FollowSymlinks
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_URI} !/(content|images|css|js|fonts|pdfs)/
RewriteRule /([^.]+\.(jpe?g|gif|bmp|png|css|js|eot|svg|ttf|ico|pdf))$ /$1 [NC,R,L]
RewriteCond %{REQUEST_URI} !(content|images|css|js|fonts|pdfs)/.*
RewriteRule !^[a-z]{2}/ /en/ [NC,L,R]
RewriteCond %{REQUEST_URI} !/(init\.php|content|images|css|js|fonts|pdfs)/
RewriteRule ^([a-z]{2})/(.*)$ init.php?lang=$1&request=$2&site=basecamp[L,QSA]
Why is the htaccess file redirecting to /?GET_VARS instead of /init.php?GET_VARS ?
And how can I avoid this loop?
Try changing your last condition by removing the leading and trailing slashes. You've rewritten your URI to:
/init.php
But there's no trailing slash like there is in the condition that you've provided, so the rule gets applied again. It should look like:
RewriteCond %{REQUEST_URI} !(init\.php|content|images|css|js|fonts|pdfs)
Not sure why you insist on having the trailing slash at the end of your condition here:
# with this / here, it will never match init.php --------v
RewriteCond %{REQUEST_URI} !/(init\.php|content|images|css|js|fonts|pdfs)/
But you can solve it by just excluding init.php directly:
RewriteCond %{REQUEST_URI} !init.php
So, just so it's clear, your last set of conditions/rule will look like:
RewriteCond %{REQUEST_URI} !init.php
RewriteCond %{REQUEST_URI} !/(content|images|css|js|fonts|pdfs)/
RewriteRule ^([a-z]{2})/(.*)$ init.php?lang=$1&request=$2&site=basecamp [L,QSA]
Or worst case, just add this in the very beginning of your rules:
RewriteCond %{ENV:REDIRECT_STATUS} 200
RewriteRule ^ - [L]
Which prevents any kind of rewrite engine looping altogether.