.htaccess folder as parameter to root index.php - .htaccess

What I need is any subfolder to be passed as a parameter to the root index.php
This is the code and it actually works.
RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} -d
RewriteRule ^(.+?)(/[^/]*|)$ index.php?dir=$1/ [L,QSA]
There is a problem:
When the url is like this (no end slash after 'projects'):
http://example.com/projects
the rewrite rule changes the link in the address bar and it looks like this:
http://example.com/projects/?dir=projects/
Is there a chance the url in the address bar always stays the same(no matter if there is an end slash or not) so the dir parameter is not visible to the user?
I tried with multiple rules - the first one to add an end slash, and then the second rule to pass the directory as parameter, but with no luck so far.
EDIT: so far thanks to w3d I managed to get it working. In the .htaccess just add:
DirectorySlash Off

tl;dr Make the trailing slash mandatory in the RewriteRule pattern (and remove the DirectorySlash Off directive, ie. keep it On).
RewriteRule ^(.+)/$ index.php?dir=$1/ [L,QSA]
As suggested in comments, this "strange" redirect is the result of mod_dir's DirectorySlash On directive, which is On by default. This can be quickly resolved by including DirectorySlash Off at the top of your .htaccess file (or making the trailing slash mandatory - see above and below).
The DirectorySlash On directive instructs Apache to automatically append a slash to URLs that end in a file system directory. In this sense it is "fixing" the URL. mod_dir achieves this with a 301 external redirect.
So, what is actually happening in the above, when DirectorySlash is enabled, is:
Initial request:
/projects (no trailing slash)
Internal rewrite in .htaccess:
/index.php?dir=projects/ (note that the request URL is still /projects)
mod_dir now kicks in and "fixes" the initial request (/projects --> /projects/) by appending a slash to the end of the URL-path. However, the query string from the rewritten URL (above) is passed through:
/projects/?dir=projects/ (this is a 301 external redirect, ie. a new request!)
Internal rewrite in .htaccess (again - new request):
/index.php?dir=projects/&dir=projects/ (note that the request is still /projects/?dir=projects/)
The doubling of the dir=projects/ query param is a result of the QSA flag on the RewriteRule (which I assume is required for other requests?). Your PHP script simply sees a single dir GET param (the later overwrites the former), unless you included dir[]=$1/ in your RewriteRule and you will end up with a 2-element array!
Your RewriteRule pattern also looks unnecessarily complex. You could simply make the trailing slash optional. ie:
RewriteRule ^(.+?)/?$ index.php?dir=$1/ [L,QSA]
Alternatively, having said all the above, you should probably leave DirectorySlash On (default) and simply make the trailing slash mandatory! For example:
RewriteRule ^(.+)/$ index.php?dir=$1/ [L,QSA]
mod_dir will now kick in before your internal rewrite (since it won't match without a trailing slash). This is also better for canonicalising your URLs and there are also potential security risks with turning it off.
Reference:
http://httpd.apache.org/docs/2.2/mod/mod_dir.html#directoryslash

Related

Remove Trailing Slash With .htaccess

I've looked at 5 pages of Google, and StackOverflow, and I can't seem to find a way to remove the trailing slash on my domain using .htaccess. It uses Litespeed. Can anyone provide me with code I can add to my file? I'll reply to say whether or not it worked. Thanks!
they're physical directories.
You can't "simply" remove the trailing slash from physical filesystem directories. And I would recommend against trying to do so.
This is very different to trailing slashes on arbitrary "virtual" URLs that do not map to physical file-paths.
The trailing slash on directories is required by Apache to be able to correctly serve the DirectoryIndex document (mod_dir) and generate directory listings (mod_autoindex).
By default mod_dir explicitly appends the trailing slash to directories (if omitted) by issuing a 301 (permanent) redirect which is cached persistently by the browser.
In order to remove the trailing slash on directories (or prevent it from being appended) you need to override this default behaviour. But you must then manually append the trailing slash with an internal rewrite, so the URLs work as intended.
It is relatively trivial to prevent mod_dir appending the trailing slash:
# Prevent mod_dir from appending trailing slashes to directories
DirectorySlash Off
# Prevent mod_autoindex generating directory listings
Options -Indexes
Ensuring that directory indexes are disabled is an additional security measure when DirectorySlash Off is set, since without a trailing slash the presence of a DirectoryIndex document does not prevent mod_autoindex from generating a directory listing and exposing your file structure.
However, you now need to issue internal rewrites to "silently" append the trailing slash if a physical directory is requested without, for example:
# Append trailing slash on directories with an internal rewrite
RewriteCond $1 !/$
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule (.+) $1/ [L]
Having implemented the above you should already be requesting URLs/directories without the trailing slash. However, if you are changing this behaviour and the URL with the trailing slash has been indexed by search engines or linked to by third parties then you also need to implement an external redirect to remove the trailing slash in order to preserve SEO. For simplicity, I assume you would want to remove the trailing slash from all URLs (not just physical directories).
For example, the following would need to go before the above rewrite:
# Remove trailing slash if requested directly
# NB: Applies to ALL URLs, including directories
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)/$ /$1 [R=301,L]
The condition that checks against the REDIRECT_STATUS environment variable is required in order to prevent a redirect loop. We only want to redirect direct requests from the client and not rewritten requests by the later rewrite.
NB: Test with 302 (temporary) redirects to avoid potential caching issues.
You will need to clear your browser (and any intermediary) caches before testing.
However, as I noted at the top of my answer, unless you have a good reason for doing this then I would recommend against implementing this as you could encounter unexpected conflicts. At the end of the day, Apache needs that trailing slash on physical filesystem directories.
Aside:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
This removes the trailing slash from an arbitrary URL-path. This is your "standard" slash removal rule. However, this will not remove the trailing slash from physical directories, as you are trying to do. For two reasons:
The condition explicitly checks that the request does not map to a physical directory.
Removing the slash from a physical directory without first setting DirectorySlash Off will result in a redirect-loop since mod_dir will naturally try to append it again.
You can remove the trailing slash on your URL’s with the following in your .htaccess:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1 [L,R=301]
For your testing, i’d recommend using R=302 so it’s not a permanent redirect as some browsers will cache these indefinitely without a full cache clear and in prod use R=301.

