Mod_Rewrite to Remove .PHP But Still Serve the .PHP File

mod_rewrite to remove .php but still serve the .php file?

For this solution, I have followed the following rules:

  1. If the user tries to load /something.php they should be externally redirected to /something.
  2. If the user tries to load /something then they should be internally redirected to /something.php.
  3. If the user passed any query string parameters to the URL then these should be preserved through the redirects.
  4. If the user tries to load a different file which really exists on the filesystem (a stylesheet, image etc) then this should be loaded as is.

And here's the final set of mod_rewrite magic:

RewriteEngine on
RewriteBase /

## Always use www.
RewriteCond %{HTTP_HOST} ^mysite\.com$ [NC]
RewriteRule ^(.*)$ http://www.mysite.com/$1 [L,R=301]

# Change urlpath.php to urlpath
## Only perform this rule if we're on the expected domain
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
## Don't perform this rule if we've already been redirected internally
RewriteCond %{QUERY_STRING} !internal=1 [NC]
## Redirect the user externally to the non PHP URL
RewriteRule ^(.*)\.php$ $1 [L,R=301]

# if the user requests /something we need to serve the php version if it exists

## Only perform this rule if we're on the expected domain
RewriteCond %{HTTP_HOST} ^www\.mysite\.com$ [NC]
## Perform this rule only if a file with this name does not exist
RewriteCond %{REQUEST_FILENAME} !-f
## Perform this rule if the requested file doesn't end with '.php'
RewriteCond %{REQUEST_FILENAME} !\.php$ [NC]
## Only perform this rule if we're not requesting the index page
RewriteCond %{REQUEST_URI} !^/$
## Finally, rewrite the URL internally, passing through the user's query string
## using the [qsa] flag along with an 'internal=1' identifier so that our first
## RewriteRule knows we've already redirected once.
RewriteRule ^(.*)$ $1.php?internal=1 [L, QSA]

Removing the .php extension with mod_rewrite

RewriteEngine On
RewriteRule something something.php [L]

http://example.com/something will be handled as if it was a request for something.php

To redirect all requests that are not a physical file to the same name but with .php:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule (.*) $1.php [L]

Remove .php from URL but it should still be pointing towards the original file (mod-rewrite)

With your shown samples, could you please try following.
Please make sure you clear your browser cache before testing your URLs.

RewriteEngine On
RewriteBase /

RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]

RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [NC,L]

RewriteRule ^([^\.]+)$ $1.html [NC,L]

Trying to remove .php file extension

You have asked many questions here. Let me answer first one:

www.mysite.com/page works without any rewrite rule due to Options MultiViews. Option MultiViews is used by Apache's content negotiation module that runs before mod_rewrite and and makes Apache server match extensions of files. So /file can be in URL but it will serve /file.php.

If you place this line at top of your root .htaccess:

Options -MultiViews

Then www.mysite.com/page will issue 404.

Also to automatically remove .php from your URLs use this code in your root .htaccess:

Options -MultiViews
RewriteEngine On

# To externally redirect /dir/file.php to /dir/file
RewriteCond %{THE_REQUEST} \s/+(?:index)?(.*?)\.php[\s?] [NC]
RewriteRule ^ /%1 [R=301,L,NE]

# To internally forward /dir/file to /dir/file.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{DOCUMENT_ROOT}/$1\.php -f [NC]
RewriteRule ^(.+?)/?$ /$1.php [L]

How to create simple remove .php extension with .htaccess page?

My aims is type this url http://site/Test it can visit hello.php content, anyone know how to do that?

This isn't simply "file extension removal". If it was then /Test would serve the content from /Test.php. In your example, you are wanting to serve the contents of an entirely different file.

Rewriting the request with mod_rewrite

Since you are requesting a directory (/Test/) and wanting to serve a file from within that directory and the .htaccess file itself is actually located in that directory, you would need to write your RewriteRule like this:

RewriteRule ^$ hello.php [L]

In .htaccess (directory context), the RewriteRule pattern matches the URL-path relative to the location of the .htaccess file. So, in this case the URL-path we are matching against is simply an empty string, ie. ^$, since we are wanting to match /Test/<nothing>.

