3
* Horde optimized interface to the MaxMind IP Address->Country
6
* $Horde: framework/NLS/NLS/GeoIP.php,v 1.10.10.1 2005/01/03 12:19:08 jan Exp $
8
* Based on PHP geoip.inc library by MaxMind LLC:
9
* http://www.maxmind.com/download/geoip/api/php/
11
* Originally based on php version of the geoip library written in May
12
* 2002 by jim winstead <jimw@apache.org>
14
* Copyright (C) 2003 MaxMind LLC
15
* Copyright 2003-2005 Michael Slusarz <slusarz@bigworm.colorado.edu>
17
* This library is free software; you can redistribute it and/or
18
* modify it under the terms of the GNU Lesser General Public
19
* License as published by the Free Software Foundation; either
20
* version 2.1 of the License, or (at your option) any later version.
22
* See the enclosed file COPYING for license information (LGPL). If you
23
* did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
25
* @author Michael Slusarz <slusarz@bigworm.colorado.edu>
26
* @version $Revision: 1.10.10.1 $
32
$GLOBALS['GEOIP_COUNTRY_CODES'] = array(
33
'', 'AP', 'EU', 'AD', 'AE', 'AF', 'AG', 'AI', 'AL', 'AM', 'AN', 'AO', 'AQ',
34
'AR', 'AS', 'AT', 'AU', 'AW', 'AZ', 'BA', 'BB', 'BD', 'BE', 'BF', 'BG', 'BH',
35
'BI', 'BJ', 'BM', 'BN', 'BO', 'BR', 'BS', 'BT', 'BV', 'BW', 'BY', 'BZ', 'CA',
36
'CC', 'CD', 'CF', 'CG', 'CH', 'CI', 'CK', 'CL', 'CM', 'CN', 'CO', 'CR', 'CU',
37
'CV', 'CX', 'CY', 'CZ', 'DE', 'DJ', 'DK', 'DM', 'DO', 'DZ', 'EC', 'EE', 'EG',
38
'EH', 'ER', 'ES', 'ET', 'FI', 'FJ', 'FK', 'FM', 'FO', 'FR', 'FX', 'GA', 'UK',
39
'GD', 'GE', 'GF', 'GH', 'GI', 'GL', 'GM', 'GN', 'GP', 'GQ', 'GR', 'GS', 'GT',
40
'GU', 'GW', 'GY', 'HK', 'HM', 'HN', 'HR', 'HT', 'HU', 'ID', 'IE', 'IL', 'IN',
41
'IO', 'IQ', 'IR', 'IS', 'IT', 'JM', 'JO', 'JP', 'KE', 'KG', 'KH', 'KI', 'KM',
42
'KN', 'KP', 'KR', 'KW', 'KY', 'KZ', 'LA', 'LB', 'LC', 'LI', 'LK', 'LR', 'LS',
43
'LT', 'LU', 'LV', 'LY', 'MA', 'MC', 'MD', 'MG', 'MH', 'MK', 'ML', 'MM', 'MN',
44
'MO', 'MP', 'MQ', 'MR', 'MS', 'MT', 'MU', 'MV', 'MW', 'MX', 'MY', 'MZ', 'NA',
45
'NC', 'NE', 'NF', 'NG', 'NI', 'NL', 'NO', 'NP', 'NR', 'NU', 'NZ', 'OM', 'PA',
46
'PE', 'PF', 'PG', 'PH', 'PK', 'PL', 'PM', 'PN', 'PR', 'PS', 'PT', 'PW', 'PY',
47
'QA', 'RE', 'RO', 'RU', 'RW', 'SA', 'SB', 'SC', 'SD', 'SE', 'SG', 'SH', 'SI',
48
'SJ', 'SK', 'SL', 'SM', 'SN', 'SO', 'SR', 'ST', 'SV', 'SY', 'SZ', 'TC', 'TD',
49
'TF', 'TG', 'TH', 'TJ', 'TK', 'TM', 'TN', 'TO', 'TP', 'TR', 'TT', 'TV', 'TW',
50
'TZ', 'UA', 'UG', 'UM', 'US', 'UY', 'UZ', 'VA', 'VC', 'VE', 'VG', 'VI', 'VN',
51
'VU', 'WF', 'WS', 'YE', 'YT', 'YU', 'ZA', 'ZM', 'ZR', 'ZW', 'A1', 'A2', 'O1'
55
$GLOBALS['GEOIP_COUNTRY_NAMES'] = array(
56
"", _("Asia/Pacific Region"), _("Europe"), _("Andorra"),
57
_("United Arab Emirates"), _("Afghanistan"), _("Antigua and Barbuda"),
58
_("Anguilla"), _("Albania"), _("Armenia"), _("Netherlands Antilles"),
59
_("Angola"), _("Antarctica"), _("Argentina"), _("American Samoa"),
60
_("Austria"), _("Australia"), _("Aruba"), _("Azerbaijan"),
61
_("Bosnia and Herzegovina"), _("Barbados"), _("Bangladesh"), _("Belgium"),
62
_("Burkina Faso"), _("Bulgaria"), _("Bahrain"), _("Burundi"), _("Benin"),
63
_("Bermuda"), _("Brunei Darussalam"), _("Bolivia"), _("Brazil"), _("Bahamas"),
64
_("Bhutan"), _("Bouvet Island"), _("Botswana"), _("Belarus"), _("Belize"),
65
_("Canada"), _("Cocos (Keeling) Islands"),
66
_("Congo, The Democratic Republic of the"), _("Central African Republic"),
67
_("Congo"), _("Switzerland"), _("Cote d'Ivoire"), _("Cook Islands"),
68
_("Chile"), _("Cameroon"), _("China"), _("Colombia"), _("Costa Rica"),
69
_("Cuba"), _("Cape Verde"), _("Christmas Island"), _("Cyprus"),
70
_("Czech Republic"), _("Germany"), _("Djibouti"), _("Denmark"), _("Dominica"),
71
_("Dominican Republic"), _("Algeria"), _("Ecuador"), _("Estonia"), _("Egypt"),
72
_("Western Sahara"), _("Eritrea"), _("Spain"), _("Ethiopia"), _("Finland"),
73
_("Fiji"), _("Falkland Islands (Malvinas)"), _("Micronesia, Federated States of"),
74
_("Faroe Islands"), _("France"), _("France, Metropolitan"), _("Gabon"),
75
_("United Kingdom"), _("Grenada"), _("Georgia"), _("French Guiana"),
76
_("Ghana"), _("Gibraltar"), _("Greenland"), _("Gambia"), _("Guinea"),
77
_("Guadeloupe"), _("Equatorial Guinea"), _("Greece"),
78
_("South Georgia and the South Sandwich Islands"), _("Guatemala"), _("Guam"),
79
_("Guinea-Bissau"), _("Guyana"), _("Hong Kong"),
80
_("Heard Island and McDonald Islands"), _("Honduras"), _("Croatia"),
81
_("Haiti"), _("Hungary"), _("Indonesia"), _("Ireland"), _("Israel"),
82
_("India"), _("British Indian Ocean Territory"), _("Iraq"),
83
_("Iran, Islamic Republic of"), _("Iceland"), _("Italy"), _("Jamaica"),
84
_("Jordan"), _("Japan"), _("Kenya"), _("Kyrgyzstan"), _("Cambodia"),
85
_("Kiribati"), _("Comoros"), _("Saint Kitts and Nevis"),
86
_("Korea, Democratic People's Republic of"), _("Korea, Republic of"),
87
_("Kuwait"), _("Cayman Islands"), _("Kazakhstan"),
88
_("Lao People's Democratic Republic"), _("Lebanon"), _("Saint Lucia"),
89
_("Liechtenstein"), _("Sri Lanka"), _("Liberia"), _("Lesotho"),
90
_("Lithuania"), _("Luxembourg"), _("Latvia"), _("Libyan Arab Jamahiriya"),
91
_("Morocco"), _("Monaco"), _("Moldova, Republic of"), _("Madagascar"),
92
_("Marshall Islands"), _("Macedonia, The Former Yugoslav Republic of"),
93
_("Mali"), _("Myanmar"), _("Mongolia"), _("Macao"),
94
_("Northern Mariana Islands"), _("Martinique"), _("Mauritania"),
95
_("Montserrat"), _("Malta"), _("Mauritius"), _("Maldives"), _("Malawi"),
96
_("Mexico"), _("Malaysia"), _("Mozambique"), _("Namibia"), _("New Caledonia"),
97
_("Niger"), _("Norfolk Island"), _("Nigeria"), _("Nicaragua"),
98
_("Netherlands"), _("Norway"), _("Nepal"), _("Nauru"), _("Niue"),
99
_("New Zealand"), _("Oman"), _("Panama"), _("Peru"), _("French Polynesia"),
100
_("Papua New Guinea"), _("Philippines"), _("Pakistan"), _("Poland"),
101
_("Saint Pierre and Miquelon"), _("Pitcairn"), _("Puerto Rico"),
102
_("Palestinian Territory, Occupied"), _("Portugal"), _("Palau"),
103
_("Paraguay"), _("Qatar"), _("Reunion"), _("Romania"),
104
_("Russian Federation"), _("Rwanda"), _("Saudi Arabia"), _("Solomon Islands"),
105
_("Seychelles"), _("Sudan"), _("Sweden"), _("Singapore"), _("Saint Helena"),
106
_("Slovenia"), _("Svalbard and Jan Mayen"), _("Slovakia"), _("Sierra Leone"),
107
_("San Marino"), _("Senegal"), _("Somalia"), _("Suriname"),
108
_("Sao Tome and Principe"), _("El Salvador"), _("Syrian Arab Republic"),
109
_("Swaziland"), _("Turks and Caicos Islands"), _("Chad"),
110
_("French Southern Territories"), _("Togo"), _("Thailand"), _("Tajikistan"),
111
_("Tokelau"), _("Turkmenistan"), _("Tunisia"), _("Tonga"), _("Timor-Leste"),
112
_("Turkey"), _("Trinidad and Tobago"), _("Tuvalu"), _("Taiwan"),
113
_("Tanzania, United Republic of"), _("Ukraine"), _("Uganda"),
114
_("United States Minor Outlying Islands"), _("United States"), _("Uruguay"),
115
_("Uzbekistan"), _("Holy See (Vatican City State)"),
116
_("Saint Vincent and the Grenadines"), _("Venezuela"),
117
_("Virgin Islands, British"), _("Virgin Islands, U.S."), _("Viet Nam"),
118
_("Vanuatu"), _("Wallis and Futuna"), _("Samoa"), _("Yemen"), _("Mayotte"),
119
_("Yugoslavia"), _("South Africa"), _("Zambia"), _("Zaire"), _("Zimbabwe"),
120
_("Anonymous Proxy"), _("Satellite Provider"), _("Other")
123
define('GEOIP_COUNTRY_BEGIN', 16776960);
124
define('STRUCTURE_INFO_MAX_SIZE', 20);
125
define('STANDARD_RECORD_LENGTH', 3);
130
* The location of the GeoIP database.
132
* @var string $_datafile
137
* The open filehandle to the GeoIP database.
139
* @var resource $_filehandle
144
* Returns a reference to the global NLS_GeoIP object, only creating it
145
* if it doesn't already exist.
147
* This method must be invoked as:
148
* $geoip = &GeoIP::singleton($datafile);
152
* @param string $datafile The location of the GeoIP database.
154
* @return object NLS_GeoIP The NLS_GeoIP instance.
156
function &singleton($datafile)
160
if (!isset($instance)) {
161
$instance = new NLS_GeoIP($datafile);
168
* Create a NLS_GeoIP instance (Constructor).
172
* @param string $datafile The location of the GeoIP database.
174
function NLS_GeoIP($datafile)
176
$this->_datafile = $datafile;
180
* Open the GeoIP database.
184
* @return boolean False on error.
188
/* Return if we already have an object. */
189
if (!empty($this->_gi)) {
193
/* Return if no datafile specified. */
194
if (empty($this->_datafile)) {
198
$this->_filehandle = fopen($this->_datafile, 'rb');
200
$filepos = ftell($this->_filehandle);
201
fseek($this->_filehandle, -3, SEEK_END);
202
for ($i = 0; $i < STRUCTURE_INFO_MAX_SIZE; $i++) {
203
$delim = fread($this->_filehandle, 3);
204
if ($delim == (chr(255) . chr(255) . chr(255))) {
207
fseek($this->_filehandle, -4, SEEK_CUR);
210
fseek($this->_filehandle, $filepos, SEEK_SET);
216
* Returns the country ID for a hostname.
220
* @param string $name The hostname.
222
* @return integer The GeoIP country ID.
224
function countryIdByName($name)
226
if (!$this->_open()) {
229
$addr = gethostbyname($name);
230
if (!$addr || $addr == $name) {
233
return $this->countryIdByAddr($addr);
237
* Returns the country abbreviation (2-letter) for a hostname.
241
* @param string $name The hostname.
243
* @return integer The country abbreviation.
245
function countryCodeByName($name)
247
if ($this->_open()) {
248
$country_id = $this->countryIdByName($name);
249
if ($country_id !== false) {
250
return $GLOBALS['GEOIP_COUNTRY_CODES'][$country_id];
257
* Returns the country name for a hostname.
261
* @param string $name The hostname.
263
* @return integer The country name.
265
function countryNameByName($name)
267
if ($this->_open()) {
268
$country_id = $this->countryIdByName($name);
269
if ($country_id !== false) {
270
return $GLOBALS['GEOIP_COUNTRY_NAMES'][$country_id];
277
* Returns the country ID for an IP Address.
281
* @param string $addr The IP Address.
283
* @return integer The GeoIP country ID.
285
function countryIdByAddr($addr)
287
if (!$this->_open()) {
290
$ipnum = ip2long($addr);
291
return ($this->_seekCountry($ipnum) - GEOIP_COUNTRY_BEGIN);
295
* Returns the country abbreviation (2-letter) for an IP Address.
299
* @param string $addr The IP Address.
301
* @return integer The country abbreviation.
303
function countryCodeByAddr($addr)
305
if ($this->_open()) {
306
$country_id = $this->countryIdByAddr($addr);
307
if ($country_id !== false) {
308
return $GLOBALS['GEOIP_COUNTRY_CODES'][$country_id];
315
* Returns the country name for an IP address.
319
* @param string $addr The IP address.
321
* @return mixed The country name.
323
function countryNameByAddr($addr)
325
if ($this->_open()) {
326
$country_id = $this->countryIdByAddr($addr);
327
if ($country_id !== false) {
328
return $GLOBALS['GEOIP_COUNTRY_NAMES'][$country_id];
335
* Finds a country by IP Address in the GeoIP database.
339
* @param string $ipnum The IP Address to search for.
341
* @return mixed The country ID or false if not found.
342
* Returns PEAR_Error on error.
344
function _seekCountry($ipnum)
347
for ($depth = 31; $depth >= 0; --$depth) {
348
if (fseek($this->_filehandle, 2 * STANDARD_RECORD_LENGTH * $offset, SEEK_SET) != 0) {
349
return PEAR::raiseError('fseek failed');
351
$buf = fread($this->_filehandle, 2 * STANDARD_RECORD_LENGTH);
353
for ($i = 0; $i < 2; ++$i) {
354
for ($j = 0; $j < STANDARD_RECORD_LENGTH; ++$j) {
355
$x[$i] += ord($buf[STANDARD_RECORD_LENGTH * $i + $j]) << ($j * 8);
358
if ($ipnum & (1 << $depth)) {
359
if ($x[1] >= GEOIP_COUNTRY_BEGIN) {
364
if ($x[0] >= GEOIP_COUNTRY_BEGIN) {