.htaccess: ??/index.php --> ??/, built on a relative path - .htaccess

Remove indx.php from URL; always redirect ??/ from ??/index.php
...including subdirectories, which may have their own .htaccess and index.php.
I'm using Apache with .htaccess.
I have a webapp with index.php in a subdirectory of the domain, say here:
example.tld/somedir/
But, it could be installed to any directory, such as these...
example.tld/anotherdir/
sub.domain.tld/
another.tld/
Each has its own index.php and its own .htaccess, for our purposes
On example.tld/somedir/: example.tld/, sub.example.tld/, et cetera also have their separate index.php and .htaccess, for their separate purposes
I need this to still work if placed in a subdir example.tld/dir/ of a WordPress or October or SuitCRM installation at example.tld/.
Always hide index.php via .htaccess
I want to make sure that:
All above four / (root) addresses link to index.php in whatever same directory.
index.php always redirects to / (root)
Examples
example.tld/anotherdir/index.php -> example.tld/anotherdir/
sub.domain.tld/index.php -> sub.domain.tld/
another.tld/index.php -> another.tld/
I need something like this
RewriteRule ^.*$ /{$PWD}/index.php [L,QSA]
...and any Rewrite statements that must precede it.
These Questions do not provide an answer:
htaccess redirect index.php to root (including subdomains)
This does not address subdirectories, only subdomains
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
htaccess remove index.php from url
This only removes indx.php from example.com/index.php/dir/subdir
This does not remove index.php from example.com/dir/index.php like I need
.Htaccess redirect index.php
This never got a working Answer
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
Redirect to index.php of .htaccess dir
This requires to specify /dir/, which I can't do.
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
The Answers don't work for the OP.
htaccess remove index.php and index.php/
This removes subdirectories from the URL also.
Redirect all to index.php using htaccess
This also requires to specify /dir/ in example.tld/dir/index.php
Answer is: RewriteRule ^.*$ /mvc/index.php [L,QSA], which I can't use.
.htaccess - simple redirect: index (with no extension!) / index.html / index.php to root
Does not address subdirectories, which I need.
Removing index.php from URLS with .htaccess
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/

