MDL-12796 iplookup rewrite
[moodle.git] / lib / geoip / geoip.inc
1 <?php
3 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 2 -*- */
4 /* geoip.inc
5  *
6  * Copyright (C) 2007 MaxMind LLC
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
23 define("GEOIP_COUNTRY_BEGIN", 16776960);
24 define("GEOIP_STATE_BEGIN_REV0", 16700000);
25 define("GEOIP_STATE_BEGIN_REV1", 16000000);
26 define("GEOIP_STANDARD", 0);
27 define("GEOIP_MEMORY_CACHE", 1);
28 define("GEOIP_SHARED_MEMORY", 2);
29 define("STRUCTURE_INFO_MAX_SIZE", 20);
30 define("DATABASE_INFO_MAX_SIZE", 100);
31 define("GEOIP_COUNTRY_EDITION", 106);
32 define("GEOIP_PROXY_EDITION", 8);
33 define("GEOIP_ASNUM_EDITION", 9);
34 define("GEOIP_NETSPEED_EDITION", 10);
35 define("GEOIP_REGION_EDITION_REV0", 112);
36 define("GEOIP_REGION_EDITION_REV1", 3);
37 define("GEOIP_CITY_EDITION_REV0", 111);
38 define("GEOIP_CITY_EDITION_REV1", 2);
39 define("GEOIP_ORG_EDITION", 110);
40 define("GEOIP_ISP_EDITION", 4);
41 define("SEGMENT_RECORD_LENGTH", 3);
42 define("STANDARD_RECORD_LENGTH", 3);
43 define("ORG_RECORD_LENGTH", 4);
44 define("MAX_RECORD_LENGTH", 4);
45 define("MAX_ORG_RECORD_LENGTH", 300);
46 define("GEOIP_SHM_KEY", 0x4f415401);
47 define("US_OFFSET", 1);
48 define("CANADA_OFFSET", 677);
49 define("WORLD_OFFSET", 1353);
50 define("FIPS_RANGE", 360);
51 define("GEOIP_UNKNOWN_SPEED", 0);
52 define("GEOIP_DIALUP_SPEED", 1);
53 define("GEOIP_CABLEDSL_SPEED", 2);
54 define("GEOIP_CORPORATE_SPEED", 3);
56 class GeoIP {
57     var $flags;
58     var $filehandle;
59     var $memory_buffer;
60     var $databaseType;
61     var $databaseSegments;
62     var $record_length;
63     var $shmid;
64     var $GEOIP_COUNTRY_CODE_TO_NUMBER = array(
65 "" => 0, "AP" => 1, "EU" => 2, "AD" => 3, "AE" => 4, "AF" => 5, 
66 "AG" => 6, "AI" => 7, "AL" => 8, "AM" => 9, "AN" => 10, "AO" => 11, 
67 "AQ" => 12, "AR" => 13, "AS" => 14, "AT" => 15, "AU" => 16, "AW" => 17, 
68 "AZ" => 18, "BA" => 19, "BB" => 20, "BD" => 21, "BE" => 22, "BF" => 23, 
69 "BG" => 24, "BH" => 25, "BI" => 26, "BJ" => 27, "BM" => 28, "BN" => 29, 
70 "BO" => 30, "BR" => 31, "BS" => 32, "BT" => 33, "BV" => 34, "BW" => 35, 
71 "BY" => 36, "BZ" => 37, "CA" => 38, "CC" => 39, "CD" => 40, "CF" => 41, 
72 "CG" => 42, "CH" => 43, "CI" => 44, "CK" => 45, "CL" => 46, "CM" => 47, 
73 "CN" => 48, "CO" => 49, "CR" => 50, "CU" => 51, "CV" => 52, "CX" => 53, 
74 "CY" => 54, "CZ" => 55, "DE" => 56, "DJ" => 57, "DK" => 58, "DM" => 59, 
75 "DO" => 60, "DZ" => 61, "EC" => 62, "EE" => 63, "EG" => 64, "EH" => 65, 
76 "ER" => 66, "ES" => 67, "ET" => 68, "FI" => 69, "FJ" => 70, "FK" => 71, 
77 "FM" => 72, "FO" => 73, "FR" => 74, "FX" => 75, "GA" => 76, "GB" => 77,
78 "GD" => 78, "GE" => 79, "GF" => 80, "GH" => 81, "GI" => 82, "GL" => 83, 
79 "GM" => 84, "GN" => 85, "GP" => 86, "GQ" => 87, "GR" => 88, "GS" => 89, 
80 "GT" => 90, "GU" => 91, "GW" => 92, "GY" => 93, "HK" => 94, "HM" => 95, 
81 "HN" => 96, "HR" => 97, "HT" => 98, "HU" => 99, "ID" => 100, "IE" => 101, 
82 "IL" => 102, "IN" => 103, "IO" => 104, "IQ" => 105, "IR" => 106, "IS" => 107, 
83 "IT" => 108, "JM" => 109, "JO" => 110, "JP" => 111, "KE" => 112, "KG" => 113, 
84 "KH" => 114, "KI" => 115, "KM" => 116, "KN" => 117, "KP" => 118, "KR" => 119, 
85 "KW" => 120, "KY" => 121, "KZ" => 122, "LA" => 123, "LB" => 124, "LC" => 125, 
86 "LI" => 126, "LK" => 127, "LR" => 128, "LS" => 129, "LT" => 130, "LU" => 131, 
87 "LV" => 132, "LY" => 133, "MA" => 134, "MC" => 135, "MD" => 136, "MG" => 137, 
88 "MH" => 138, "MK" => 139, "ML" => 140, "MM" => 141, "MN" => 142, "MO" => 143, 
89 "MP" => 144, "MQ" => 145, "MR" => 146, "MS" => 147, "MT" => 148, "MU" => 149, 
90 "MV" => 150, "MW" => 151, "MX" => 152, "MY" => 153, "MZ" => 154, "NA" => 155,
91 "NC" => 156, "NE" => 157, "NF" => 158, "NG" => 159, "NI" => 160, "NL" => 161, 
92 "NO" => 162, "NP" => 163, "NR" => 164, "NU" => 165, "NZ" => 166, "OM" => 167, 
93 "PA" => 168, "PE" => 169, "PF" => 170, "PG" => 171, "PH" => 172, "PK" => 173, 
94 "PL" => 174, "PM" => 175, "PN" => 176, "PR" => 177, "PS" => 178, "PT" => 179, 
95 "PW" => 180, "PY" => 181, "QA" => 182, "RE" => 183, "RO" => 184, "RU" => 185, 
96 "RW" => 186, "SA" => 187, "SB" => 188, "SC" => 189, "SD" => 190, "SE" => 191, 
97 "SG" => 192, "SH" => 193, "SI" => 194, "SJ" => 195, "SK" => 196, "SL" => 197, 
98 "SM" => 198, "SN" => 199, "SO" => 200, "SR" => 201, "ST" => 202, "SV" => 203, 
99 "SY" => 204, "SZ" => 205, "TC" => 206, "TD" => 207, "TF" => 208, "TG" => 209, 
100 "TH" => 210, "TJ" => 211, "TK" => 212, "TM" => 213, "TN" => 214, "TO" => 215, 
101 "TL" => 216, "TR" => 217, "TT" => 218, "TV" => 219, "TW" => 220, "TZ" => 221, 
102 "UA" => 222, "UG" => 223, "UM" => 224, "US" => 225, "UY" => 226, "UZ" => 227, 
103 "VA" => 228, "VC" => 229, "VE" => 230, "VG" => 231, "VI" => 232, "VN" => 233,
104 "VU" => 234, "WF" => 235, "WS" => 236, "YE" => 237, "YT" => 238, "RS" => 239, 
105 "ZA" => 240, "ZM" => 241, "ME" => 242, "ZW" => 243, "A1" => 244, "A2" => 245, 
106 "O1" => 246, "AX" => 247, "GG" => 248, "IM" => 249, "JE" => 250
107 );
108     var $GEOIP_COUNTRY_CODES = array(
109 "", "AP", "EU", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ",
110 "AR", "AS", "AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH",
111 "BI", "BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA",
112 "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU",
113 "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", "EG",
114 "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "FX", "GA", "GB",
115 "GD", "GE", "GF", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR", "GS", "GT",
116 "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", "ID", "IE", "IL", "IN",
117 "IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM",
118 "KN", "KP", "KR", "KW", "KY", "KZ", "LA", "LB", "LC", "LI", "LK", "LR", "LS",
119 "LT", "LU", "LV", "LY", "MA", "MC", "MD", "MG", "MH", "MK", "ML", "MM", "MN",
120 "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA",
121 "NC", "NE", "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA",
122 "PE", "PF", "PG", "PH", "PK", "PL", "PM", "PN", "PR", "PS", "PT", "PW", "PY",
123 "QA", "RE", "RO", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI",
124 "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TC", "TD",
125 "TF", "TG", "TH", "TJ", "TK", "TM", "TN", "TO", "TL", "TR", "TT", "TV", "TW",
126 "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", "VN",
127 "VU", "WF", "WS", "YE", "YT", "RS", "ZA", "ZM", "ME", "ZW", "A1", "A2", "O1",
128 "AX", "GG", "IM", "JE"
129 );
130     var $GEOIP_COUNTRY_CODES3 = array(
131 "","AP","EU","AND","ARE","AFG","ATG","AIA","ALB","ARM","ANT","AGO","AQ","ARG",
132 "ASM","AUT","AUS","ABW","AZE","BIH","BRB","BGD","BEL","BFA","BGR","BHR","BDI",
133 "BEN","BMU","BRN","BOL","BRA","BHS","BTN","BV","BWA","BLR","BLZ","CAN","CC",
134 "COD","CAF","COG","CHE","CIV","COK","CHL","CMR","CHN","COL","CRI","CUB","CPV",
135 "CX","CYP","CZE","DEU","DJI","DNK","DMA","DOM","DZA","ECU","EST","EGY","ESH",
136 "ERI","ESP","ETH","FIN","FJI","FLK","FSM","FRO","FRA","FX","GAB","GBR","GRD",
137 "GEO","GUF","GHA","GIB","GRL","GMB","GIN","GLP","GNQ","GRC","GS","GTM","GUM",
138 "GNB","GUY","HKG","HM","HND","HRV","HTI","HUN","IDN","IRL","ISR","IND","IO",
139 "IRQ","IRN","ISL","ITA","JAM","JOR","JPN","KEN","KGZ","KHM","KIR","COM","KNA",
140 "PRK","KOR","KWT","CYM","KAZ","LAO","LBN","LCA","LIE","LKA","LBR","LSO","LTU",
141 "LUX","LVA","LBY","MAR","MCO","MDA","MDG","MHL","MKD","MLI","MMR","MNG","MAC",
142 "MNP","MTQ","MRT","MSR","MLT","MUS","MDV","MWI","MEX","MYS","MOZ","NAM","NCL",
143 "NER","NFK","NGA","NIC","NLD","NOR","NPL","NRU","NIU","NZL","OMN","PAN","PER",
144 "PYF","PNG","PHL","PAK","POL","SPM","PCN","PRI","PSE","PRT","PLW","PRY","QAT",
145 "REU","ROU","RUS","RWA","SAU","SLB","SYC","SDN","SWE","SGP","SHN","SVN","SJM",
146 "SVK","SLE","SMR","SEN","SOM","SUR","STP","SLV","SYR","SWZ","TCA","TCD","TF",
147 "TGO","THA","TJK","TKL","TLS","TKM","TUN","TON","TUR","TTO","TUV","TWN","TZA",
148 "UKR","UGA","UM","USA","URY","UZB","VAT","VCT","VEN","VGB","VIR","VNM","VUT",
149 "WLF","WSM","YEM","YT","SRB","ZAF","ZMB","MNE","ZWE","A1","A2","O1",
150 "ALA","GGY","IMN","JEY"
151     );
152     var $GEOIP_COUNTRY_NAMES = array(
153 "", "Asia/Pacific Region", "Europe", "Andorra", "United Arab Emirates",
154 "Afghanistan", "Antigua and Barbuda", "Anguilla", "Albania", "Armenia",
155 "Netherlands Antilles", "Angola", "Antarctica", "Argentina", "American Samoa",
156 "Austria", "Australia", "Aruba", "Azerbaijan", "Bosnia and Herzegovina",
157 "Barbados", "Bangladesh", "Belgium", "Burkina Faso", "Bulgaria", "Bahrain",
158 "Burundi", "Benin", "Bermuda", "Brunei Darussalam", "Bolivia", "Brazil",
159 "Bahamas", "Bhutan", "Bouvet Island", "Botswana", "Belarus", "Belize",
160 "Canada", "Cocos (Keeling) Islands", "Congo, The Democratic Republic of the",
161 "Central African Republic", "Congo", "Switzerland", "Cote D'Ivoire", "Cook
162 Islands", "Chile", "Cameroon", "China", "Colombia", "Costa Rica", "Cuba", "Cape
163 Verde", "Christmas Island", "Cyprus", "Czech Republic", "Germany", "Djibouti",
164 "Denmark", "Dominica", "Dominican Republic", "Algeria", "Ecuador", "Estonia",
165 "Egypt", "Western Sahara", "Eritrea", "Spain", "Ethiopia", "Finland", "Fiji",
166 "Falkland Islands (Malvinas)", "Micronesia, Federated States of", "Faroe
167 Islands", "France", "France, Metropolitan", "Gabon", "United Kingdom",
168 "Grenada", "Georgia", "French Guiana", "Ghana", "Gibraltar", "Greenland",
169 "Gambia", "Guinea", "Guadeloupe", "Equatorial Guinea", "Greece", "South Georgia
170 and the South Sandwich Islands", "Guatemala", "Guam", "Guinea-Bissau",
171 "Guyana", "Hong Kong", "Heard Island and McDonald Islands", "Honduras",
172 "Croatia", "Haiti", "Hungary", "Indonesia", "Ireland", "Israel", "India",
173 "British Indian Ocean Territory", "Iraq", "Iran, Islamic Republic of",
174 "Iceland", "Italy", "Jamaica", "Jordan", "Japan", "Kenya", "Kyrgyzstan",
175 "Cambodia", "Kiribati", "Comoros", "Saint Kitts and Nevis", "Korea, Democratic
176 People's Republic of", "Korea, Republic of", "Kuwait", "Cayman Islands",
177 "Kazakstan", "Lao People's Democratic Republic", "Lebanon", "Saint Lucia",
178 "Liechtenstein", "Sri Lanka", "Liberia", "Lesotho", "Lithuania", "Luxembourg",
179 "Latvia", "Libyan Arab Jamahiriya", "Morocco", "Monaco", "Moldova, Republic
180 of", "Madagascar", "Marshall Islands", "Macedonia",
181 "Mali", "Myanmar", "Mongolia", "Macau", "Northern Mariana Islands",
182 "Martinique", "Mauritania", "Montserrat", "Malta", "Mauritius", "Maldives",
183 "Malawi", "Mexico", "Malaysia", "Mozambique", "Namibia", "New Caledonia",
184 "Niger", "Norfolk Island", "Nigeria", "Nicaragua", "Netherlands", "Norway",
185 "Nepal", "Nauru", "Niue", "New Zealand", "Oman", "Panama", "Peru", "French
186 Polynesia", "Papua New Guinea", "Philippines", "Pakistan", "Poland", "Saint
187 Pierre and Miquelon", "Pitcairn Islands", "Puerto Rico", "Palestinian Territory",
188 "Portugal", "Palau", "Paraguay", "Qatar", "Reunion", "Romania",
189 "Russian Federation", "Rwanda", "Saudi Arabia", "Solomon Islands",
190 "Seychelles", "Sudan", "Sweden", "Singapore", "Saint Helena", "Slovenia",
191 "Svalbard and Jan Mayen", "Slovakia", "Sierra Leone", "San Marino", "Senegal",
192 "Somalia", "Suriname", "Sao Tome and Principe", "El Salvador", "Syrian Arab
193 Republic", "Swaziland", "Turks and Caicos Islands", "Chad", "French Southern
194 Territories", "Togo", "Thailand", "Tajikistan", "Tokelau", "Turkmenistan",
195 "Tunisia", "Tonga", "Timor-Leste", "Turkey", "Trinidad and Tobago", "Tuvalu",
196 "Taiwan", "Tanzania, United Republic of", "Ukraine",
197 "Uganda", "United States Minor Outlying Islands", "United States", "Uruguay",
198 "Uzbekistan", "Holy See (Vatican City State)", "Saint Vincent and the
199 Grenadines", "Venezuela", "Virgin Islands, British", "Virgin Islands, U.S.",
200 "Vietnam", "Vanuatu", "Wallis and Futuna", "Samoa", "Yemen", "Mayotte",
201 "Serbia", "South Africa", "Zambia", "Montenegro", "Zimbabwe",
202 "Anonymous Proxy","Satellite Provider","Other",
203 "Aland Islands","Guernsey","Isle of Man","Jersey"
204 );
206 function geoip_load_shared_mem ($file) {
208   $fp = fopen($file, "rb");
209   if (!$fp) {
210     print "error opening $file: $php_errormsg\n";
211     exit;
212   }
213   $s_array = fstat($fp);
214   $size = $s_array['size'];
215   if ($shmid = @shmop_open (GEOIP_SHM_KEY, "w", 0, 0)) {
216     shmop_delete ($shmid);
217     shmop_close ($shmid);
218   }
219   $shmid = shmop_open (GEOIP_SHM_KEY, "c", 0644, $size);
220   shmop_write ($shmid, fread($fp, $size), 0);
221   shmop_close ($shmid);
224 function _setup_segments($gi){
225   $gi->databaseType = GEOIP_COUNTRY_EDITION;
226   $gi->record_length = STANDARD_RECORD_LENGTH;
227   if ($gi->flags & GEOIP_SHARED_MEMORY) {
228     $offset = @shmop_size ($gi->shmid) - 3;
229     for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
230         $delim = @shmop_read ($gi->shmid, $offset, 3);
231         $offset += 3;
232         if ($delim == (chr(255).chr(255).chr(255))) {
233             $gi->databaseType = ord(@shmop_read ($gi->shmid, $offset, 1));
234             $offset++;
236             if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
237                 $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
238             } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
239                 $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
240             } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)||
241                      ($gi->databaseType == GEOIP_CITY_EDITION_REV1) 
242                     || ($gi->databaseType == GEOIP_ORG_EDITION)
243                     || ($gi->databaseType == GEOIP_ISP_EDITION)
244                     || ($gi->databaseType == GEOIP_ASNUM_EDITION)){
245                 $gi->databaseSegments = 0;
246                 $buf = @shmop_read ($gi->shmid, $offset, SEGMENT_RECORD_LENGTH);
247                 for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
248                     $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
249                 }
250                     if (($gi->databaseType == GEOIP_ORG_EDITION)||
251                         ($gi->databaseType == GEOIP_ISP_EDITION)) {
252                         $gi->record_length = ORG_RECORD_LENGTH;
253                 }
254             }
255             break;
256         } else {
257             $offset -= 4;
258         }
259     }
260     if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
261         ($gi->databaseType == GEOIP_PROXY_EDITION)||
262         ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
263         $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
264     }
265   } else {
266     $filepos = ftell($gi->filehandle);
267     fseek($gi->filehandle, -3, SEEK_END);
268     for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
269         $delim = fread($gi->filehandle,3);
270         if ($delim == (chr(255).chr(255).chr(255))){
271         $gi->databaseType = ord(fread($gi->filehandle,1));
272         if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
273             $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
274         }
275         else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
276             $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
277                 }  else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0) ||
278                  ($gi->databaseType == GEOIP_CITY_EDITION_REV1) || 
279                  ($gi->databaseType == GEOIP_ORG_EDITION) || 
280                  ($gi->databaseType == GEOIP_ISP_EDITION) || 
281                  ($gi->databaseType == GEOIP_ASNUM_EDITION)){
282             $gi->databaseSegments = 0;
283             $buf = fread($gi->filehandle,SEGMENT_RECORD_LENGTH);
284             for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
285             $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
286             }
287             if ($gi->databaseType == GEOIP_ORG_EDITION ||
288                 $gi->databaseType == GEOIP_ISP_EDITION) {
289             $gi->record_length = ORG_RECORD_LENGTH;
290             }
291         }
292         break;
293         } else {
294         fseek($gi->filehandle, -4, SEEK_CUR);
295         }
296     }
297     if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
298         ($gi->databaseType == GEOIP_PROXY_EDITION)||
299         ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
300          $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
301     }
302     fseek($gi->filehandle,$filepos,SEEK_SET);
303   }
304   return $gi;
307 function geoip_open($filename, $flags) {
308   $gi = new GeoIP;
309   $gi->flags = $flags;
310   if ($gi->flags & GEOIP_SHARED_MEMORY) {
311     $gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
312     } else {
313     $gi->filehandle = fopen($filename,"rb");
314     if ($gi->flags & GEOIP_MEMORY_CACHE) {
315         $s_array = fstat($gi->filehandle);
316         $gi->memory_buffer = fread($gi->filehandle, $s_array['size']);
317     }
318   }
320   $gi = _setup_segments($gi);
321   return $gi;
324 function geoip_close($gi) {
325   if ($gi->flags & GEOIP_SHARED_MEMORY) {
326     return true;
327   }
329   return fclose($gi->filehandle);
332 function geoip_country_id_by_name($gi, $name) {
333   $addr = gethostbyname($name);
334   if (!$addr || $addr == $name) {
335     return false;
336   }
337   return geoip_country_id_by_addr($gi, $addr);
340 function geoip_country_code_by_name($gi, $name) {
341   $country_id = geoip_country_id_by_name($gi,$name);
342   if ($country_id !== false) {
343         return $gi->GEOIP_COUNTRY_CODES[$country_id];
344   }
345   return false;
348 function geoip_country_name_by_name($gi, $name) {
349   $country_id = geoip_country_id_by_name($gi,$name);
350   if ($country_id !== false) {
351         return $gi->GEOIP_COUNTRY_NAMES[$country_id];
352   }
353   return false;
356 function geoip_country_id_by_addr($gi, $addr) {
357   $ipnum = ip2long($addr);
358   return _geoip_seek_country($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
361 function geoip_country_code_by_addr($gi, $addr) {
362   if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
363     $record = geoip_record_by_addr($gi,$addr);
364     return $record->country_code;
365   } else {
366     $country_id = geoip_country_id_by_addr($gi,$addr);
367     if ($country_id !== false) {
368       return $gi->GEOIP_COUNTRY_CODES[$country_id];
369     }
370   }
371   return false;
374 function geoip_country_name_by_addr($gi, $addr) {
375   if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
376     $record = geoip_record_by_addr($gi,$addr);
377     return $record->country_name;
378   } else {
379     $country_id = geoip_country_id_by_addr($gi,$addr);
380     if ($country_id !== false) {
381       return $gi->GEOIP_COUNTRY_NAMES[$country_id];
382     }
383   }
384   return false;
387 function _geoip_seek_country($gi, $ipnum) {
388   $offset = 0;
389   for ($depth = 31; $depth >= 0; --$depth) {
390     if ($gi->flags & GEOIP_MEMORY_CACHE) {
391       $buf = substr($gi->memory_buffer,
392                             2 * $gi->record_length * $offset,
393                             2 * $gi->record_length);
394         } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
395       $buf = @shmop_read ($gi->shmid, 
396                             2 * $gi->record_length * $offset,
397                             2 * $gi->record_length );
398         } else {
399       fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
400         or die("fseek failed");
401       $buf = fread($gi->filehandle, 2 * $gi->record_length);
402     }
403     $x = array(0,0);
404     for ($i = 0; $i < 2; ++$i) {
405       for ($j = 0; $j < $gi->record_length; ++$j) {
406         $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
407       }
408     }
409     if ($ipnum & (1 << $depth)) {
410       if ($x[1] >= $gi->databaseSegments) {
411         return $x[1];
412       }
413       $offset = $x[1];
414         } else {
415       if ($x[0] >= $gi->databaseSegments) {
416         return $x[0];
417       }
418       $offset = $x[0];
419     }
420   }
421   trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
422   return false;
425 function _get_org($gi,$ipnum){
426   $seek_org = _geoip_seek_country($gi,$ipnum);
427   if ($seek_org == $gi->databaseSegments) {
428     return NULL;
429   }
430   $record_pointer = $seek_org + (2 * $gi->record_length - 1) * $gi->databaseSegments;
431   if ($gi->flags & GEOIP_SHARED_MEMORY) {
432     $org_buf = @shmop_read ($gi->shmid, $record_pointer, MAX_ORG_RECORD_LENGTH);
433     } else {
434     fseek($gi->filehandle, $record_pointer, SEEK_SET);
435     $org_buf = fread($gi->filehandle,MAX_ORG_RECORD_LENGTH);
436   }
437   $org_buf = substr($org_buf, 0, strpos($org_buf, 0));
438   return $org_buf;
441 function geoip_org_by_addr ($gi,$addr) {
442   if ($addr == NULL) {
443     return 0;
444   }
445   $ipnum = ip2long($addr);
446   return _get_org($gi, $ipnum);
449 function _get_region($gi,$ipnum){
450   if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
451     $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV0;
452     if ($seek_region >= 1000){
453       $country_code = "US";
454       $region = chr(($seek_region - 1000)/26 + 65) . chr(($seek_region - 1000)%26 + 65);
455     } else {
456             $country_code = $gi->GEOIP_COUNTRY_CODES[$seek_region];
457       $region = "";
458     }
459   return array ($country_code,$region);
460     }  else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1) {
461     $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV1;
462     //print $seek_region;
463     if ($seek_region < US_OFFSET){
464       $country_code = "";
465       $region = "";  
466         } else if ($seek_region < CANADA_OFFSET) {
467       $country_code = "US";
468       $region = chr(($seek_region - US_OFFSET)/26 + 65) . chr(($seek_region - US_OFFSET)%26 + 65);
469         } else if ($seek_region < WORLD_OFFSET) {
470       $country_code = "CA";
471       $region = chr(($seek_region - CANADA_OFFSET)/26 + 65) . chr(($seek_region - CANADA_OFFSET)%26 + 65);
472     } else {
473             $country_code = $gi->GEOIP_COUNTRY_CODES[($seek_region - WORLD_OFFSET) / FIPS_RANGE];
474       $region = "";
475     }
476   return array ($country_code,$region);
477   }
480 function geoip_region_by_addr ($gi,$addr) {
481   if ($addr == NULL) {
482     return 0;
483   }
484   $ipnum = ip2long($addr);
485   return _get_region($gi, $ipnum);
488 function getdnsattributes ($l,$ip){
489   $r = new Net_DNS_Resolver();
490   $r->nameservers = array("ws1.maxmind.com");
491   $p = $r->search($l."." . $ip .".s.maxmind.com","TXT","IN");
492   $str = is_object($p->answer[0])?$p->answer[0]->string():'';
493   ereg("\"(.*)\"",$str,$regs);
494   $str = $regs[1];
495   return $str;
498 ?>