htaccess RewriteRule doesn't work properly if no trailing slash - php

I am trying to redirect one subdirectory to another using RewriteRule in the main directory's .htaccess file.
For example: http://website.com/subdir should rewrite to http://website.com/another_dir/destination_dir but the user should still see http://website.com/subdir in the address bar.
This works perfectly if the user ends the URL with a trailing slash. Example: http://website.com/subdir/ (Generates a 200
However, if the slash is omitted, a 301 redirect is generated and we see the undesired destination directory. For example, http://website/subdir redirects the user to http://website/another_dir/destination_dir
Here are the pertinent parts of .htaccess:
# URL Rewriting:
RewriteEngine On
RewriteBase /
...
# Redirect subdirectories:
RewriteRule ^subdir(.*)$ another_dir/destination_dir$1 [PT,NC,QSA,L]
Any assistance is appreciated!

You can adjust the regex in your rewrite rule to optionally match a slash.
RewriteRule ^subdir(/?.*)$ another_dir/destination_dir$1 [PT,NC,QSA,L]
Note the /? just after subdir. This says that there may or may not be a slash just after your subdir, so the regex will match either way.

A quick fix would be
DirectorySlash OFF in this htaccess, and DirectorySlash ON a .htaccess in another_dir/

Related

htaccess - Force a slash to the end of a dynamic URL

I have a single index.php file in a /slug subdirectory and would like to load dynamic content based on the file path. Regardless of what the url is, the content should reference that index.php.
In my code below, the slash is not being added at the end of the url. For example, example.com/slug/33 should be displayed in the address bar as example.com/slug/33/.
I have the following .htaccess in /slug:
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
I tried adding a / between index.php and ?path=$ but I'm not getting the desired result. Is this even possible?
RewriteRule ^(.*)$ /slug/index.php/?path=$1 [NC,L,QSA]
Changing the substitution string here changes the target of your internal rewrite - it does nothing to change the visible URL. By adding a slash after index.php you are (unnecessarily) adding additional pathname information (path-info) to the resulting URL that your application receives.
To change the visible URL (to append the slash) you need to implement an external redirect. However, to confirm... you must already be linking to the correct canonical URL (ie. with a slash) in your internal links. Appending the slash to the URL in .htaccess is only if you have changed the URL and search engines or 3rd parties are still using the old non-canonical URL (without a trailing slash).
Since the .htaccess file is in the /slug subdirectory and you are rewriting to index.php in that subdirectory then you don't need to prefix the rewritten URL with /slug/. By default, a relative URL-path is relative to the directory that contains the .htaccess file. However, you must also remove the RewriteBase directive (or set this "correctly" to RewriteBase /slug).
To redirect to append a trailing slash you can add the following before the current rewrite:
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.]+)$ /slug/$1/ [R=301,L]
This requires the /slug/ prefix on the substitution string (unless RewriteBase /slug is set), otherwise the external redirect will attempt to redirect to a file-path, which will "break".
The RewriteRule pattern ^(.*(?:^|/)[^/.]+)$ captures URL-paths that do not already end in a slash and do not contain a dot in the last path segment. This is to avoid matching URLs that already contain (what looks-like) a file extension, ie. your static resources (images, CSS, JS, etc.). This should avoid the need for a filesystem check (which are relatively expensive) - to check that the request does not already map to a file. Although, if you are not referencing any static resources with the /slug/ prefix in the URL then this can be simplified.
NB: You should first test with a 302 (temporary) redirect to avoid potential caching issues.
In context (with the use of RewriteBase):
Options -Indexes
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /slug
# Append trailing slash if omitted
RewriteRule ^(.*(?:^|/)[^/.]+)$ $1/ [R=301,L]
# Dynamic url
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.+) index.php?path=$1 [QSA,L]
The use of RewriteBase avoids you having to specify /slug/ in the other directives.
In the regex ^(.*)$, the start-of-string (^) and end-of-string ($) anchors are superfluous. And you might as well change this to use the + quantifier, since you don't want to match the base directory anyway (saves two additional filesystem checks). The NC flag was also superfluous here.

Redirect entire sub-directory to root directory

