70948dcdc3bec4bc8df478640f0e06ba023aa156
[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     var $GEOIP_CONTINENT_CODES = array(
208 "--", "AS", "EU", "EU", "AS", "AS", "SA", "SA", "EU", "AS",
209 "SA", "AF", "AN", "SA", "OC", "EU", "OC", "SA", "AS", "EU",
210 "SA", "AS", "EU", "AF", "EU", "AS", "AF", "AF", "SA", "AS",
211 "SA", "SA", "SA", "AS", "AF", "AF", "EU", "SA", "NA", "AS",
212 "AF", "AF", "AF", "EU", "AF", "OC", "SA", "AF", "AS", "SA",
213 "SA", "SA", "AF", "AS", "AS", "EU", "EU", "AF", "EU", "SA",
214 "SA", "AF", "SA", "EU", "AF", "AF", "AF", "EU", "AF", "EU",
215 "OC", "SA", "OC", "EU", "EU", "EU", "AF", "EU", "SA", "AS",
216 "SA", "AF", "EU", "SA", "AF", "AF", "SA", "AF", "EU", "SA",
217 "SA", "OC", "AF", "SA", "AS", "AF", "SA", "EU", "SA", "EU",
218 "AS", "EU", "AS", "AS", "AS", "AS", "AS", "EU", "EU", "SA",
219 "AS", "AS", "AF", "AS", "AS", "OC", "AF", "SA", "AS", "AS",
220 "AS", "SA", "AS", "AS", "AS", "SA", "EU", "AS", "AF", "AF",
221 "EU", "EU", "EU", "AF", "AF", "EU", "EU", "AF", "OC", "EU",
222 "AF", "AS", "AS", "AS", "OC", "SA", "AF", "SA", "EU", "AF",
223 "AS", "AF", "NA", "AS", "AF", "AF", "OC", "AF", "OC", "AF",
224 "SA", "EU", "EU", "AS", "OC", "OC", "OC", "AS", "SA", "SA",
225 "OC", "OC", "AS", "AS", "EU", "SA", "OC", "SA", "AS", "EU",
226 "OC", "SA", "AS", "AF", "EU", "AS", "AF", "AS", "OC", "AF",
227 "AF", "EU", "AS", "AF", "EU", "EU", "EU", "AF", "EU", "AF",
228 "AF", "SA", "AF", "SA", "AS", "AF", "SA", "AF", "AF", "AF",
229 "AS", "AS", "OC", "AS", "AF", "OC", "AS", "EU", "SA", "OC",
230 "AS", "AF", "EU", "AF", "OC", "NA", "SA", "AS", "EU", "SA",
231 "SA", "SA", "SA", "AS", "OC", "OC", "OC", "AS", "AF", "EU",
232 "AF", "AF", "EU", "AF", "--", "--", "--", "EU", "EU", "EU",
233 "EU", "SA", "SA" );
234     
236 function geoip_load_shared_mem ($file) {
238   $fp = fopen($file, "rb");
239   if (!$fp) {
240     print "error opening $file: $php_errormsg\n";
241     exit;
242   }
243   $s_array = fstat($fp);
244   $size = $s_array['size'];
245   if ($shmid = @shmop_open (GEOIP_SHM_KEY, "w", 0, 0)) {
246     shmop_delete ($shmid);
247     shmop_close ($shmid);
248   }
249   $shmid = shmop_open (GEOIP_SHM_KEY, "c", 0644, $size);
250   shmop_write ($shmid, fread($fp, $size), 0);
251   shmop_close ($shmid);
254 function _setup_segments($gi){
255   $gi->databaseType = GEOIP_COUNTRY_EDITION;
256   $gi->record_length = STANDARD_RECORD_LENGTH;
257   if ($gi->flags & GEOIP_SHARED_MEMORY) {
258     $offset = @shmop_size ($gi->shmid) - 3;
259     for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
260         $delim = @shmop_read ($gi->shmid, $offset, 3);
261         $offset += 3;
262         if ($delim == (chr(255).chr(255).chr(255))) {
263             $gi->databaseType = ord(@shmop_read ($gi->shmid, $offset, 1));
264             $offset++;
266             if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
267                 $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
268             } else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
269                 $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
270         } else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0)||
271                      ($gi->databaseType == GEOIP_CITY_EDITION_REV1) 
272                     || ($gi->databaseType == GEOIP_ORG_EDITION)
273             || ($gi->databaseType == GEOIP_ISP_EDITION)
274             || ($gi->databaseType == GEOIP_ASNUM_EDITION)){
275                 $gi->databaseSegments = 0;
276                 $buf = @shmop_read ($gi->shmid, $offset, SEGMENT_RECORD_LENGTH);
277                 for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
278                     $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
279                 }
280                 if (($gi->databaseType == GEOIP_ORG_EDITION)||
281             ($gi->databaseType == GEOIP_ISP_EDITION)) {
282                     $gi->record_length = ORG_RECORD_LENGTH;
283                 }
284             }
285             break;
286         } else {
287             $offset -= 4;
288         }
289     }
290     if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
291         ($gi->databaseType == GEOIP_PROXY_EDITION)||
292         ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
293         $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
294     }
295   } else {
296     $filepos = ftell($gi->filehandle);
297     fseek($gi->filehandle, -3, SEEK_END);
298     for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
299         $delim = fread($gi->filehandle,3);
300         if ($delim == (chr(255).chr(255).chr(255))){
301         $gi->databaseType = ord(fread($gi->filehandle,1));
302         if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
303             $gi->databaseSegments = GEOIP_STATE_BEGIN_REV0;
304         }
305         else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1){
306         $gi->databaseSegments = GEOIP_STATE_BEGIN_REV1;
307                 }  else if (($gi->databaseType == GEOIP_CITY_EDITION_REV0) ||
308                  ($gi->databaseType == GEOIP_CITY_EDITION_REV1) || 
309                  ($gi->databaseType == GEOIP_ORG_EDITION) || 
310          ($gi->databaseType == GEOIP_ISP_EDITION) || 
311                  ($gi->databaseType == GEOIP_ASNUM_EDITION)){
312             $gi->databaseSegments = 0;
313             $buf = fread($gi->filehandle,SEGMENT_RECORD_LENGTH);
314             for ($j = 0;$j < SEGMENT_RECORD_LENGTH;$j++){
315             $gi->databaseSegments += (ord($buf[$j]) << ($j * 8));
316             }
317         if ($gi->databaseType == GEOIP_ORG_EDITION ||
318         $gi->databaseType == GEOIP_ISP_EDITION) {
319         $gi->record_length = ORG_RECORD_LENGTH;
320             }
321         }
322         break;
323         } else {
324         fseek($gi->filehandle, -4, SEEK_CUR);
325         }
326     }
327     if (($gi->databaseType == GEOIP_COUNTRY_EDITION)||
328         ($gi->databaseType == GEOIP_PROXY_EDITION)||
329         ($gi->databaseType == GEOIP_NETSPEED_EDITION)){
330          $gi->databaseSegments = GEOIP_COUNTRY_BEGIN;
331     }
332     fseek($gi->filehandle,$filepos,SEEK_SET);
333   }
334   return $gi;
337 function geoip_open($filename, $flags) {
338   $gi = new GeoIP;
339   $gi->flags = $flags;
340   if ($gi->flags & GEOIP_SHARED_MEMORY) {
341     $gi->shmid = @shmop_open (GEOIP_SHM_KEY, "a", 0, 0);
342     } else {
343     $gi->filehandle = fopen($filename,"rb") or die( "Can not open $filename\n" );
344     if ($gi->flags & GEOIP_MEMORY_CACHE) {
345         $s_array = fstat($gi->filehandle);
346         $gi->memory_buffer = fread($gi->filehandle, $s_array['size']);
347     }
348   }
350   $gi = _setup_segments($gi);
351   return $gi;
354 function geoip_close($gi) {
355   if ($gi->flags & GEOIP_SHARED_MEMORY) {
356     return true;
357   }
359   return fclose($gi->filehandle);
362 function geoip_country_id_by_name($gi, $name) {
363   $addr = gethostbyname($name);
364   if (!$addr || $addr == $name) {
365     return false;
366   }
367   return geoip_country_id_by_addr($gi, $addr);
370 function geoip_country_code_by_name($gi, $name) {
371   $country_id = geoip_country_id_by_name($gi,$name);
372   if ($country_id !== false) {
373         return $gi->GEOIP_COUNTRY_CODES[$country_id];
374   }
375   return false;
378 function geoip_country_name_by_name($gi, $name) {
379   $country_id = geoip_country_id_by_name($gi,$name);
380   if ($country_id !== false) {
381         return $gi->GEOIP_COUNTRY_NAMES[$country_id];
382   }
383   return false;
386 function geoip_country_id_by_addr($gi, $addr) {
387   $ipnum = ip2long($addr);
388   return _geoip_seek_country($gi, $ipnum) - GEOIP_COUNTRY_BEGIN;
391 function geoip_country_code_by_addr($gi, $addr) {
392   if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
393     $record = geoip_record_by_addr($gi,$addr);
394     if ( $record !== false ) {
395       return $record->country_code;
396     }
397   } else {
398     $country_id = geoip_country_id_by_addr($gi,$addr);
399     if ($country_id !== false) {
400       return $gi->GEOIP_COUNTRY_CODES[$country_id];
401     }
402   }
403   return false;
406 function geoip_country_name_by_addr($gi, $addr) {
407   if ($gi->databaseType == GEOIP_CITY_EDITION_REV1) {
408     $record = geoip_record_by_addr($gi,$addr);
409     return $record->country_name;
410   } else {
411     $country_id = geoip_country_id_by_addr($gi,$addr);
412     if ($country_id !== false) {
413       return $gi->GEOIP_COUNTRY_NAMES[$country_id];
414     }
415   }
416   return false;
419 function _geoip_seek_country($gi, $ipnum) {
420   $offset = 0;
421   for ($depth = 31; $depth >= 0; --$depth) {
422     if ($gi->flags & GEOIP_MEMORY_CACHE) {
423       // workaround php's broken substr, strpos, etc handling with
424       // mbstring.func_overload and mbstring.internal_encoding
425       $enc = mb_internal_encoding();
426        mb_internal_encoding('ISO-8859-1'); 
428       $buf = substr($gi->memory_buffer,
429                             2 * $gi->record_length * $offset,
430                             2 * $gi->record_length);
432       mb_internal_encoding($enc);
433     } elseif ($gi->flags & GEOIP_SHARED_MEMORY) {
434       $buf = @shmop_read ($gi->shmid, 
435                             2 * $gi->record_length * $offset,
436                             2 * $gi->record_length );
437         } else {
438       fseek($gi->filehandle, 2 * $gi->record_length * $offset, SEEK_SET) == 0
439         or die("fseek failed");
440       $buf = fread($gi->filehandle, 2 * $gi->record_length);
441     }
442     $x = array(0,0);
443     for ($i = 0; $i < 2; ++$i) {
444       for ($j = 0; $j < $gi->record_length; ++$j) {
445         $x[$i] += ord($buf[$gi->record_length * $i + $j]) << ($j * 8);
446       }
447     }
448     if ($ipnum & (1 << $depth)) {
449       if ($x[1] >= $gi->databaseSegments) {
450         return $x[1];
451       }
452       $offset = $x[1];
453         } else {
454       if ($x[0] >= $gi->databaseSegments) {
455         return $x[0];
456       }
457       $offset = $x[0];
458     }
459   }
460   trigger_error("error traversing database - perhaps it is corrupt?", E_USER_ERROR);
461   return false;
464 function _get_org($gi,$ipnum){
465   $seek_org = _geoip_seek_country($gi,$ipnum);
466   if ($seek_org == $gi->databaseSegments) {
467     return NULL;
468   }
469   $record_pointer = $seek_org + (2 * $gi->record_length - 1) * $gi->databaseSegments;
470   if ($gi->flags & GEOIP_SHARED_MEMORY) {
471     $org_buf = @shmop_read ($gi->shmid, $record_pointer, MAX_ORG_RECORD_LENGTH);
472     } else {
473     fseek($gi->filehandle, $record_pointer, SEEK_SET);
474     $org_buf = fread($gi->filehandle,MAX_ORG_RECORD_LENGTH);
475   }
476   // workaround php's broken substr, strpos, etc handling with
477   // mbstring.func_overload and mbstring.internal_encoding
478   $enc = mb_internal_encoding();
479   mb_internal_encoding('ISO-8859-1'); 
480   $org_buf = substr($org_buf, 0, strpos($org_buf, 0));
481   mb_internal_encoding($enc);
482   return $org_buf;
485 function geoip_org_by_addr ($gi,$addr) {
486   if ($addr == NULL) {
487     return 0;
488   }
489   $ipnum = ip2long($addr);
490   return _get_org($gi, $ipnum);
493 function _get_region($gi,$ipnum){
494   if ($gi->databaseType == GEOIP_REGION_EDITION_REV0){
495     $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV0;
496     if ($seek_region >= 1000){
497       $country_code = "US";
498       $region = chr(($seek_region - 1000)/26 + 65) . chr(($seek_region - 1000)%26 + 65);
499     } else {
500             $country_code = $gi->GEOIP_COUNTRY_CODES[$seek_region];
501       $region = "";
502     }
503   return array ($country_code,$region);
504     }  else if ($gi->databaseType == GEOIP_REGION_EDITION_REV1) {
505     $seek_region = _geoip_seek_country($gi,$ipnum) - GEOIP_STATE_BEGIN_REV1;
506     //print $seek_region;
507     if ($seek_region < US_OFFSET){
508       $country_code = "";
509       $region = "";  
510         } else if ($seek_region < CANADA_OFFSET) {
511       $country_code = "US";
512       $region = chr(($seek_region - US_OFFSET)/26 + 65) . chr(($seek_region - US_OFFSET)%26 + 65);
513         } else if ($seek_region < WORLD_OFFSET) {
514       $country_code = "CA";
515       $region = chr(($seek_region - CANADA_OFFSET)/26 + 65) . chr(($seek_region - CANADA_OFFSET)%26 + 65);
516     } else {
517             $country_code = $gi->GEOIP_COUNTRY_CODES[($seek_region - WORLD_OFFSET) / FIPS_RANGE];
518       $region = "";
519     }
520   return array ($country_code,$region);
521   }
524 function geoip_region_by_addr ($gi,$addr) {
525   if ($addr == NULL) {
526     return 0;
527   }
528   $ipnum = ip2long($addr);
529   return _get_region($gi, $ipnum);
532 function getdnsattributes ($l,$ip){
533   $r = new Net_DNS_Resolver();
534   $r->nameservers = array("ws1.maxmind.com");
535   $p = $r->search($l."." . $ip .".s.maxmind.com","TXT","IN");
536   $str = is_object($p->answer[0])?$p->answer[0]->string():'';
537   preg_match("#\"(.*)\"#",$str,$regs);
538   $str = $regs[1];
539   return $str;
542 ?>