Иногда приходится определять с какой именно страны к нам зашел пользователь на PHP. В этом нам поможет MaxMind. Конечно, для nginx есть модуль, но когда хочется иметь все проще, но, может быть, чуть медленнее на PHP, то почему бы и нет?..

Более детальная информация находится на GitHub.

Если еще нет композера, то поставьте его (ссылка на офиц. сайт композера)...

curl -sS https://getcomposer.org/installer | php

Далее установим сам пакет PHP:

php composer.phar require geoip2/geoip2:~2.0

В нужном файле подключить:

require 'vendor/autoload.php';

Установить GeoIP:

https://zoomadmin.com/HowToInstall/UbuntuPackage/geoip-database

sudo apt-get update -y
sudo apt-get install -y geoip-database

Если Вы не хотите устанавливать GeoIP по определенным причинам, то сами базы можно скачать с сайта maxmind. НО! Для начала необходимо там зарегистрироваться...

Сам сайт:

https://www.maxmind.com/en/geolite2/signup

Регистрация и т.п...

Вводим данные, email должен быть настоящим...

Сам архив с базой IP Country (страны) выглядит так:

Города ...

обратите внимание, что файл 

/usr/local/share/GeoIP/GeoIP2-City.mmdb

должен находится в указанном Вами каталоге.

<?php
require_once 'vendor/autoload.php';
use GeoIp2\Database\Reader;

// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader('/usr/local/share/GeoIP/GeoIP2-City.mmdb');

// Replace "city" with the appropriate method for your database, e.g.,
// "country".
$record = $reader->city('128.101.101.101');

print($record->country->isoCode . "\n"); // 'US'
print($record->country->name . "\n"); // 'United States'
print($record->country->names['zh-CN'] . "\n"); // '美国'

print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'

print($record->city->name . "\n"); // 'Minneapolis'

print($record->postal->code . "\n"); // '55455'

print($record->location->latitude . "\n"); // 44.9733
print($record->location->longitude . "\n"); // -93.2323

print($record->traits->network . "\n"); // '128.101.101.101/32'

Страны...

обратите внимание, что файл 

folder/GeoLite2-Country.mmdb

должен находится в указанном Вами каталоге.

<?php
#https://dev.maxmind.com/geoip/geoip2/geolite2/
#ini_set('display_errors',1);
require_once '../vendor/autoload.php';
use GeoIp2\Database\Reader;

// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader(getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb');

// Replace "city" with the appropriate method for your database, e.g.,
function ip():String //get user IP
{
  $ip='';
  if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
  $ip=$_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
  $ip=$_SERVER['REMOTE_ADDR'];
}
  if(!filter_var($ip, FILTER_VALIDATE_IP)){
    return '127.0.0.1';
  }
  return $ip;
}

$ip=ip();

if (!filter_var($ip, FILTER_VALIDATE_IP)) {
echo 'Some error...';
exit;
}

// "country".
$country = $reader->country($ip);
print($country->country->isoCode);

ГЛАВНОЕ!

Точность определения зависит от выбранного Вами пакета. В пакете без оплаты, точность минимальная, чем больше платите — тем больше точность... Скрипт может отдать пустую строку, если он не определил страну по определенному IP, к примеру, 127.0.0.1

Помните о том, что в Вашем PHP приложении нужно закешировать переменную с вызовом функции получения страны по IP. Т.е. просто сделать так (код ниже)... Хотя в самом скрипте все максимально оптимизировано и базы хранятся в бинарнике (если Вы не используете CSV), но все-равно нужно помнить об оптимизации.

К примеру, у меня сайт, на котором требуется определять IP находится на одном сервере, а скрипт, который определяет страну — на другом. Поэтому я запрашиваю инфу по CURL...

function ip():String
{
$ip='';
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip=$_SERVER['HTTP_CLIENT_IP'];
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
} else {
$ip=$_SERVER['REMOTE_ADDR'];
}
if(!filter_var($ip, FILTER_VALIDATE_IP)){
return '127.0.0.1';
}
return $ip;
}

function getCountry(){
if(!isset($_SESSION['country'])){
$qwe=explode(',',ip());
$link_='';
is_array($qwe) ? $link_='https://getcountry-from-ip.org/folder/IP.php?ip='.$qwe[0] : $link_='https://getcountry-from-ip/folder/IP.php?ip='.ip();
$ch = curl_init($link_);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response=curl_exec($ch);
$responseCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if($responseCode === 200){
if(empty($response) OR $response==""){$response='';}
$_SESSION['country']=$response;
return $response;
}else{
$_SESSION['country']='RU';
return 'RU';
}
}else{
return $_SESSION['country'];
}
}

Можно достучаться через web:

https://getcountry-from-ip.org/folder/IP.php?ip=192.168.0.1

Теперь, когда Вам нужна страна пользователя:

$country = getCountry();

Дальше используйте эту переменную или используйте $_SESSION... так как функция getCountry() записывает в сессию страну.

$country = $_SESSION['country'];

Сам файл скрипта на сервере, где я определяю страну по IP:

<?php
#https://dev.maxmind.com/geoip/geoip2/geolite2/
#ini_set('display_errors',1);
require_once '../vendor/autoload.php';
use GeoIp2\Database\Reader;

// This creates the Reader object, which should be reused across
// lookups.
$reader = new Reader(getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb');

// Replace "city" with the appropriate method for your database, e.g.,

$ip='';
if(isset($_GET['ip'])){$ip=$_GET['ip'];}else{
echo 'Some error...';
exit;
}

if(empty($_GET['ip'])){
echo 'Some error...';
exit;
}

$p_ = stripos($ip, ',');
if ($p_ !== false) {
$ip=explode(',',$ip);
$ip=trim($ip[0]);
}

if (!filter_var($ip, FILTER_VALIDATE_IP)) {
echo 'Some error...';
exit;
}

// "country".
$country = $reader->country($ip);
print($country->country->isoCode);
/*
print($record->country->name . "\n"); // 'United States'
print($record->country->names['zh-CN'] . "\n"); // '美国'

print($record->mostSpecificSubdivision->name . "\n"); // 'Minnesota'
print($record->mostSpecificSubdivision->isoCode . "\n"); // 'MN'

print($record->city->name . "\n"); // 'Minneapolis'

print($record->postal->code . "\n"); // '55455'

print($record->location->latitude . "\n"); // 44.9733
print($record->location->longitude . "\n"); // -93.2323 */

Получается сама база лежит в каталоге:

getenv('DOCUMENT_ROOT').'/folder/GeoLite2-Country.mmdb'

Файлы, которые были загружены с помощью композера нужно кинуть в корень Вашего проекта:

внутри папки vendor (сгенерировано автоматически):

желательно запретить из web доступ к папке vendor (для nginx):

location ~* ^/(composer.phar|composer.json|composer.lock) {
deny all;
}

location ~* ^/(vendor)($|\/) {deny all;}