Motivation
Any Website may be accessible by several addresses. Often host names like example.com and www.example.com address the same website. It may be useful to be reachable through both addresses but to display only one of them in the browsers address bar. To do so you can redirect from example.com to www.example.com
One server may host many websites at the same time. Which site to deliver is decided based on the given host name within the HTTP request.
www.example.com — unknown host!
What should a server do when it gets a request for a host it doen not know? It provides it default page. Some of the big commercial hosters have error or advertising pages for that purpose.
Under the cover of host names the internetuses IP addresses. These are based on numbers and they may be long and ugly. The domain name system (DNS) is there to get the corresponding IP address to a host name. When you enter www.richler.de in your webbrowser it asks a nameserver for the IP address (87.106.74.74) and sends a HTTP request to this address.
The domains richler.de and richler.info are set up, like many others too, as wildcard domains. This means any hostnames in this domain point to the same address. In my case both domains point to the same address. So invalid.richler.de points to the same address as invalid.richler.de and so to the same default page of the webserver.
Redirect — but individually
If you don't want to loose visitors you should provide a useful standard page or redirect them to your main website. This should happen based on the given host name. A request for invalid.richler.de should redirect to www.richler.de while a request for not-there.richler.info should redirect to www.richler.info
What is checkHostname()?
checkHostname uses a config file to determ where to redirect to.
To be able to perform a redirect the function must be called before any HTML code is send to the client.
In case of a redirection the original PHP script is terminated in the other case the function
returns true or false. false indicates a redirection
loop. The destination of the redirection is performing this redirection again. Some browsers, like
Microsoft Internet Explorer™ 6, wound't detect that.
A tiny example:
1
<?php
2
3 require_once('chkHostname');
4
5 if (!checkHostname('hosts.ini')) {
6 echo 'this is an error!';
7 }
8
9 ?><html>
10 <body>
11 <h1>Welcome</h1>
12 </body>
13 </html>
The redirection is controlled by a config or ini file. The hostnames are given in squared brackets followed by some parameters. Only the first matching host name will be observed, all others will be ignored.
In the example (hosts.ini) in line 1 a rule for www.richler.de is defined. As there are no parameters no redirection will be performed. This may be used to exclude certain hosts from being redirected.
Starting from line 4 a redirection from ww.richler.de to www.richler.de is configured.
In line 7 with *.richler.de a rule for all sub domains of richler.de is defined. This matches any host name ending with .richler.de. So this rule would even match for www.richler.de. But as the rule in line 1 matches first this rule would not be reached.
The rule for richler.de has two new parameters. keepquery = true tells to keep the given query. So from http://richler.de/page.html will be redirected to http://www.richler.de/page.html. Without keepquery the destination would be http://www.richler.de.
HTTP knows to kinds of redirection; temporarily and permanent. Permanent redirections may be remembered by browsers or proxies. So there is no need to send the same request again. But even search engines may use this information to replace a permanent redirected page in their index with the redirection destination.
1 [www.richler.de]
2
; do nothing - no more rules will be checked
3
4
5
[ww.richler.de]
6
redirect = http://www.richler.de/
7
8
9
[*.richler.de]
10
redirect = http://www.richler.de/
11
12
13
[*.richler.info]
14
redirect = http://www.richler.info/
15
16
17
[richler.de]
18
redirect = http://www.richler.de
19
20
keepquery = true
21
22
permanent = true
23
24
25
; Default:
26
27
[*]
28
redirect = http://www.richler.de/
The function checkHostname()
1
<?php
2 /*********************************************************************
3 *
4 * Reads a given ini-File and does some Redirection based on Hostnames
5 *
6 * If there is a matching rule this function will redirect to an other
7 * site. If there is no matching rule or one with no destination it
8 * returns true. If there is a matching rule but the function detects
9 * a loop it returns false.
10 *
11 * (C) 2006 by Heiko Richler http://www.richler.de/
12 *
13 * This Code is provided unter the GNU Lesser General Public License
14 * http://www.gnu.org/licenses/lgpl.html
15 *
16 * No warranty at all!
17 */
18 function checkHostname($inifile = 'hosts.ini') {
19 // Load ini-File. Each section in this file represents an
20 // Domainname to match.
21 $ini = parse_ini_file($inifile, true);
22 foreach($ini as $domain => $vArgs) {
23 // Create regular expression out of Domainname. It may
24 // contain * as a wildcard
25 $regex = '/^' . str_replace(array('.', '*'),
26 array('\.', '.*'), $domain) . '$/i';
27 if (preg_match($regex, $_SERVER['HTTP_HOST'])) {
28 if (isset($vArgs['redirect'])) {
29 $destination = $vArgs['redirect'];
30 if (isset($vArgs['keepquery']) and $vArgs['keepquery']) {
31 $destination .= $_SERVER['REQUEST_URI'].
32 $_SERVER['QUERY_STRING'];
33 }
34 $old = 'http'.
35 (($_SERVER['HTTPS'] == 'on') ? 'S' : '').
36 '://'.
37 $_SERVER['HTTP_HOST'].
38 $_SERVER['REQUEST_URI'].
39 $_SERVER['QUERY_STRING'];
40 if ($old == $destination) { // this would be a loop!
41 // error_log(...) ?
42 return false;
43 }
44 $counter = 0;
45 if (isset($_COOKIE['RedirectCounter'])) {
46 $counter = @intval($_COOKIE['RedirectCounter']);
47 }
48 if (isset($_COOKIE['Redirected'])) {
49 // I redirected from here ...
50 if ($_COOKIE['Redirected']>=time()-5) {
51 // ... and I did so within the last 5 seconds
52 // this should be a lot of time - even for a
53 // slow client
54 $counter++;
55 }
56 else {
57 // after more than 5 seconds I believe this was a
58 // reload by user
59 $counter = 0;
60 }
61 }
62 if ($counter>19) { // Firefox waits till 20 to detect a loop
63 // this may be a loop!
64 // error_log(...) ?
65 return false;
66 }
67 setcookie('Redirected',time(),time()+60); // 60 seconds
68 setcookie('RedirectCounter',$counter,time()+60); // 60 seconds
69 if (isset($vArgs['permanent']) and $vArgs['permanent']) {
70 // Use a permanent reddirect means the client may
71 // remember it and doesn't ask for the original site
72 // again soon.
73 header('HTTP/1.1 301 Moved Permanently');
74 }
75 header("Location:$destination");
76 echo "<html><body>
77 <a href='$destination'>Redirecting to $destination.</a>
78 </body></html>";
79 die(); // do nothing else
80 }
81 // No Destination to redirect to, so do nothing
82 // This can be used to set a rule without redirecting to
83 // avoid following rules to match.
84 return true;
85 }
86 }
87 // No Matching Rule
88 return true;
89 }
90 ?>
Download chkHostname.php
here you may download the source with an example: chkHostname.zip.