That’s the “loopy redirection” I have in my signature’s tutorial (Redirect TO New Format) with all the code you need in there.
BTW, while you’ve correctly handled the spaces in the {THE_REQUEST} variable, WHY? If you didn’t use the start anchor or include the HTTP at the end, all that horrible variable would give you is the ORIGINAL URI so, if you have to use it (which, apparently you do for this “loopy” redirection), then treat it as you would {REQUEST_URI} but without the start and end anchors.
Thanks for that but it seems we aren’t seeing eye to eye on this. You think I need to remove the file extension, I meanwhile wish to simply remove the “index” file name as I’ve already removed the file extensions.
I’ve looked at your tutorial but when I paste your code into my .htaccess file it simply brings back the .php file extensions on all links.
Just to be clear on this. I want to make www.domainname.com/index appear as www.domainname.com in the browser’s address bar. Consequently, it’s a case of chopping off the “index” each time it crops up rather than the file extensions.
Whether the server is configured to allow that or not depends upon the host, however, if you merely add a RewriteRule to the .htaccess in the directory root to remove index(\.php)?, you should be set. That would be something like:
RewriteEngine on
# Remove index.php, if index or index.php, redirect to domain (no {REQUEST_URI} THEN
# chain that to match the empty {REQUEST_URI} and redirect internally to index.php
# Hopefully, that will prevent the server from rewriting to the DirectoryIndex
RewriteRule ^index(\\.php)? http://www.example.com/ [R=301,C]
RewriteRule ^$ index.php [L]
# Remove PHP extension from links (internally)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ /$1.php [L,QSA]
# Remove PHP extension from links (externally)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\\ /([^.]+\\.)+php\\ HTTP
RewriteRule ^(.+)\\.php$ /$1 [R=301,L]
PLEASE let me know if that works on your host’s setup as that’s the biggest unknown variable in this problem.
If that generates a loop on the DirectoryIndex, then you’ll have to fall back on testing the EMPTY (meaning “/”) URI in {THE_REQUEST} as a condition of the index.php redirection.
This works offline in WAMP when supplied an online HTTP redirect (www.example.com or whatever seems fit) but not on my host. On my host it generates a redirect loop. In Chrome it displays the following message:
This web page has a redirect loop.
[I]The web page at http://www.domainaname.com has resulted in too many redirects. Clearing your cookies for this site or allowing third-party cookies may fix the problem. If not, it is possibly a server configuration issue and not a problem with your computer.
Here are some suggestions:
Reload this web page later.
Learn more about this problem.
More information on this error[/I]
In your further comment you write a solution to this is to test for a {THE_REQUEST} of “\” which I assume means the default page of a given folder (index, default php/htm/html etc.). If my thinking isn’t skewed I assume you’re implying I change this:
Also, my host requires the below line, which is different to the normal way of enabling ex-tensionless file names, does this have any effect on the above?
Okay, your host has redirected empty requests to the DirectoryIndex before allowing mod_rewrite access - which SHOULD be the case. THEREFORE, the first redirection should look at {THE_REQUEST} to see whether a file was requested or not (as suggested in the follow-up to the post you quoted).
No, that means to change:
RewriteRule ^index(\\.php)? http://www.example.com/ [R=301,C]
# to
RewriteCond %{THE_REQUEST} !/\\ HTTP
RewriteRule ^index(\\.php)? http://www.example.com/ [R=301,C]
# if the original request was NOT blank (Directory Index)
# but the index or index.php was requested,
# redirect to the domain with no path/file.
I don’t know why your host requires Options -MultiViews BECAUSE they should be doing that in the server config file. Argh! MultiViews is such a major PITA that it would be better to eliminate that possibility! However, it should have NO impact on your code (it’s designed to implant a file request in a directory slot in the URI - and serve that file).
Okay, so we seem to be getting somewhere. After pasting the following code and editing it to the correct domain all requests to index get pointed to the domain:
RewriteCond %{THE_REQUEST} !/\\ HTTP
RewriteRule ^index(\\.php)? http://www.example.com/ [R=301,C]
# if the original request was NOT blank (Directory Index)
# but the index or index.php was requested,
# redirect to the domain with no path/file.
This however introduces a different problem regardless whether I test it on localhost or via my online host.
Namely, all links pointing to non-index (those that aren’t named index.php) pages produce a 404. The page url’s stay extensionless, just yield a 404.
I’m no guru on this topic, else I wouldn’t be asking this question but I think what’s going wrong now is that Apache (offline/online - both) is trying to read a file name of the requested page after stripping away the file extension. Consequently no such file names without the .php extension exist hence the 404. As soon as I remove the above code things return to normal. Somehow the order in which Apache strips a file extension then reads a file has changed. The HTTP part of the above code seems to be interfering? …then again the HTTP should only intefere on localhost and not on my online host?
…or is there a different logical explanation?
The other thing I was wanting to ask (not a problem/rather a hope) is can I pass it a path reference rather than a domain name to redirect to? This way wouldn’t have to remove the above piece of code each time I edit the website offline in WAMP.
Your understanding is fine. Because Apache’s process is to convert a request to a URI before going to .htaccess, each change you make goes back and restarts the process in the Apache core. That’s just ONE problem with the type of “loopy” redirection you’re attempting to make. Stripping the filename off the domain is complicated by the server configuration directives which MUST add it to the URI (as the DirectoryIndex) BEFORE processing mod_rewrite directives in the .htaccess. Of course, if it’s only you creating index links, you could help that a great deal by merely linking to the domain.
Let me redefine what you’re attempting:
Strip DirectoryIndex from domain (pass through if not specified)
# Pass Through the empty request (to be handled as DirectoryIndex)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\\ /?\\ HTTP
RewriteRule .? - [PT]
# If index or index.php requested, strip and redirect
RewriteCond %{THE_REQUEST} index(\\.php)?
RewriteRule ^index(\\.php)?$ http://www.example.com/ [R=301,L]
Strip .php file extension from request
# Remove PHP extension from links if NOT subrequest
RewriteRule ^(.+)\\.php$ $1 [R=301,NS,L]
Keep these RewriteRules in this order, though, as order is critical (to allow the pass through then internal redirections.
The other thing I was wanting to ask (not a problem/rather a hope) is can I pass it a path reference rather than a domain name to redirect to? This way wouldn’t have to remove the above piece of code each time I edit the website offline in WAMP.
Because I use a local version of my domain names (e.g., datakoncepts for local and datakoncepts.com online) to test, I generally don’t need to specify a different path - unless using PHP’s file functions. In that case, yes, I initialize a script with the correct path (generally with the db connection).
Okay thanks for that further clarification, either my head isn’t what it used to be or Apache .htaccess configuration is about the most confusing and mysterious concept in web development.
I have used the code in the order your prescribe, which is:
# Pass Through the empty request (to be handled as DirectoryIndex)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\\ /?\\ HTTP
RewriteRule .? - [PT]
# If index or index.php requested, strip and redirect
RewriteCond %{THE_REQUEST} index(\\.php)?
RewriteRule ^index(\\.php)?$ http://www.example.com/ [R=301,L]
# Remove PHP extension from links if NOT subrequest
RewriteRule ^(.+)\\.php$ $1 [R=301,NS,L]
# Serve PHP extension from links
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ /$1.php [L]
Unfortunately after trying some alternatives the outcome I get is either:
.php file extensions suddenly popup again
I get a forbidden access when trying to access any link
Because deep breaths aren’t helping the cause either I came up with the idea to fall back on the oldie but goodie method of 301’s. Given this I came up with:
Works fine for localhost
redirect 301 /index /
Works fine for localhost and online host
redirect 301 /index www.domainnamehere.com
Yes, it’s probably not a smart or professional way to go about it but do I have a choice? After trying it seems not. I just need to remember to remove the line each time I do a major site edit on locahost so it doesn’t display the online version.
It seems Apache is missing an “invisible” operand where it hides displaying a given part of a url if a match is found.
The below code seems to work offline on locahost thus far but when I tried it on my host I think it brought down the whole server. Even if I upload a previous working .htaccess I still can’t load my site online. Can Apache crumble this easily? Even with a .htaccess I can’t get a response online.
All my online host gives me now is “Internal Server Error”. I had this before but found that it was due to be supplying a 301 redirect as a path rather than an absolute url. Sadly this isn’t the case this time.
# Pass Through the empty request (to be handled as DirectoryIndex)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\\ /?\\ HTTP
RewriteRule .? - [PT]
# If index or index.php requested, strip and redirect
RewriteCond %{THE_REQUEST} index(\\.php)?
RewriteRule ^index(\\.php)?$ http://www.domainname.com/ [R=301,L]
# Remove PHP extension from links (internally)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}.php -f
RewriteRule ^(.+)$ /$1.php [L,QSA]
# Remove PHP extension from links (externally)
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\\ /([^.]+\\.)+php\\ HTTP
RewriteRule ^(.+)\\.php$ /$1 [R=301,L]
UPDATE: Okay, so I spoke too soon (not the first time).
My instict was telling me that it’s not that easy to bring down Apache and so I checked my .htaccess file line by line. It turns out there was a \ in there after all and while completely harmless on localhost it reaps havoc on my online host.
Once I removed the \ all is hunky dory again.
The best news of all is that your code now works on both localhost and online host. Such a sigh of relief to see it in action.
Thank you heaps for staying with this thread till the end. There’s a few clear changes you’ve made that I don’t think I would ever contemplate on my own, i.e. the .?, the [PT] etc.
You stated performance might suffer but so far it seems very brisk online, less than a second delay, which is normal for a standard HTTP request anyhow. Excellent.
As I understand it the pass through is necessary so that when we tell it to redirect to a url without a page parameter passed it doesn’t attempt to append a .php and thus instantiates the loop structure.
As for the .? I can’t find a reference to it online. I myself would probably take a wild guess and state it means whatever the file extension is then continue, seems to make sense considering the line directly above it.
[PT] from looking up it online means pass through, or otherwise to set the given URI to the file name so it isn’t empty. My understanding is that we need a file name so Apache knows which file to strip the .php and later remove the index from.
Apache is however definitely considerably more confusing when compared to Windows programming, OODP or otherwise.