R2D2
R2D2

Reputation: 2640

301 redirect to url without extension

I am trying to set up my site without file extensions in the URLs.

All my pages are php.

All my menu links have extensions removed, such as...

<a href="page1">page 1</a>
<a href="page2">page 2</a>
<a href="page3">page 3</a>

And these links all work fine.

But I am trying to now set up a .htaccess file to make 301 redirects from other external links, such as Google.

In my htaccess file, I have...

Redirect 301 /page1.php https://www.mysite.co.uk/page1

But this makes the link from Google hit the 404 page not found - it doesn't go to the page that it should.

What am I doing wrong, and how can I get these 301 redirects to work properly?

EDIT

In an effort to try and debug this, I have changed my htaccess file. My full htaccess code is now this...

DirectoryIndex index.php

CheckSpelling Off

FileETag none
ServerSignature Off

Options +FollowSymlinks

Redirect 301 https://www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 https://mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 http://www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 http://mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1

Now if I follow the menu link, I get to...

https://www.mysite.co.uk/page1

If I enter https://www.mysite.co.uk/page1 into the address bar of the browser, it loads the page correctly.

BUT if I follow the link from google, it ends up at...

http://www.mysite.co.uk/page1.php

How can this be?!

I have covered all possible URLs in my htaccess file, so how does this google link go to the http:// file with the .php at the end?

Upvotes: 1

Views: 2587

Answers (1)

DocRoot
DocRoot

Reputation: 1201

I assume you are currently using Apache's MultiViews (part of mod_negotiation) to map URLs without the file extension (eg. /page1) to the corresponding URL with the file extension (eg. /page1.php) - since you have nothing else in your .htaccess file that does this.

MultiViews maps file extensions using internal subrequests, so you will need to use mod_rewrite (RewriteRule), as opposed to mod_alias (Redirect) in order to redirect to the extensionless URLs, since you only want to redirect direct requests, not subrequests, and it's not possible to differentiate with Redirect.

Redirect 301 https://www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 https://mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 http://www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 http://mysite.co.uk/page1.php https://www.mysite.co.uk/page1
Redirect 301 www.mysite.co.uk/page1.php https://www.mysite.co.uk/page1

You need to change the above Redirect directives to something like the following. (Incidentally, the above directives aren't actually doing anything since the URL-path stated, eg. https://www.mysite.co.uk/page1.php, would never match - this must be a root-relative URL-path.)

RewriteEngine On

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)\.php$ https://www.example.com/$1 [R=302,L]

The RewriteCond directive that checks against the REDIRECT_STATUS environment variable ensures we are only redirecting initial/direct requests.

Note that this is currently a temporary (302) redirect. Change it to a 301 (permanent) redirect only after you have confirmed that it's all working OK. (301s are cached hard by the browser, so can make testing problematic.)


You could also try the following one-liner instead (without a RewriteCond directive):

RewriteRule ^(.*)\.php$ https://www.example.com/$1 [NS,R=302,L]

Note the addition of the NS (nosubreq) flag, that prevents the directive being processed for internal subrequests.


UPDATE: Try disabling MultiViews and doing this all with mod_rewrite instead (which is probably recommended). For example:

Options +FollowSymLinks -MultiViews

RewriteEngine On

# Remove .php file extension with an external redirect
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)\.php$ https://www.example.com/$1 [R=302,L]

# Append the .php extension with an internal rewrite
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^.])+$ $1.php [L]

The directives that append the file extension assumes that existing URLs do not already include a dot. ie. dots only occur when a file extension is applied to the URL.

Upvotes: 2

Related Questions