Stripping trailing slash in URL doesn't work in subdirectory - apache

The following rule works to remove the trailing slash for all pages in my web root:
RewriteRule ^(.+)/$ /$1 [L,R=301]
However, it does not work when placed in a sub folder. I've also tried:
RewriteRule (.*)/$ /$1 [L,R=301]
to no avail. What happens is, it redirects
http://example.com/testfolder/testpage/
to
http://example.com/testpage
What am I missing? Thanks in advance!

Have you tried omitting the leading slash from your replacement?
RewriteRule ^(.+)/$ $1 [L,R=301]
It's just a stone's throw from what you have. The context of the directory rewrite (being "in" /testfolder) may be the root cause of the trouble.

you may be able to define this in variables also make sure Rewrite mods are enabled in your php.ini if there is no other way of doing what you need.

The trailing slash fixup is being done by mod_dir. Rewrites in your per-directory context are re-injected into the URL processing chain and subject to the fixup again.
The behavior is configurable. E.g.
<Directory /path/to/wherever>
DirectorySlash Off
...
</Directory>
The context for this is not only Directory: it is server config, virtual host, directory, .htaccess.

Related

How can I create a redirect with .htaccess to correct path instead of page acess

I am making a multilingual dynamic site that creates a virtual path per language.
So french pages go to domain.com/fr/ english domain.com/en/page domain.com/fr/some/page but in reality these pages are in the base folder and /fr/ is converted to a query string.
This is all working with the following .htaccess:
RewriteEngine on
DirectorySlash Off # Fixes the issue where a page and folder can have the same name. See https://stackoverflow.com/questions/2017748
# Return 404 if original request is /foo/bar.php
RewriteCond %{THE_REQUEST} "^[^ ]* .*?\.php[? ].*$"
RewriteRule .* - [L,R=404]
# Remove virtual language/locale component
RewriteRule ^(en|fr)/(.*)$ $2?lang=$1 [L,QSA]
RewriteRule ^(en|fr)/$ index.php?lang=$1 [L,QSA]
# Rewrite /foo/bar to /foo/bar.php
RewriteRule ^([^.?]+)$ %{REQUEST_URI}.php [L]
My problem is that some sites (Like a Linkedin post) somehow remove the trailing / in the index page automatically. So if I put a link in my post of domain.com/fr/ somehow they make the link domain.com/fr even if it shows domain.com/fr/ but that 404's as domain.com/fr dosent exist.
So how can I redirect domain.com/fr to domain.com/fr/ or localhost/mypath/fr (There's many sites in my local workstation) to localhost/mypath/fr/.
I tried something like:
RewriteRule ^(.*)/(en|fr)$ $1/$2/ [L,QSA,R=301]
RewriteRule ^(en|fr)$ $1/ [L,QSA,R=301]
But that ended up somehow adding the full real computer path in the url:
localhost/mypath/fr becomes localhost/thepathofthewebserverinmypc/mypath/fr/
I would very much appreciate some help as I have yet to find the right rule.
Thank you
RewriteRule ^(en|fr)$ $1/ [L,QSA,R=301]
You are just missing the slash prefix on the substitution string. Consequently, Apache applies the directory-prefix to the relative URL, which results in the malformed redirect.
For example:
RewriteRule ^(en|fr)$ /$1/ [L,R=301]
The substitution is now a root-relative URL path and Apache just prefixes the scheme + hostname to the external redirect. (The QSA flag is unnecessary here, since any query string is appended by default.)
This needs to go before the existing rewrites (and after the blocking rule for .php requests).
Note that the "internal rewrite" directives are correct to not have the slash prefix.
Aside:
DirectorySlash Off
Note that if you disable the directory slash, you must ensure that auto-generated directory listings (mod_autoindex) are also disabled, otherwise if a directory without a trailing slash is requested then a directory listing will be generated (exposing your file structure), even though there might be a DirectoryIndex document in that directory.
For example, include the following at the top of the .htaccess file:
# Disable auto-generated directory listings (mod_autoindex)
Options -Indexes
UPDATE:
this worked on the production server. As the site is in the server root. Would your know how can I also try and "catch" this on my localhost ? RewriteRule ^(.*)/(en|fr)$ /$1/$2/ [L,R=301] dosent catch but with only RewriteRule ^(en|fr)$ /$1/ [L,R=301] localhost/mypath/fr becomes localhost/fr/
From that I assume the .htaccess file is inside the /mypath subdirectory on your local development server.
The RewriteRule pattern (first argument) matches the URL-path relative to the location of the .htaccess file (so it does not match /mypath). You can then make use of the REQUEST_URI server variable in the substitution that contains the entire (root-relative) URL-path.
For example:
RewriteRule ^(en|fr)$ %{REQUEST_URI}/ [L,R=301]
The REQUEST_URI server variable already includes the slash prefix.
This rule would work OK on both development (in a subdirectory) and in production (root directory), so it should replace the rule above if you need to support both environments with a single .htaccess file.

.htaccess to show a directory index.html without a trailing slash

I've got a Jekyll generated site running on an Apache server and I'm having some trouble getting my .htaccess file set up correctly. Jekyll places index.html files into folders which represent each page so my URLs currently look like domain.com/foo/
I'd like to remove that trailing slash from the URL so that it exactly matches what I had set up previously (and also because I think it looks better).
Currently the section of my .htaccess file dealing with rewites looks like:
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
</IfModule>
Options -Indexes
DirectoryIndex index.xml index.html
I have tried following the advice here but that puts me into a redirect loop.
Can anybody help me out? In brief, what I want is for a domain.com/foo URL to show the index.html file form the /foo directory and for domain.com/foo/ and domain.com/foo/index.html to redirect to domain.com/foo.
You should be able to use this to turn off the addition of slashes.
DirectorySlash Off
Note that the trailing slash is added for a good reason. Having the trailing slash in the directory name will make relative URLs point at the same thing regardless of whether the URL ends with "foo/bar/index.html" or just "foo/bar/". Without the trailing slash, relative URLs would reference something up one level from what they normally point at. (eg: "baz.jpg" would give the user "/foo/baz.jpg" instead of "/foo/bar/baz.jpg", as the trailing "bar" will get removed if it isn't protected by a trailing slash.) So if you do this, you probably want to avoid relative URLs.
To then rewrite the directory name to return the index.html you could probably do something like this:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}/index.html -f
RewriteRule ^(.*)$ /$1/index.html [L]
This checks if REQUEST_URI/index.html exists, and if it does performs an internal redirect.

htaccess rewrite of directory to variable fails on localhost

Let's take something like this question. So, I'm looking to rewrite:
http://www.example.com/test to
http://www.example.com/page.php?v=test
with:
RewriteRule ^(.*)$ page.php?v=$1 [L]
This takes me to the page http://www.example.com/test/?v=test
Why does it not stay on http://www.example.com/test without the trailing slash and the query string.
PS: I'm using WampServer on Windows
in RewriteRule don't put / and the begining!
RewriteRule ^(.*)$ page.php?id=$1 [L]
The problem arises if test is an existing directory on the server. Apache then uses the DirectorySlash Directive to "fix up" the URL pointing to the directory by adding a trailing slash.
I'm answering my own question here, but the solution (as the above link states) is to add DirectorySlash Off to .htaccess

Who adds a slash at the end of my url?

I'm using mod_rewrite to rewrite /products to /products.php. I've got this code in /.htaccess
Options FollowSymLinks
RewriteEngine on
RewriteRule ^([a-zA-z]+)$ /$1.php [PT,L]
Unfortunately there is also a folder /products/ on my server.
My problem is, when I try to access http://mydomain.com/products my request is redirected to http://mydomain.com/products/ and showing me an error because I don't have an index for that directory.
Who is redirecting me? Apache, my UserAgent?
How do I prevent that this happens without changing the folder name or the rewrite rule?
You need to look up the "DirectorySlash Directive".
The DirectorySlash directive
determines whether mod_dir should
fixup URLs pointing to a directory or
not.
http://httpd.apache.org/docs/2.2/mod/mod_dir.html
You could also try adding an optional slash to you rewrite rule:
RewriteRule ^([a-zA-z]+)/?$ /$1.php [PT,L]
Trailing slashes problem
You have probably enabled MultiViews on your Apache.
Every browser is adding the trailing slash after your request if it doesn't by ".something" because it thinks it is a folder. To avoid this, your rewrite rule should look like this:
RewriteRule /products(.*)$ /index.php?page=products
OR
RewriteRule /products /index.php?page=products
That way, it will rewrite every request with "/products" in it, with or without the trailing slash.
The only thing is your folder /products/ will not be accessible by an http request. If you want so, you must change the name of the folder or the page name.

Trailing slashes problem

When I type this "http://example.com/Hello%20There/" , it displays the
index page wich is : "http://example.com/Hello%20There/index.html" .
Well, what I want to do is when the user types "http://example.com/Hello%20There"
(so like the first one except it doesn't have a trailing slash).
I tried many things and specially regular expressions, but nothing works because I think
that the server stops the reg exp process when he finds a space ("%20" in the URL).
I tried this reg exp:
Options +FollowSymLinks
rewriteEngine On rewriteCond %{REQUEST_URI} ^(.*)\ (.*html)$
rewriteRule ^.*$ %1-%2 [E=space_replacer:%1-%2]
rewriteCond %{ENV:space_replacer}!^$
rewriteCond %{ENV:space_replacer}!^.*\ .*$
rewriteRule ^.*$ %{ENV:space_replacer} [R=301,L]
and also put:
DirectorySlash On
in the "mod_dir" module of Apache.
So, my question is:
- How to tell to the server to add a trailing slash when the user types an url
without a trailing slash;$
You can make a character optional by appending the ? quantifier to it like this:
RewriteRule ^([^/]+)/?$ $1/index.html
Now both /foobar and /foobar/ would be rewritten to /foobar/index.html.
But it would be better if you use just one spelling, with or without the trailing slash, and redirect the other one:
# remove trailing slash
RewriteRule (.+)/$ /$1 [L,R=301]
# add trailing slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .*[^/]$ /$1/ [L,R=301]
These rules either remove or add a missing trailing slash and do a permanent redirect.
I had the same problem, but I was using mod_alias to set up a subsite. Turns out, I needed to make a second alias without the trailing slash so that it would work correctly. Looked something like this:
Alias /forum/ "/var/www/forum"
Alias /forum "/var/www/forum"
<Directory "/var/www/forum">
Options FollowSymlinks
AllowOverride None
Order allow,deny
Allow from all
</Directory>
In Ubuntu, I had to edit the /etc/apache2/mods-enabled/alias.conf file with these lines, then restart apache. Couldn't find this answer anywhere on the web; I just stumbled onto it myself as mod_rewrite wasn't working and the DirectorySlash command didn't help either. I was appending a non-Drupal program as a subsite under a Drupal installation, which is what kicked off all this madness in the first place...
Don't use trailing slash to define an alias.
Both URLs http://example.com/myalias1 and http://example.com/myalias1/ would work fine.
Example:
sudo vi /etc/apache2/apache2.conf
Alias /myalias1 "/path/to/folder1"