Trying to stop urls such as mydomain.com/index.php/garbage-after-slash

I know very little about .htaccess files and mod-rewrite rules. Looking at my statcounter information today, I noticed that a visitor to my site entered a url as follows:
http://mywebsite.com/index.php/contact-us
Since there is no such folder or file on the website and no broken links on the site, I'm assuming this was a penetration attempt. What was displayed to the visitor was the output of the index.php file, but without benefit of the associated CSS layout.
I need to create a rewrite rule that will either remove the information after index.php (or any .php file), or perhaps more appropriately, insert a question mark (after the .php filename), so that any following garbage will be treated like a parameter (and will be gracefully ignored if no parameters are required).
Thank you for any assistance.
If you're only expecting real directories and real files that do exist, then you can add this to an .htaccess file. What it does is it takes a non-existent file or directory request and gives the user the index.php page with the original request as a query string. [QSA] appends any existing query string.
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?$1 [PT,QSA]
I found a solution, using information provided by AbsoluteZero as well as other threads that popped up on the right side of the screen as the solution came closer.
Here's the code that worked for me...
Options -Multiviews -Indexes +FollowSymLinks
RewriteEngine On
RewriteBase /
DirectorySlash Off
# remove trailing slash
RewriteRule ^(.*)\/(\?.*)?$ $1$2 [R=301,L]
# translate PATH_INFO information into a parameter
RewriteRule ^(.*)\.php(\/)(.*) $1.php?$3 [R=301,L]
# rewrite /dir/file?query to /dir/file.php?query
RewriteRule ^([\w\/-]+)(\?.*)?$ $1.php$2 [L,T=application/x-httpd-php]
I got the removal of trailing slash from another post on StackOverflow. However, even after removing the trailing slash, the rewrite rule did not account for someone appending what looks to be valid information after the .php file
(For example: mysite.com/index.php/somethingelse)
My goal was to either remove the "/somethingelse", or render it harmless. The PATH_INFO rule locates a "/" after the .php file, and turns everything else from that point forward into a query string (which will usually be ignored by the PHP file).

mod_rewrite existing directory changes URL in address bar