To serve index.php from the requested directory you use mod_dir's DirectoryIndex directive (which is probably already set in the server config, although defaults to index.html only) - you do not need mod_rewrite for this. For example:
# Serve "index.php" from the requested directory
DirectoryIndex index.php
This instructs Apache to serve index.php from whatever directory is requested. eg. Request /foo/bar/ then /foo/bar/index.php is served via an internal subrequest (no redirect). If index.php is not present in that directory you'll get a 403 Forbidden response (assuming directory listings - as generated by mod_autoindex - are disabled).
To remove index.php from any URL that is requested directly you can use mod_rewrite. For example:
RewriteEngine On
# Remove "index.php" from any URL and redirect back to the "directory"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+/)?index\.php(/|$) /$1 [R=301,L]
The above will redirect as follows, preserving the requested protocol and hostname:
/index.php to /
/foo/index.php to /foo/
/foo/bar/index.php to /foo/bar/
/fooindex.php - NO REDIRECT (404 expected)
/foo/index.php/bar (containing path-info) to /foo/ (path-info removed)
/foo/index.phpbar - NO REDIRECT (404 expected)
The (optional) capturing group (.*/)? contains the part of the URL-path before index.php. This is then available in the substitution string using the $1 backreference. In the case when /index.php is requested in the document root, this is empty. When a subdirectory is present then this contains a string of the form subdir/, including the trailing slash.
If you have no other directives in your .htaccess file then you don't strictly need the condition that checks against the REDIRECT_STATUS environment variable. This condition ensures that only direct requests are redirected in the case when you have a front-controller pattern later in the file that might rewrite requests to index.php.
If you do have other directives in the file then the order can be important. This rule that removes index.php via an external redirect must go before any existing rewrites, near the top of the file.
Note that this removes index.php from the URL regardless of whether the requested URL actually maps to a real file or whether the preceding URL-path even exists as a physical directory. So, /<something>/index.php is redirected to /<something>/ regardless of whether /<something>/ is a physical directory or not. This check can be implemented at the cost of an additional filesystem check - but it's probably not required.
NB: Test first with a 302 (temporary) redirect to avoid potential caching issues. Only change to a 301 (permanent) redirect once you have tested that it works as intended.
UPDATE#1:
These Questions do not provide an answer:
htaccess redirect index.php to root (including subdomains)
This does not address subdirectories, only subdomains
This redirects example.tld/dir/index.php to example.tld/, but I need example.tld/dir/
Actually, the first question you've linked to does answer your question, with regards to removing index.php from the requested URL. It does address subdirectories and would redirect example.tld/dir/index.php to example.tld/dir/ (not example.tld/ as you've stated).
The part of the question that discusses subdomains is a bit misleading as it doesn't really have anything to do with subdomains specifically.
The solution presented in the linked question basically does the same sort of thing as I've done above, except that it arguably matches too much (and not enough). It would incorrectly/unnecessarily redirect /fooindex.php to /foo (no trailing slash) and would fail to redirect URLs that contained path-info (which could be malicious). eg. /foo/index.php/bar would fail to redirect but still serve the contents of /foo/index.php (unless AcceptPathInfo had been disabled). Although whether these "errors" would actually cause an issue in your case is another matter.
UPDATE#2:
I have the code exactly in the directory for example.tld/dir
The code above assumes the .htaccess file is located in the document root. If the .htaccess file is located in the directory of where the app is installed then you would need to modify the above like so:
# Remove "index.php" from any URL and redirect back to the "directory"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_URI} ^/(.+/)?index\.php
RewriteRule (^|/)index\.php(/|$) /%1 [R=301,L]
The %1 backreference (as opposed to $1) refers to the captured group in the preceding CondPattern. This naturally includes the full URL-path, so avoids having to hardcode the directory in which the .htaccess file is located.
This applies to the directory that contains the .htaccess file and any subdirectories thereof. Note that, by default, this completely overrides any mod_rewrite directives that might be present in the parent .htaccess file (mod_rewrite directives are not inherited by default).
...including subdirectories, which may have their own .htaccess and index.php.
If additional sub-subdirectories have their own .htaccess file then this may or may not work depending on the directives used in these sub-subdirectory .htaccess files and/or how mod_rewrite inheritance is configured.
mod_rewrite directives do not inherit by default. So, if the .htaccess file in the sub-subdirectory enables the rewrite engine then the above mod_rewrite directives in the parent directory will be completely overridden (they are not even processed).
If, on the other hand, the .htaccess file in the sub-subdirectory uses directives from other modules then this may not be an issue.

Related

Restrict access to TYPO3 backend via .htaccess

I'm trying to restrict access to the TYPO3 backend and the install tool. Beacause of that, the IPMaskList isn't the best thing to do so. I tried an .htaccess file in the /typo3 directory and it worked quite well to certain point. The following code was used to accomplish that:
RewriteEngine On
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteRule ^(.*)$ https://example.com [R=301]
Only the computer with the listed ip can access the index.php or install.php, which is very good. But as soon as I click the login button, and the URL changes to https://example.com/typo3/login?loginProvider=1433416747, it throws a 404 error. First, I thought it was the configured IP, as the server is requesting a page, and not my computer, but I don't know how to implement that.
The problem might just be that you are missing the L flag on the RewriteRule. The missing L flag will cause processing to continue through the remaining directives which probably includes a front-controller pattern. Typo3 then generates a 404 because https://example.com is not a valid "Typo3" URL.
But also...
First, I thought it was the configured ip, as the server is requesting a page, and not my computer,
If the server itself is also making an HTTP request (although not sure why) then you will also need to permit the server's IP address in your rule. For example:
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteCond %{REMOTE_ADDR} !=<server_ip>
RewriteRule ^ https://example.com/ [R=301,L]
Additional changes:
Missing L flag. (Mentioned above)
Missing trailing slash after the hostname (the browser "corrects" it).
No point capturing the URL-path in the RewriteRule pattern.
Although if you simply ant to restrict access then why not serve a "403 Forbidden" instead. Change the RewriteRule accordingly:
:
RewriteRule ^ - [F]
(L flag not required here.)
UPDATE:
No, by default there's no .htaccess in that dir, only the one in the root dir. Only with a .htaccess in the typo3 dir it's resulting in a 404. That's my only content in this particular .htaccess.
By enabling the rewrite engine in the subdirectory then it's going to completely override any mod_rewrite directives in the parent .htaccess file (by default), regardless of whether you are accessing the site by your IP or not. It would seem there are mod_rewrite directives in the parent/root .htaccess file that are required for your Typo3 installation to function (a front-controller pattern perhaps). (I had assumed these were all in the /typo3/.htaccess file.)
There are two solutions:
Move the above rule to the top of the root .htaccess file, adjusting accordingly. And delete the /typo3/.htaccess file. For example:
# In the root ".htaccess" file
RewriteCond %{REMOTE_ADDR} !=<my_ip>
RewriteRule ^typo3(/|$) - [F]
OR
Don't use mod_rewrite to block the request. For example, use an Apache expression with mod_authz_core instead. For example:
# In the "/typo3/.htaccess" file
<If "! -R '<my_ip>'">
Require all denied
</If>

