I have a problem to hide php extension on my website using htaccess.
I saw a lot of webs to try to fix it and nothing.
But just html extension is hidden for me.
On my htaccess I have this to hide extensions (it's right after errors pages what is the first on my htaccess, but I don't think that influences):
#hide extensions
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule ^(.*)$ $1.html
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php
I can access to html files without extension, but for php files, I can't (404).
I deleted htaccess file and created it again but nothing.
And of course, on links to php and html files, I don't put the extension (for example url/file instead of url/file.php).
Assuming your .htaccess file is in the document root of your site then try the following instead:
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.html -f
RewriteRule (.+) $1.html [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.+) $1.php [L]
The $1 backreference in the RewriteCond TestString (ie. %{DOCUMENT_ROOT}/$1.php) is a backreference to the captured group in the RewriteRule pattern (ie. (.+)), ie. the requested URL-path. This is the same backreference as used in the RewriteRule substitution (ie. $1.php).
A bit more explanation...
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php
The condition here that checks the existence of the requested resource plus the file extension is not strictly correct, depending on your file structure. It's not necessarily checking the same file that you will ultimately rewrite to in the following RewriteRule. See my answer to this ServerFault question for a detailed explanation of this.
The L flag is missing on the RewriteRule, so processing will continue through the file and could be getting rewritten again.
MultiViews needs to be disabled (if not already) for the rewrite to be successfully processed. This probably does not affect you currently, but if your rewrite included URL parameters; they would be missing. (The effect of MultiViews is that mod_negotation would issue an internal subrequest for file.php before your mod_rewrite directive is processed.)
Related
I've a problem with some rewrite rules for my URL, I'm using this rule to remove .php from the URL of my website
Options +SymLinksIfOwnerMatch
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
The problem is that when added a trailing slash at the end, the website gives back an error.
Example:
example.com/test/ gives back an error
I do think that's because it rewrites it like example.com/test/.php, I do not know how to properly solve that
I do think that's because it rewrites it like example.com/test/.php
Yes, that is what's happening. But it will do this repeatedly (causing a rewrite-loop) until the server "breaks" with a 500 Internal Server Error.
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php
The "problem" with this is that you aren't necessarily testing the existence of the same file in the RewriteCond directive that you are rewriting to in the RewriteRule directive.
So, this will cause an error (rewrite-loop / 500 Internal Server Error) when appending a slash because REQUEST_FILENAME is /abs/path/to/test (the resolved filesystem path) and /abs/path/to/test.php exists, but it internally rewrites the request to test/.php because $1 is test/ (captured from the URL-path). It will do this repeatedly until the server aborts with an error.
You need to make sure you are always testing the same thing in the condition as you are rewriting to later.
See my answer to the following question on ServerFault with a detailed explanation of this behaviour: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error
Additional points...
You are missing the L flag, so processing continues on to the next rule.
The first condition that checks the request does not map to a directory is not required, since you are already checking that <whatever>.php exists as a file.
Minor point, but there is no need to backslash-escape a literal dot in the TestString (1st argument to the RewriteCond directive) - this is not a regex.
For example, use the following instead:
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule (.*) $1.php [L]
Now, %{DOCUMENT_ROOT}/$1.php in the RewriteCond directive refers to the same string/file as $1.php in the substitution string.
So, when you request /test/, it will now be testing /abs/path/to/test/.php in the RewriteCond directive, which doesn't exist, so nothing happens (results in a 404). /test and test/ are, after all, different URLs.
Aside:
RewriteCond %{REQUEST_URI} ^(.*)//(.*)$
RewriteRule . %1/%2 [R=301,L]
This redirect is in the wrong place. It should be the first rule, not the last.
Hello there i have a little problem.
When using these lines of .htaccess
RewriteEngine on
Options +FollowSymLinks
# clean up file extensions .php only
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
#make get request clean
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^cms/tests/([0-9]+) cms/tests/index.php?survey=$1 [NC,L]
I transform the url
cms/tests/index.php?survey=65 to -> cms/tests/65
This works!
Now i want to have an edit mode like this:
cms/tests/65/edit or cms/tests/65/view
This is the rewrite rule I have come up with:
RewriteEngine on
Options +FollowSymLinks
# clean up file extensions .php only
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
#make get request clean
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^cms/tests/([0-9]+)/([a-zA-Z0-9_-]+) cms/tests/index.php?survey=$1&mode=$2 [NC,L]
When writing the full url like this cms/tests/index.php?survey=65&mode=edit it completely works
But it with the "clean" url it goes to my 404 page and also shows a 302 redirect in the network tab.
Is there a something that I am doing wrong or over seeing?
#make get request clean
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^cms/tests/([0-9]+)/([a-zA-Z0-9_-]+) cms/tests/index.php?survey=$1&mode=$2 [NC,L]
The second condition is never successful so the rule is not processed.
The second condition (that supposedly checks that the request + .php exists) is not what you should be doing here. If anything, you would need to check that the request does not map to a file. For example:
RewriteCond %{REQUEST_FILENAME} !-f
However, if you restrict the regex in your RewriteRule pattern by appending a $ (end-of-string anchor) then you can remove that condition altogether. For example:
#make get request clean
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^cms/tests/([0-9]+)/([a-zA-Z0-9_-]+)$ cms/tests/index.php?survey=$1&mode=$2 [NC,L]
A request that matches the regex as stated could not map to a real file (unless you have extensionless files).
Aside:
# clean up file extensions .php only
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
The second condition in your first code block is also not strictly correct and will fail under certain conditions, because the filesystem check is not necessarily the same as the file you will ultimately rewrite to, which could result in a 404 or 500 (rewrite loop) depending on your file structure. (This code block is surprisingly common, but issues relating to this keep on cropping up.)
This should really be written more like this:
# clean up file extensions .php only
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^(.*)$ $1.php [NC,L]
Now, the condition %{DOCUMENT_ROOT}/$1.php matches the rewrite substitution $1.php. (Assuming the .htaccess file is in the document root.)
See my answer to the following question on ServerFault with a detailed explanation of this change: https://serverfault.com/questions/989333/using-apache-rewrite-rules-in-htaccess-to-remove-html-causing-a-500-error
I want to remove the .php filename extension from the URL, I have already written code in the .htaccess file but I am missing something because by default when I open the page it doesn't have the .php extension, but if I manually add the .php extension in the URL then the page also opens, which I want to avoid.
.htaccess file:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
# rewrite category
RewriteEngine On
RewriteRule ^blog-category/(.*)$ blog-category.php?category=$1 [NC,L]
# rewrite blog
RewriteEngine On
RewriteRule ^blog/(.*)$ blog.php?title=$1 [NC,L]
# error pages
RewriteEngine On
ErrorDocument 404 /404.php
# on 301 error redirect to softcrayons.com
RewriteEngine On
RewriteCond %{HTTP_HOST} ^softcrayons.com
RewriteRule (.*) http://www.softcrayons.com/$1 [R=301,L]
You have nothing in that dynamic configuration file that actually prevents scripts being called directly. You have to add another redirection for that:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/?([^.]+)\.php$ $1 [L,R=301]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^/?([^.]+)/?$ $1.php [L]
This will force an external redirection (so change the URL visible in the browser) and a second request for all requests that use the .php file name extension and where that file actually exists.
Note that you may have to take care to not create an endless rewrite loop.
I also added some additional condition to only internally rewrite to .php if that file actually exists.
If you really want to create an error, a http status 404 for requests to URLs that have the .php file name extension then replace the rewriting rule in the code above like that:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^/?([^.]+)\.php$ - [R=404]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^/?([^.]+)/?$ $1.php [L]
Note however that as already said I think that is a stupid thing to do. Why frustrate your users with an error? You know what they actually want and you can fulfill that request. Think positive!
And a general hint: you should always prefer to place such rules inside the http servers (virtual) host configuration instead of using dynamic configuration files (.htaccess style files). Those files are notoriously error prone, hard to debug and they really slow down the server. They are only provided as a last option for situations where you do not have control over the host configuration (read: really cheap hosting service providers) or if you have an application that relies on writing its own rewrite rules (which is an obvious security nightmare).
HTML:
Index
.htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
Link will redirect you to the home.php file, and your url will be example.com/home hope this will help you.
Greetings!
## hide .php extension snippet
# To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R,L]
# To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [L]`
I have a multilanguage website. I want the URL's to be like: http://example.com/en/blog_post/2 where blog_post is the name of the file blog_post.php and 2 is value of the parameter id.
I have this .htaccess code now
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(bg|en)/(.*)$ /$2?lang=$1 [L]
RewriteRule ^(bg|en)/(.*)/([^/.]+)$ /$2?lang=$1&id=$3 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) $1.php [L]
I tried with this line, but it doesn't work:
RewriteRule ^(bg|en)/(.*)/([^/\.]+)$ /$2?lang=$1&id=$3 [L]
Can you help me please :)
I did it. It works with these lines. Thanks to everyone :)
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(bg|en)/post/([^/\.]+)$ blog_post.php?lang=$1&id=$2 [L]
RewriteRule ^(bg|en)/(.*)$ $2?lang=$1 [L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule (.*) $1.php [L]
As mentioned above, the order of these directives is important. The more specific rules should come before the more general rules and this is a key problem with the above. However, the pattern also needs to be changed (made more specific) to prevent other malformed URLs triggering a 500 Internal Server Error and breaking your site. eg. /en/blog_post/2/3 (an additional - erroneous - /something) would still trigger a 500 error in the "fixed" code above.
So, this could be written as:
Options +FollowSymLinks
RewriteEngine On
RewriteRule ^(bg|en)/([^/.]+)$ /$2?lang=$1
RewriteRule ^(bg|en)/([^/.]+)/([^/.]+)$ /$2?lang=$1&id=$3
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule (.*) /$1.php [L]
The generic (.*) pattern has been replaced with ([^/.]+) to only match path segments (excluding a slash). By doing this it also means that the order no longer matters and /en/blog_post/2/3 will simply result in a 404.
I've also removed the L flag on the initial RewriteRule directives, since you need to continue anyway to append the .php extension.
The RewriteRule substitutions should also be kept as root-relative, ie. starting with a slash. (Or you should include the RewriteBase directive.)
I've also added another RewriteCond directive to make sure that <file>.php actually exists before appending the file extension. If you don't do this and <file>.php does not exist then you will get another 500 error.
You could combine the two RewriteRules into one if you don't mind having an empty id= parameter (which presumably your script handles anyway):
RewriteRule ^(bg|en)/([^/.]+)(?:/([^/.]+))?$ /$2?lang=$1&id=$3
This handles both /en/blog_post and /en/blog_post/2 requests.
Sorry I couldn't come up with a better title.
Here is my htaccess
RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*)$ $1.php [L,QSA]
And this is my problem:
localhost/validpage gives me the contents of localhost/validpage.php.
localhost/validpage/blah also gives me the same (validpage.php) page and so does localhost/validpage/blah/blah/...
Therefore the problem I am facing is link duplicity(in my words!).
How do I allow localhost/validpage.php to be accessed from localhost/validpage only and nothing else, not even localhost/validpage.php.
I have started a question on *Server****Fault*** too but with not much success.
The answer I have got is it cannot be done with htaccess alone.
By validpage I mean any valid page on the server. Since I am retrofitting an existing site with mod_rewrite for cleaner urls, I am looking for a relatively easy solution preferably with .htaccess only. However, any solutions are welcome.
what is the source attribute of your images, etc ???
absolute or relative?
<img src="/images/my.jpg" /> and <img src="images/my.jpg" /> point to different files when applying your rewrite rules.
You could try using this in your .htaccess
RewriteEngine on
RewriteBase /
# if request has a php extension remove and redirect
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteCond %{REQUEST_FILENAME} -f
RewriteCond %{REQUEST_URI} ^((.*)\.php)$
RewriteRule ^(.*).php$ $1 [L,R=301]
# if request uri has no extension link to php file
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.php [NC,L]
I should rewrite your php scripts to friendly urls, and redirect requests using the .php extension.