I'm trying get mod_rewrite to redirect all requests that aren't files to index.php so I can handle routing for clean URLs.
<IfModule mod_rewrite.c>
RewriteEngine On
# Route requests to index.php for processing
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ index.php?request=$1 [QSA,L]
</IfModule>
For some reason, when I access an existing directory without a trailing slash, the address bar is reformed to include a trailing slash and the query string, which is not very clean.
I'm able to improve this by changing the RewriteRule to ^(.+)/$ and adding RewriteBase /. However, this directs all URLs to one with a trailing slash. Not a big deal, but not how I want it.
If, for example, /test/folder exists and I go to that directly, I'd like the address bar to display that, instead of displaying /test/folder/ or /test/folder/?request=/test/folder.
I'd give this a try:
DirectoryIndex index.php
<IfModule mod_rewrite.c>
RewriteEngine On
# I tested this inside a subdir named "stack", so I had to uncomment the next line
#RewriteBase /stack
# Route requests to index.php for processing
# Check if the request is NOT for a file:
RewriteCond %{REQUEST_FILENAME} !-f
# Check if the request IS for an existing directory:
RewriteCond %{REQUEST_FILENAME} -d
# If all criteria are met, send everything to index.php as a GET request whose
# key is "request" and whose value is the entire requested URI, including any
# original GET query strings by adding QSA (remove QSA if you don't want the
# Query String Appended):
RewriteRule .* index.php?request=%{REQUEST_URI} [R,L,QSA]
</IfModule>
If this doesn't happen to work, please let me know what else is in your .htaccess file because for the most part, it looks like it should be working. Should. ;)
Well, persistence pays off. jerdiggity's answer provided insight, which led to further experimentation and research. Eventually, I came to the conclusion that there must be something built into Apache that is rewriting the trailing slash.
As jerdiggity suspected, all of the Rewrite logic was accurate, but something called a DirectorySlash Directive in another directory-related Apache module, mod_dir, was adding the trailing slash.
Apparently, you can simply disable this directive, which I added to the top of my logic:
DirectorySlash Off
RewriteEngine On
...

Rewriten URL without trailing slash?

RewriteEngine on
RewriteRule ^$ http://my-site.com/directory [R=301,L]
This redirects my root page to
http://my-site.com/directory/
(notice the trailing slash).
How can I make .htaccess omit the trailing slash when generating the URL?
This is because directory is an existing directory, this is not a rewritten url.
Use another word instead of :
RewriteEngine on
RewriteRule ^$ /mypath [R=301,L]
RewriteRule ^mypath$ /directory/ [L]
Quote from noupe.com :
The filesystem on your server will always take precedence over the
rewritten URL. For example, if you have a directory named “services”
and within that directory is a file called “design.html”, you can’t
have the URL redirect to “http://domain.com/services”. What happens is
that Apache goes into the “services” directory and doesn’t see the
rewrite instructions.
To fix this, simply rename your directory (adding an underscore to the
beginning or end is a simple way to do that).
Bonus : To remove trailing slash in every urls :
RewriteEngine On
RewriteRule ^(.*)/$ $1 [R,301,L]

rewriterule how to handle no ending slash

I try to redirect anything coming into a directory to another. the rewriterule command I use is :
RewriteRule ^VirtualDirectory(.*)$ GENS/RealDirectory$1 [L,NC]
The thing is that I'd like that a query with no end slash to VirtualDirectory to be rewritten as if the query was for VirtualDirectory/
The behaviour I get is :
query to VirtualDirectory/ works great without the user noticing
query to VirtualDirectory workd great but the url shown in the brwoser is : GENS/RealDirectory/
I've tried many things but I can't get the behaviour I want.
If I add a rule
RewriteRule ^VirtualDirectory$ GENS/RealDirectory/ [L,NC]
to handle that specific case, it works great except that all resources of the page are rewrited to the folder before VirtualDirectory
What's happening is the internal rewrite is happening without a trailing slash, then mod_dir takes over and does a browser redirect to the same URL but with a trailing slash. You can turn off mod_dir by using DirectorySlash Off in your .htaccess file. If you want the trailing slash always, try changing the rule to this:
RewriteRule ^VirtualDirectory/?(.*)$ GENS/RealDirectory/$1 [L,NC]

Resources