1<?php 2 3/* geoipcity.inc 4 * 5 * Copyright (C) 2013 MaxMind, Inc. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 22 23define("FULL_RECORD_LENGTH", 50); 24 25require_once 'geoip.inc'; 26require_once 'geoipregionvars.php'; 27 28class geoiprecord 29{ 30 public $country_code; 31 public $country_code3; 32 public $country_name; 33 public $region; 34 public $city; 35 public $postal_code; 36 public $latitude; 37 public $longitude; 38 public $area_code; 39 public $dma_code; # metro and dma code are the same. use metro_code 40 public $metro_code; 41 public $continent_code; 42} 43 44function _get_record_v6($gi, $ipnum) 45{ 46 $seek_country = _geoip_seek_country_v6($gi, $ipnum); 47 if ($seek_country == $gi->databaseSegments) { 48 return null; 49 } 50 return _common_get_record($gi, $seek_country); 51} 52 53function _common_get_record($gi, $seek_country) 54{ 55 // workaround php's broken substr, strpos, etc handling with 56 // mbstring.func_overload and mbstring.internal_encoding 57 $mbExists = extension_loaded('mbstring'); 58 if ($mbExists) { 59 $enc = mb_internal_encoding(); 60 mb_internal_encoding('ISO-8859-1'); 61 } 62 63 $record_pointer = $seek_country + (2 * $gi->record_length - 1) * $gi->databaseSegments; 64 65 if ($gi->flags & GEOIP_MEMORY_CACHE) { 66 $record_buf = substr($gi->memory_buffer, $record_pointer, FULL_RECORD_LENGTH); 67 } elseif ($gi->flags & GEOIP_SHARED_MEMORY) { 68 $record_buf = @shmop_read($gi->shmid, $record_pointer, FULL_RECORD_LENGTH); 69 } else { 70 fseek($gi->filehandle, $record_pointer, SEEK_SET); 71 $record_buf = fread($gi->filehandle, FULL_RECORD_LENGTH); 72 } 73 $record = new geoiprecord; 74 $record_buf_pos = 0; 75 $char = ord(substr($record_buf, $record_buf_pos, 1)); 76 $record->country_code = $gi->GEOIP_COUNTRY_CODES[$char]; 77 $record->country_code3 = $gi->GEOIP_COUNTRY_CODES3[$char]; 78 $record->country_name = $gi->GEOIP_COUNTRY_NAMES[$char]; 79 $record->continent_code = $gi->GEOIP_CONTINENT_CODES[$char]; 80 $record_buf_pos++; 81 $str_length = 0; 82 83 // Get region 84 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 85 while ($char != 0) { 86 $str_length++; 87 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 88 } 89 if ($str_length > 0) { 90 $record->region = substr($record_buf, $record_buf_pos, $str_length); 91 } 92 $record_buf_pos += $str_length + 1; 93 $str_length = 0; 94 // Get city 95 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 96 while ($char != 0) { 97 $str_length++; 98 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 99 } 100 if ($str_length > 0) { 101 $record->city = substr($record_buf, $record_buf_pos, $str_length); 102 } 103 $record_buf_pos += $str_length + 1; 104 $str_length = 0; 105 // Get postal code 106 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 107 while ($char != 0) { 108 $str_length++; 109 $char = ord(substr($record_buf, $record_buf_pos + $str_length, 1)); 110 } 111 if ($str_length > 0) { 112 $record->postal_code = substr($record_buf, $record_buf_pos, $str_length); 113 } 114 $record_buf_pos += $str_length + 1; 115 $str_length = 0; 116 // Get latitude and longitude 117 $latitude = 0; 118 $longitude = 0; 119 for ($j = 0; $j < 3; ++$j) { 120 $char = ord(substr($record_buf, $record_buf_pos++, 1)); 121 $latitude += ($char << ($j * 8)); 122 } 123 $record->latitude = ($latitude / 10000) - 180; 124 for ($j = 0; $j < 3; ++$j) { 125 $char = ord(substr($record_buf, $record_buf_pos++, 1)); 126 $longitude += ($char << ($j * 8)); 127 } 128 $record->longitude = ($longitude / 10000) - 180; 129 if (GEOIP_CITY_EDITION_REV1 == $gi->databaseType) { 130 $metroarea_combo = 0; 131 if ($record->country_code == "US") { 132 for ($j = 0; $j < 3; ++$j) { 133 $char = ord(substr($record_buf, $record_buf_pos++, 1)); 134 $metroarea_combo += ($char << ($j * 8)); 135 } 136 $record->metro_code = $record->dma_code = floor($metroarea_combo / 1000); 137 $record->area_code = $metroarea_combo % 1000; 138 } 139 } 140 if ($mbExists) { 141 mb_internal_encoding($enc); 142 } 143 return $record; 144} 145 146function GeoIP_record_by_addr_v6($gi, $addr) 147{ 148 if ($addr == null) { 149 return 0; 150 } 151 $ipnum = inet_pton($addr); 152 return _get_record_v6($gi, $ipnum); 153} 154 155function _get_record($gi, $ipnum) 156{ 157 $seek_country = _geoip_seek_country($gi, $ipnum); 158 if ($seek_country == $gi->databaseSegments) { 159 return null; 160 } 161 return _common_get_record($gi, $seek_country); 162} 163 164function GeoIP_record_by_addr($gi, $addr) 165{ 166 if ($addr == null) { 167 return 0; 168 } 169 $ipnum = ip2long($addr); 170 return _get_record($gi, $ipnum); 171} 172