RewriteRule htaccess to always remove trailing slash even directory - php

The target is to combine several rules:
never have a trailing slash in the URI
internally rewrite to the index.php (domain.tld/somedir/index.php) when calling domain.tld/somedir
remove file extensions, check if + '.php' exists and eventually internally rewrite to it
This is to be done in '.htaccess' as this is my only accessible .
My attempt so far
# check if *.php exists
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*[^/])/?$ $1.php [L, QSA]
# do not allow trailing slash
RewriteRule (.*)/ $1 [L, R=301]
The difficulty here is that the query 'domain.tld/somedir' normally calls the directory's index.php after having been redirected to 'domain.tld/somedir/'. However, I would like the index.php to be internally called (no 301) directly when querying 'domain.tld/somedir'.

You can use this code:
DirectoryIndex index.php
RewriteEngine On
# remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{THE_REQUEST} \s(.+?)/+[?\s]
RewriteRule ^(.+?)/$ /$1 [R=301,L]
# To internally forward /dir/file to /dir/file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f [NC]
RewriteRule ^(.+?)/?$ /$1.php [L]

There is a separate setting in apache called DirectorySlash that can be enabled/disabled. You can read more at httpd.apache.org/docs/2.2/mod/mod_dir.html#directoryslash but be sure to read the part about why this is done right below where it says "some good reasons". Also note the security issue.

Related

Remove query string parameter to create a more user-friendly URL