.htaccess need help to serve requests to index.php in non root folder

I have a specific website structure:
root:
styles.css
pages/index.html
folder_with_assets_1
folder_with_assets_2
folder_with_images
I've renamed index.html to index.php in order to get rid of .html extension in the URL
But the problem is that index.php is located not in a root folder, it's in pages folder.
Which right .htaccess rules could solve the problem in order to redirect requests to pages folder?
UPDATE
the screenshot with folder structure:
On the face of it, this just looks a standard front-controller pattern. Whether the front-controller is located inside a subdirectory or directly in the document root is largely irrelevant - the process is the same.
Assuming you are using the .htaccess file in the document root and there is no discernable pattern to the page URLs...
For example, using mod_dir FallbackResource:
FallbackResource /pages/index.php
Or, using mod_rewrite:
DirectoryIndex /pages/index.php
RewriteEngine On
RewriteRule (^|/)index\.php - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . pages/index.php [L]
UPDATE#1:
It's "onepage" website format with plenty of JS and CSS. There are only local URLs pointing to sections (href tag) and AJAX call to specific PHP files
In that case, it just looks like you need to change the DirectoryIndex - you don't need a front-controller pattern (as discussed above) at all.
For example:
DirectoryIndex /pages/index.php
Now, a request for the "homepage", ie the document root https://example.com/ will serve /pages/index.php.
UPDATE#2:
From your screenshot, it looks like directory listings (mod_autoindex) are enabled. These should be disabled at the top of the .htaccess file:
Options -Indexes
UPDATE#3:
From your screenshot, it would seem that what you have called "root" in your file structure is not actually your website's "document root", since you are accessing this location via a /test subdirectory, ie. localhost/test/. The directives above are assuming these files are located in the "document root", ie. localhost/ and there is no /test subdirectory. (Which I expect is how it is structured on your "live" environment?)
If your .htaccess file is located in the /test subdirectory and you are requesting localhost/test/ (as per your screenshot) then you will need to adjust this accordingly:
For example:
DirectoryIndex /test/pages/index.php
However, that will not work on the live site (assuming you don't have a /test subdirectory on live). Instead, you can simply omit the slash prefix, to make it relative.
For example:
DirectoryIndex pages/index.php
This should work OK in your case since you have a SPA (just a homepage URL).

Use .htaccess to redirect root to two different directories

I'm developing a website that has to co-exist with another one on an existing server. I know it's not an ideal situation but for timing reasons we don't really have any choice.
Request coming to the root of the URL have to be routed to the index.html of the new website, and everything else has to go the index.html of the old website (both of the websites are using react so every route goes to index.html).
I've tried to write a .htaccess doing this but with no success so far.
Here's an example of how it's supposed to work :
I have two folders, old/ and new/ each containing a website.
if a user goes to http://example/ -> it's serving content from the new/ folder.
if a user goes to http://example/test -> it's serving content from the old/ folder.
Below is what I've tried. It redirects / to the new/ folder, but rewrites the URL doing so. Furthermore, as soon as I try to redirect /* to the old/ folder things stop working.
# Turn rewriting on
Options +FollowSymLinks
RewriteEngine On
# Redirect requests to index.php
RewriteCond %{REQUEST_URI} ^$
RewriteRule ^$ new [L]
Try the following instead:
Options +FollowSymLinks
RewriteEngine On
# Rewrite the root only to new/index.html
RewriteRule ^$ new/index.html [L]
# Rewrite other URLs to old/index.html
RewriteRule . old/index.html [L]
You should rewrite directly to the file that is handling the request. If you rewrite to new only - without a trailing slash - then mod_dir will issue an external redirect to append the slash.
NB: This does assume that you have another .htaccess file in the /old/ subdirectory that contains mod_rewrite directives (a front-controller), otherwise everything (including static resources) will be rewritten to /old/index.html.
It redirects / to the new/ folder, but rewrites the URL doing so
I think you are using the terms "redirect" and "rewrite" the wrong way round. A "rewrite" is internal to the server, the URL does not change. This is what you are doing here... rewriting from root to /new/index.html etc.
However, a "redirect" is an external HTTP redirect that triggers a 3xx response and a second request to the server.

.htaccess rewrite directories with index.html to subdirectory

At the site were some directories with html files like:
site.com/folderone/index.html
site.com/foldertwo/index.html
and it was available by links like:
site.com/folderone
site.com/foldertwo
now all these directories moved to /old-pages:
site.com/old-pages/folderone/index.html
site.com/old-pages/foldertwo/index.html
but old links should be available, so .htaccess file:
RewriteEngine on
RewriteRule ^folde(.*)$ /old-pages/folde$1 [L]
it's rewrite correct site.com/folderone/ and site.com/folderone/index.html
the problem is: for site.com/folderone it's not rewrite but redirect to site.com/old-pages/folderone/
The redirect is probably happening because of mod_dir and the DirectorySlash directive, which redirects requests for a directory that is missing the trailing slash so that the trailing slash is there. There's a good reason why that happens, as there's a info disclosure security concern without the trailing slash.
What you can do to avoid the redirect is either turn it off (not recommended):
DirectorySlash Off
or include the slash via mod_rewrite so that the two modules won't interfere with each other over the same request:
RewriteRule ^folder([^/]+)$ /folder$1/ [L,R=301]
You must add that before your other rewrite rules so that it gets applied first. Then your other rule should work.

htaccess rule - Take the Place of Symlinked Files

I'm working on this legacy project that has a rather odd setup that I'm looking to get rid of but my htaccess skills are a little lacking in this department.
Here's the directory structure.
/index.php
/www
page1.php -> symlink to index.php
page2.php -> symlink to index.php
page3.php -> symlink to index.php
/www is the public directory and people visit http://site/page1.php. However, each of those files with an * actually symlinks to /index.php.
I find this arrangement idiotic and would like to get rid of the symlinks and simply have any /www/*.php request simply point at index.php without the page actually redirecting to index.php.
Any ideas for an htaccess rule(s) that could solve this problem? At its most basic core, I'd like to keep the same functionality without having to have a thousand symlinked files.
It looks like the index.php file is not in your document root (which I'm assuming is www), and because of that, I don't think there's a way you can do this from your .htaccess file. In order to access something outside of your document root, you'll need to setup an alias in either your server config or your vhost config:
# Somewhere in vhost/server config
Alias /index.php /var/www/path/to/index.php
# We need to make sure this path is allowed to be served by apache, otherwise
# you will always get "403 Forbidden" if you try to access "/index.php"
<Directory "/var/www/path/to">
Options None
Order allow,deny
Allow from all
</Directory>
Now you should be able to access /var/www/path/to/index.php. Note that other files in the /var/www/path/to directory is safe as long as you don't create an Alias (or AliasMatch or ScriptAlias) that points to them. Now that you can access index.php via the /index.php URI, you can setup some mod_rewrite rules in the .htaccess file in your document root (www) to point things to index.php:
# Turn on the rewrite engine
RewriteEngine On
# Only apply the rule to URI's that don't map to an existing file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Rewrite all requests ending with ".php" to "/index.php"
RewriteRule ^(.*)\.php$ /index.php [L]
This will make it so when you request http://site/page1.php, the browser's address bar is unchanged but the server actually serves /index.php, which is aliased to /var/www/path/to/index.php.
You can tweak the regular expression ^(.*)\.php$ to something more appropriate if need be. This just matches anything that ends with a .php, including /blah/bleh/foo/bar/somethingsomething.php. If you want to limit the directory depth, you can tweak the regular expression to ^([^/]+)\.php$, etc.

Resources