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