File extension "removal"
This piece is supposed to remove .php from any and all urls. It ADDS a
.php to the end of every .php url.
So my urls turn into "file.php.php"
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ $1.php [NC,L]
That code is incorrect/incomplete. In fact, that code by itself would result in an endless rewrite-loop: file.php.php.php.php.php
etc. (and a 500 response).
And yes, as noted, that code does not actually "remove the .php
" extension, although it is associated with having removed the .php
extension. Unfortunately, there are too many instances on the internet where the wording is arguably back-to-front in this regard. You "remove" the file extension in your URLs in your HTML source (not in .htaccess
). You then add the .php
extension back again via an internal rewrite in your .htaccess
file in order to rewrite the URL to the actual file-path that handles the request. Optionally, you can redirect to remove the .php
extension in .htaccess
as well, but this is only to benefit SEO if you are changing an existing URL structure.
You can "fix" the above in various ways...
Check that the requested URL does not already have a .php
extension AND does not already map to an existing file (as well as check that it does not map to a directory). For example:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.php$ %{REQUEST_URI}.php [L]
OR, check that the requested URL does not already have a .php
extension AND that if you append .php
to the current URL-path it would map to an actual file. This avoids the additional check that the request does not map to a directory. For example:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI}.php -f
RewriteRule !\.php$ %{REQUEST_URI}.php [L]
Instead of checking that the request does not already end with .php
, you could improve this by checking that the initial request does not include any file extension (assuming your URLs don't have what looks like a file extension). eg. There's probably no point checking that /styles/mystyles.css.php
exists. In this case change the RewriteRule
pattern from !\.php$
to something like !\.\w{2,4}$
instead.
However, your proposed URL structure is not simply ".php
extension removal". You are also removing the /Pages
path segment. So, you wouldn't necessarily do it this way to begin with. (See below)
Regex not behaving like a regex
The regex just doesnt act like basic regex, instead, it does things that dont make sense
The problem would seem to be that the string being matched is not what you think it is.
RewriteRule ^([a-z]+\:\/\/|)(www\.|)([a-z]+\.[a-z]+|)((\/|)([a-z_-]+)) $6 [NC,L]
The RewriteRule
pattern (regex) matches against the URL-path only. And in a .htaccess
(directory) context, this is also missing the slash prefix (assuming your .htaccess
file is in the document root). So, given a request for https://www.example.com/projects.php
(from your linked example) then this regex matches against the string projects.php
only and consequently $6
is a single p
.
However, I can't see why you would need to match the basename (filename less the file extension) here?
"Problem" with proposed URL structure / conflict with mod_dir
An immediate problem with your proposed URL structure is that you have the URL /projects
that is expected to map to /Pages/projects.php
, but /projects
is also a physical subdirectory. This, by default, will create a conflict with mod_dir, which will issue an external 301 redirect to append the trailing slash. ie. Redirecting /projects
to /projects/
.
Again, there are various ways to resolve this:
Change your URL structure (or underlying file structure) to avoid this conflict. ie. Change the name of projects.php
or the /projects
subdirectory - you can still keep the same URL structure. eg. You could rename the subdirectory /projects
to /projects-dir
, but still reference /projects/subproject
in your URLs if you wish. (Avoiding the conflict would be preferred.)
OR, include a trailing slash on all your URLs. Strictly speaking, you only need to include a trailing slash on the URL with a conflict, ie. /projects/
. But you need to be consistent. This also assumes that you never need to access a directory directly.
OR, override mod_dir and disable the auto-appending trailing slash. However, you will then need to manually append the trailing slash should you need to access a directory. This could also have additional caveats.
Which method you choose is really up to you and how your web application is structured, but it changes the implementation.
Solution [A] - /phpfilename
and /projects/phpfile
Assuming you avoid the conflict using method #1 above and you change the filesystem directory from /projects
to /projects-dir
, but still use /projects
in the visible URL, then you could do something like the following.
I also assume that your URL path segments (that map to file basenames) do not contain dots, this avoids having to check that the requested URL does not end in a file extension (as mentioned above).
RewriteEngine On
# Rewrite "/<filename>" to "/Pages/<filename>.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/Pages/$0.php -f
RewriteRule ^[\w-]+$ Pages/$0.php [L]
# Rewrite "/projects/<filename>" to "/projects-dir/Pages/<filename>.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/projects-dir/Pages/$1.php -f
RewriteRule ^projects/([\w-]+)$ projects-dir/Pages/$1.php [L]
The RewriteCond
directives that check for the existence of the file before rewriting to it aren't strictly necessary. You could simply rewrite the request based solely on the input URL. Although the 404 would then be triggered on the rewritten URL (file-path), not the requested URL.
UPDATE:
Solution [B] - /phpfilename
only
How can I rewrite all Files to the Index Folder and also Remove the Extensions
At this point, I would be happy with all my PHP URLs being shortened down to just
example.com/phpfilename
Ok, I think I understand what you mean, but this doesn't "rewrite all Files to the Index Folder" - you would seem to want to do the opposite... you are rewriting all requests from the document root to the appropriate file in the subdirectory. "At this point" - you make it sound as if this should be easier, but if anything, the opposite is true.
So, /phpfilename
could map to either /Pages/phpfilename.php
or /projects-dir/Pages/phpfilename.php
(following the same renaming of the /projects
subdirectory as mentioned above). This does, however, create a potential conflict as you naturally can't have a file with the same filename in both places - one will need to take priority (I assume the file in the /Pages
subdirectory).
In order to implement this, you would need to change the above directives to something like the following instead:
RewriteEngine On
# Rewrite "/<filename>" to "/Pages/<filename>.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/Pages/$0.php -f
RewriteRule ^[\w-]+$ Pages/$0.php [L]
# Rewrite "/<filename>" to "/projects-dir/Pages/<filename>.php" if it exists
RewriteCond %{DOCUMENT_ROOT}/projects-dir/Pages/$0.php -f
RewriteRule ^[\w-]+$ projects-dir/Pages/$0.php [L]
We basically need to "search" for the file and test the expected locations in turn.