So I am trying to clean up my search engine redirect errors. I had some old development sites that got indexed that I want to redirect to the main site.
Basically I want everything in the /dev/ folder to go to https://myfakewebsite.com/
I added this to .htaccess file in the /dev/ directory:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(.*)$ /$1 [R=301,L]
I tried this but it doesn't quite work, it does take out the /dev/ but it keeps the rest of the link there.
For example: https://myfakewebsite.com/dev/index.php?route=product/category&path=122
redirects to: https://myfakewebsite.com/index.php?route=product/category&path=122
I want it to redirect to: https://myfakewebsite.com/ (removing the /index.php?route=product/category&path=122 part).
Is there a way to do this with .htaccess?
You can use the following rule in your /dev/.htaccess
RewriteEngine on
RewriteRule (.*) / [L,R=301]
The rule above redirects all requests from /dev to the root of site ie . /dev/* => / including query strings from /dev?querystring to /?querystring . By default mod-rewrite appends old query string to the destination path so if you do not want it then you can use QSD flag in your rule or you can another rule to handle and remove QUERY_STRING .
You can use the following rules to redirect urls with and without query string to / . The ? at the end of the rule's destination discards the old query string.
RewriteEngine on
# redirect /dev?querystring to /
RewriteCond %{QUERY_STRING} .+
RewriteRule (.*) /? [L,R=301]
# redirect /dev/uri to /
RewriteRule (.*) / [L,R=301]
Make sure to clear your browser cache before testing these redirects.
You might want to achieve this kind of "trivial" redirect with the RedirectMatch directive from mod_alias, instead of doing this with mod_rewrite.
RedirectMatch 301 "/dev/(.*)" "/$1"
See documentation at https://httpd.apache.org/docs/2.4/mod/mod_alias.html.
You left the match results as part of the redirect on this line:
RewriteRule ^(.*)$ /$1 [R=301,L]
Specifically $1 as part of /$1 (the redirecting portion of the rule). Since this file is within the /dev directory it automatically removes /dev/ then applies the match to the redirect. Since you are using the capture ($1) as part of the rule, it'll take everything it matched after /dev/ (in your rule you should read it as ^/dev/(.*)$) and apply it to /$1, where $1 is whatever it "found" during ^(.*)$ in the previous step.
Try removing the pattern match, e.g.:
RewriteRule ^(.*)$ / [R=301,L]
Additionally, since you aren't using the results of the match you can remove the parenthesis (e.g. ^.*$). You can also put this .htaccess file in the root and simply redirect ^/dev(/?.*)$ to / depending on how you want to manage your subdirectories.

Access Drupal7 site in a subdirectory without trailing slash

I have a Drupal7 site hosted in a sub-directory and site can be access following with directory path and trailing slash:
http://mydomain.com/dir1/dir2/ (with the trailing slash).
I’m looking to access this site without the trailing slash:
http://mydomain.com/dir1/dir2
I tried with the DirectorySlash Off in the .htaccess file. But it gives Access forbidden error when accessing site without trailing slash.
Then I created a new .htaccess file in the ../dir1 and tried to rewrite the url to get the main page content when user access site without trailing slash.
<IfModule mod_rewrite.c>
DirectorySlash Off
RewriteEngine on
Options +FollowSymLinks
RewriteRule ^dir2$ dir2/index.php
</IfModule>
Again I’m getting the same issue “Access forbidden”. Is there anything to do in .htaccess file in Drupal root after setting these rules?
Any idea how to access Drupal site hosted in a sub-directory without trailing slash?
Try this. But I'm not tested it.
Basically the trick here is to use a 301-redirect to remove the trailing slash at the end of all your URL’s. The code to put in your .HTACCESS
#remove trailing slashes
RewriteCond %{HTTP_HOST} !^\.domain\.com$ [NC]
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]
There is a Drupal plugin also. According to their description looks like it will match to your requirement. Give a try.
https://drupal.org/project/globalredirect

How do I redirect specific URLs to specific pages using mod_rewrite?

I'd like to redirect localhost/website/setup to localhost/website/setup.php.
This is the mod_rewrite rule currently used:
RewriteRule ^setup/$ setup.php [L]
This works for redirecting localhost/website/setup/ to localhost/website/setup.php. However, as soon as the trailing slash is removed, it no longer works (it redirects me to localhost/setup/), even if I do not add the trailing slash in the rewrite rule. What am I doing wrong?
This part ^setup/$ is regular expressions so you can just do this
RewriteRule ^setup/*$ setup.php [L]

How do I get rid of the extra slash at the end of the url

I have this link and as you can see there is an extra / at the end. Basically i have a restaurant_pos folder with an index.php file in it but apache is adding the extra slash. I thought there was a way to do this in htaccess with directory directives off or something like that...not sure the name...any ideas
This should do the job for you (redirect if UR has trailing slash):
DirectorySlash Off
RewriteEngine On
RewriteBase /
# get rid of trailing slash
RewriteRule ^(.*)/$ $1 [R=301,L]
But you may have that extra slash added by some other rule in your .htaccess. If above will not help and you have some rewrite rules already in place -- please post them in your question.

Categories