Likewise, when the susbtitution string (ie. hello.php) is relative (as it is here), it is relative to the location of the .htaccess file. So, in this case it effectively rewrites the request to /Test/hello.php (it's actually the absolute filesystem path, eg. /var/www/user/public_html/Test/hello.php - after the directory-prefix is added back).

Additional issues with this example

Since you are rewriting a request that would otherwise map to a physical directory there are a couple of potential issues you need to be aware of...

You should request the directory with a trailing slash, ie. /Test/, not /Test (as you stated in your initial example), otherwise mod_dir will issue a 301 redirect to append the slash before your rewrite is successful.

(There are ways to avoid the trailing slash, but this does increase the complexity and requires further manual rewrites.)

An additional complication occurs if there is a DirectoryIndex document in this subdirectory. eg. /Test/index.php. In this case mod_dir issues an internal subrequest to the DirectoryIndex document (eg. index.php) and this takes priority over your internal rewrite. (Your rewrite does still occur, but mod_dir "wins".) If this is the case then you can rewrite the DirectoryIndex document instead of an empty URL-path. For example:

RewriteRule ^index\.php$ hello.php [L]

This is perhaps counter-intuitive, as we are now rewriting the internal subrequest that mod_dir has issued in a later pass through the file.

You could handle both scenarios and make index.php optional. For example:

RewriteRule ^(index\.php)?$ hello.php [L]
RewriteRule ^(.*)$ $1.php

Your example would result in an internal rewrite loop (500 Internal Server Error response) since the pattern ^(.*)$ also matches the rewritten URL and it gets stuck in an endless loop. (The rewriting process doesn't just consist of a single pass through the file. The process repeats until the URL passes through unchanged.)

(Incidentally, this IS an extensionless URL type of rewrite, but it doesn't help you achieve what you stated in your example.)

There are various ways to prevent this "endless loop":

  • Use a more specific regex, that won't also match the rewritten URL. eg. a regex that excludes a dot such as ^([^.]+)$.
  • Use a RewriteCond (condition) directive that prevents the rule being triggered on the rewritten URL. eg. Exclude .php files or check that the request does not map to a file, etc.
  • Use the END flag on the RewriteRule to stop all further processing by the rewrite engine.

Alternative - change the DirectoryIndex

Instead of using mod_rewrite, as explained above, to internally rewrite the request, we could instead change the DirectoryIndex document.

This only works in this particular case where you are requesting a directory and wanting to serve a file from that directory (although strictly speaking the file could be anywhere).

The DirectoryIndex is the document that mod_dir will look for when requesting a directory (eg. /test/). By default, it looks for index.html (and often index.php) and possibly others. If a DirectoryIndex document is not found, you get a 403 Forbidden when requesting that directory (assuming auto-directory indexes are disabled).

For example, you could set the following:

DocumentIndex hello.php

And now when you request /Test/, mod_dir will serve hello.php in that directory.

However, this method (by itself) is limiting and potentially confusing for readers of your code (if changing the DirectoryIndex on a directory by directory basis). It is generally expected that the DirectoryIndex document(s) is consistent throughout your site.

Running PHP without extension without using mod_rewrite?

An alternative is to use content negotiation. Turn on multiviews:

Options +MultiViews

If a named resource doesn't exist, Apache will glob for the file, then sort based on the media type and content encoding requirements send by the browser. If there's only one file (your PHP script), then that's what the URL resolves to.

Remove php extension for only one file by using htaccess

with the code I just posted I can visit example.com/content/myfile correctly. But I wanted to restrict it to only this URL.

RewriteRule ^content/myfile$ content/myfile.php [L]

Or, use a backreference to save repetition:

RewriteRule ^content/myfile$ $0.php [L]

The $0 backreference contains the URL-path matched by the RewriteRule pattern (ie. "content/myfile").



RewriteCond %{REQUEST_FILENAME} !-d 
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php

This code works, but it removes the PHP extension for all PHP files.

(As stated in comments, this does not actually "remove" anything.)

But this only applies to requests that exist as physical files when the .php extension is applied, so if you don't want it to apply then you shouldn't be requesting the arbitrary URL without the .php extension in the first place. (?)

And, if I want to add another file in the future, for example, https://example.com/content/otherfile.php, how can I do it without writing the same rule twice?

If you only want this to apply to a second arbitrary file then you obviously need to write essentially the same rule twice (or modify the existing rule), otherwise, how does Apache know to rewrite the URL (without writing a more generic rule that you had initially)?

You could combine/simplify the two rules into one, but this is not necessarily an improvement. For example, the following single rule will rewrite both URLs:

RewriteRule ^content/(myfile|otherfile)$ $0.php [L]

But this is really the purpose of the first rule you posted - so you don't need to write a second rule (or update your .htaccess file each time) for each URL.

Remove .php from URL

Hope helped.

It's worked for me.

Options +FollowSymLinks -MultiViews
# Turn mod_rewrite on
RewriteEngine On
RewriteBase /

# For LocalHost !.php
RewriteCond %{HTTP_HOST} !=localhost
RewriteCond %{HTTP_HOST} !=127.0.0.1
RewriteCond %{REMOTE_ADDR} !=127.0.0.1
RewriteCond %{REMOTE_ADDR} !=::1

## hide .php extension
# To externally redirect /dir/foo.php to /dir/foo
RewriteCond %{THE_REQUEST} ^[A-Z]{3,}\s([^.]+)\.php [NC]
RewriteRule ^ %1 [R=302,L]

# To internally forward /dir/foo to /dir/foo.php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.*?)/?$ $1.php [L]

5 .htaccess Rewrites: Force HTTPS, Remove index.php, Remove .php, Force www, Force Trailing Slash

I see 2 issues:

Redirect rules appearing after rewrite ones
Adding .php should only happen after you ensure corresponding .php file exists.

Have it this way:

Options +SymLinksIfOwnerMatch
RewriteEngine On
RewriteBase /

# Ensure www on all URLs.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [L,R=302]

# Ensure we are using HTTPS version of the site.
RewriteCond %{HTTPS} !on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302]

RewriteCond %{THE_REQUEST} \s/*(.*?)/index\.php [NC]
RewriteRule ^ %1/ [R=302,L]

RewriteCond %{THE_REQUEST} \s/+(.+?)\.php[\s?] [NC]
RewriteRule ^ /%1/ [R=302,L]

# Ensure all URLs have a trailing slash.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^[^.]*?[^/.]$ %{REQUEST_URI}/ [L,R=302]

# Remove all .php extensions without interfering with .js or .css.
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^([^.]+?)/?$ $1.php [L]

# Remove index from url.
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^.]+?)/?$ index.php?$1 [L,QSA]

Make sure to clear your browser cache before testing this.



Related Topics



Leave a reply



Submit