I have this .htaccess file and I have no knowledge with mod_rewrite,
RewriteEngine On
RewriteRule ^(.+[^/])/$ http://%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{THE_REQUEST} \s/([^.]+)\.php [NC]
RewriteRule ^ /%1 [NE,L,R]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)/?$ /$1.php [L]
What I want to achieve is to have localhost/viewticket/${id} instead of localhost/viewticket.php?id=123
I have tried many .htaccess rules but none worked except this one that hides .php in my URL.
I created this one for you, just erase yours and copy this one enjoy^^
IndexIgnore */*
Options FollowSymLinks
AddDefaultCharset utf-8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^viewticket/([^/]+)/?([^/]*)/?([^/]*)$ viewticket.php?id=$1&param2=$2&param3=$3 [L]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)/?$ /$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule . index.php [L]
</IfModule>```
Make sure you've changed your internal URLs so you are linking to /viewticket/<id>. Then add the following at the top of the root .htaccess file:
# Prevent MutliViews rewriting "viewticket" and omitting the URL parameter
Options -MultiViews
RewriteEngine On
# Redirect any direct requests to "/viewticket.php?id=<id>" to "/viewticket/<id>"
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{QUERY_STRING} ^id=(\d*)
RewriteRule ^(viewticket)\.php$ /$1/%1 [R=301,L]
# Rewrite "/viewticket/<id>" to "viewticket.php?id=<id>"
RewriteRule ^(viewticket)/(\d*)$ $1.php?id=$2 [QSA,L]
If you are not expecting any query string on your "pretty" /viewticket/<id> URL then remove the QSA (Query String Append) flag in the last rule.
$1 is a backreference to the first capturing group (parenthesised subpattern) in the RewriteRule pattern. Likewise, %1 is a backreference to the first capturing group in the last matched CondPattern (RewriteCond directive).
Always test first with 302 (temporary) redirects to avoid potential caching issues and only change to a 301 (permanent) redirect when you are sure everything is working as intended. Clear your browser cache before testing.
Reference:
https://httpd.apache.org/docs/2.4/rewrite/intro.html
https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html#rewriterule
Additional:
RewriteEngine On
RewriteRule ^(.+[^/])/$ http://%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{THE_REQUEST} \s/([^.]+)\.php [NC]
RewriteRule ^ /%1 [NE,L,R]
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)/?$ /$1.php [L]
Your existing directives (that remove the trailing slash and .php extension) are not quite correct.
Your first rule that unconditionally removes the trailing slash will also "try" to remove the trailing slash from directories as well - which will conflict with mod_dir and result in a redirect loop. The negated character class [^/] (to match a non-slash character) in the middle of the regex would seem to be superfluous. This also redirects to HTTP (not HTTPS)?
The second rule that removes the .php extension would also erroneosuly match .php should it appear in the query string portion of the URL. eg. /foo?bar.php would be redirected to /foo?bar. Although the regex ([^.]+) does avoid the perhaps more common case of /foo.php?bar.php being erroneously redirected.
The third rule that appends the .php extension via an internal rewrite could potentially result in a rewrite-loop (500 Internal Server Error) if you received a request of the form /foo/bar and /foo.php exists in the root of the filesystem. Also, the (optional) trailing slash is also captured by the capturing subgroup, since the * quantifier is greedy. This would also result in a malformed rewrite, if it wasn't for the first rule that removes the trailing slash. (But since the trailing slash is removed then the optional trailing slash in this rule is redundant.)
If you still need these rules to remove the trailing slash and handle extensionless .php URLs then have these rules as follows. Make sure you are already linking to the extensionless URLs internally. These rules should follow the rule block I posted above.
# Remove trailing slash
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ http://%{HTTP_HOST}/$1 [R=301,L]
# Remove ".php" extension if present on the initial request
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule (.+)\.php$ /$1 [R=301,L]
# Append ".php" extension if request maps to a PHP file
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*?)/?$ $1.php [L]
These directives (and your original directives for that matter) do assume the .htaccess file is located in the document root directory.
You can use the following code:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)/$ $1.php
RewriteRule ^([^/]+)/([^/]+)/$ /$1/$2.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
RewriteRule (.*)$ /$1/ [R=301,L
And if it won't works you can read this PDF file: How to remove PHP or HTML extensions with htaccess

htaccess remove .php extension from URLs with multiple forward slashes

I need to 301 redirect all URLs ending in .php to the non extension version. But the rewrite rules need to work with the existing ones below.
# ==== REWRITE URLS ====
RewriteEngine On
# pass through root
RewriteRule ^(index\.php|Sitemap\.xml)?$ - [L]
# no more / so add extension
RewriteCond $1 !/
RewriteCond $1 !\.php$
RewriteCond ${REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /$1.php [L]
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule ^(_assets|_css|_fonts|_includes|_scripts)($|/) - [L] #exclude these folders using the 'last: L' flag
RewriteRule ^(.*)/(.*)$ /$1-$2 [L]
This is an extension of this question here.
So the desired result is:
domain.com/region/brand/more-content-here.php
Redirects permanently to:
domain.com/region/brand/more-content-here
But fetches the actual file at:
domain.com/region-brand-more-content-here.php
Tried a few various ideas but they didn't seem to work in with the existing rules and htaccess is not my strength. Also need it to be querystring friendly. Any help would be appreciated.
To remove the .php extension ,you can use :
RewriteEngine on
#1)Permanently redirect "foo.php" to "/foo"#
RewriteCond %{THE_REQUEST} /([^.]+)\.php [NC]
RewriteRule ^ /%1 [NE,L,R=301]
#2)Rewrite "/foo" to "/foo.php"#
#this will internally redirect file to file.php#
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^ %{REQUEST_URI}.php [L]
Working code:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f

.htaccess removing *.php throws away the parameters of a URL that is passed as a GET parameter

My request is quite simple. Using my current .htaccess conditions and rules as given here:
# Remove .php extension from URLS
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# Redirect from *.php to URL without *.php
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R,L]
Problem is, when I pass a URL that contains *.php?param1=A&param2=B as a parameter, it throws away "?param1=A&param2=B"
For example:
I want to redirect to: "/views/users/login.php?redirect=/views/home.php?id=1"
Resulting in: "/views/users/login?redirect=/views/home", which throws away "?id=1", so now I can not access that parameter.
How do I rewrite my rules so that it keeps those parameters?
Any suggestions are welcome and much appreciated.
Update (2015-09-16):
Removing
RewriteRule ^(.*)\/index\.php$ $1 [R=301,L,NC]
As it is irrelevant.
You'll have to use urlencode to encode the URL into a parameter.
So when building the link or redirect, use:
redirect('views/user/login.php?redirect=' . urlencode('/views/home.php?id=1'))
btw: redirecting to a "controller" in a folder called "views" might be a bit confusing in a few month :)
Hello you just need to add the query append marker like so:
RewriteRule ^(.*)\/index\.php$ $1 [QSA,R=301,L,NC]
that is "QSA"
I have solved this issue (to some agree) using the following code:
# Enable rewrite mod.
RewriteEngine On
RewriteBase /
Options +FollowSymLinks -MultiViews
# Redirect URLs that contain *.php to extensionless php URLs.
RewriteCond %{THE_REQUEST} ^(.*)\.php
RewriteRule ^(.+)\.php$ $1 [R,L]
# Resolve *.php file for extensionless php URLs.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteCond %{QUERY_STRING} ^(.*)$
RewriteRule ^(.*)$ $1.php [NC,L,QSA]
# Resolve /views/* for URLs that do not contain views and needs it.
RewriteCond %{REQUEST_URI} ^/applications/(.*)$ [OR]
...
RewriteCond %{REQUEST_URI} ^/home [OR]
...
RewriteRule ^(.*)$ /views/$1
# Redirect URLs that contains /views/* to viewsless URLs.
RewriteCond %{THE_REQUEST} ^(.*)/views/(.*)
RewriteRule ^views(.*)$ $1 [R,L]

.htaccess remove .php and force trailing slash

I have files in my root folder. jobs.php, contact.php.
I want to be able to use .htaccess to remove the .php extension and force a trailing slash /. So that, www.domain.com/jobs/ and www.domain.com/contact/ goes to their respective pages.
Also, I want jobs.domain.com to point to www.domain.com/jobs/
<IfModule mod_rewrite.c>
Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteBase /
RewriteRule ^(rosquillos)/$ $1 [L,R=301,NC]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
</IfModule>
This is what I've got so far, and as much as I try. I can't seem to get it to work.
Any help would be awesome.
EDIT:
I would like to rephrase my question. The existing code removes the .php extensions for me, what I really only need right now is an additional rule that points the subdomain to the correct file: ie. jobs.domain.com points to jobs.php. I can live without the trailing slash.
Your condition:
RewriteCond %{REQUEST_FILENAME}\.php -f
will fail if your URL's end with a trailing slash. But if you only have jobs and contact then you'll just want:
RewriteEngine On
# add trailing slash and redirect browser
RewriteRule ^([^/]+)$ /$1/ [L,R=301]
RewriteRule ^([^/]+)/$ /$1.php [L]
# redirect direct access to php files:
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /([^/]+)\.php
RewriteRule ^ /%1/ [L,R=301]
Oh and I forgot:
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)\.domain\.com$ [NC]
RewriteCond %{DOCUMENT_ROOT}/%1.php -f
RewriteRule ^ /%1.php [L]
Assuming that *.domain.com has the same document root as www.domain.com.

.htaccess problem

I want to redirect what's in link after localhost/myScript/ to localhost/myScript/test.php?var=$1.
So.. something like
localhost/myScript/this/is/just/a/test/
(with or without the last slash) would redirect to
localhost/myScript/test.php?var=this/is/just/a/test
This is what I've got, but it's not good enough.
RewriteRule ^(.+)$ test.php?var=$1
I've tried using
RewriteRule ^(.+)/?$ test.php?var=$1
But, I get $_GET['var'] = 'test.php'.
I see 2 main approaches:
1. Two separate rules to deal with URL with and without trailing slash. It will only rewrite requests to non-existing files/folder thus preventing rewrite loop you are having:
# work with URL that ends with slash
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)/$ test.php?var=$1 [L]
# work with the rest of URLs (that ends with no slash)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ test.php?var=$1 [L]
2. Have separate rule to ignore existing files (to not to rewrite already rewritten URLs) and then use 1 line rewrite rule for URL with and without trailing slash:
# do not do anything for already existing files
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
# rewrite URLs
RewriteRule ^(.*[^/])/$ test.php?var=$1 [L]
RewriteRule ^(.+)$ test.php?var=$1 [L]
I would prefer #2.
this is better one
RewriteCond %{REQUEST_URI} !\.php$
RewriteRule ^(.+?)$ test.php?var=$1 [L]

Categories