Наверняка перед многими web-мастерами вставала задача — определить по маске подсети вхождение IP-адреса посетителя сайта. Цели при этом могут быть разными: выдать содержимое на странице в зависимости от географической принадлежности посетителя (что арабу хорошо, то еврею смерть), заблокировать доступ к сайту по IP… Впрочем, блокировать доступ к сайту удобнее с помощью файла .htaccess.
В общем, однажды подобная задача встала и передо мной — нужно было телефон на странице выводить в зависимости от страны посетителя сайта. Хождение по Google мало что дало. На многих блогах и форумах я находил какие-то обрезки php-скриптов, в большинстве своем не работающие. А если и попадались работающие скрипты, то проверка производилась только по одному диапазону IP-адресов. Пришлось писать свой php-код, коим и хочу поделиться.
В файл ipbase.txt вносим подсети IP-адресов нужной страны, берем их здесь: ipdeny.com →
Пишем php-скрипт:
<?php
// Функция проверки вхождения IP-адреса в подсеть:
$ip = $_SERVER['REMOTE_ADDR'];
function ip_in_net($ip, $net, $mask)
{
// Преобразование IP в беззнаковое десятичное целое число:
$ip = (int) sprintf("%u", ip2long($ip));
$mask = (int) sprintf("%u", ip2long($mask));
$net = (int) sprintf("%u", ip2long($net));
if (($ip & $mask) == $net) {
return 1;
} else {
return 0;
}
}
// Поскольку подсети записаны в формате 127.0.0.0/8, то понадобится функция перевода CIDR в обычную маску: 127.0.0.0/255.0.0.0:
function cidr_to_mask($mask)
{
return long2ip(pow(2, 32) - pow(2, (32 - $mask)));
}
// Загружаем файл с базой подсетей, не забываем указать правильный путь к файлу:
$file = $_SERVER['DOCUMENT_ROOT'] . '/ПУТЬ_К_ФАЙЛУ/ipbase.txt';
// Если файл существует и доступен для чтения:
if (is_readable($file)) {
// Считываем файл в массив:
$nets = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// Проходим массив циклом:
for ($i = 0, $size = sizeof($nets); $i < $size; $i++) {
// Если строка существует:
if ($nets[$i]) {
// Разбиваем строку на массив, в качестве значений используются адрес и маска подсети:
$line = explode('/', $nets[$i]);
$mask = cidr_to_mask($line[1]); // Переводим CIDR в обычную маску
$net = $line[0];
// Проверяем вхождение IP-адреса в подсеть:
if (ip_in_net($ip, $net, $mask)) {
// Если IP-адрес входит в подсеть, выводим результат:
echo 'Адрес ' . $ip . ' входит в подсеть ' . $net . '/' . $mask;
// Или задаем значение переменной $ip для использования за пределами данного цикла (в правиле ниже):
$ip = 'yes';
break; // Прерываем цикл
}
}
}
}
?>
Скрипт удобнее разместить в отдельном файле, подключая его к нужной странице функцией include. Путь к файлу с базой подсетей также можно вынести из скрипта и прописывать на нужной странице. Так вы сможете использовать различные файлы для разных страниц, используя только один скрипт. При соответствии IP-адреса маске подсети в скрипте выводится только значение переменной $ip = 'yes', по которому на страницах сайта задаются определенные правила:
<?php
$file = $_SERVER['DOCUMENT_ROOT'] . '/ПУТЬ_К_ФАЙЛУ/ipbase_egypt.txt';
include($_SERVER['DOCUMENT_ROOT'] . '/ПУТЬ_К_ФАЙЛУ/ipsearch.php');
if ($ip == 'yes') {
// IP-адрес входит в подсеть, например, Египта, пишем приветствие для друзей-арабов:
echo 'Рахат-лукум!';
} else {
// В противном случае приветствуем остальной мир, а арабы из Египта пусть идут руслом Нила — можно и в Крыму отдыхать, далась вам эта пустыня:
echo 'Миру — мир, Крыму — Крым!';
}
?>
Напоследок привожу оптимизированный код:
<?php
$file = $_SERVER['DOCUMENT_ROOT'] . '/ПУТЬ_К_ФАЙЛУ';
if (is_readable($file)) {
$cidr = array('0.0.0.0', '128.0.0.0', '192.0.0.0', '224.0.0.0', '240.0.0.0', '248.0.0.0', '252.0.0.0', '254.0.0.0', '255.0.0.0', '255.128.0.0', '255.192.0.0', '255.224.0.0', '255.240.0.0', '255.248.0.0', '255.252.0.0', '255.254.0.0', '255.255.0.0', '255.255.128.0', '255.255.192.0', '255.255.224.0', '255.255.240.0', '255.255.248.0', '255.255.252.0', '255.255.254.0', '255.255.255.0', '255.255.255.128', '255.255.255.192', '255.255.255.224', '255.255.255.240', '255.255.255.248', '255.255.255.252', '255.255.255.254', '255.255.255.255');
$ip = intval(sprintf("%u", ip2long($_SERVER['REMOTE_ADDR'])));
$nets = @file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
for ($i = 0, $size = sizeof($nets); $i < $size; $i++) {
if ($nets[$i]) {
$line = explode('/', $nets[$i]);
$net = intval(sprintf("%u", ip2long($line[0])));
if (isset($cidr[$line[1]])) {
$mask = $cidr[$line[1]];
} else {
$mask = long2ip(pow(2, 32) - pow(2, (32 - $line[1])));
}
$mask = intval(sprintf("%u", ip2long($mask)));
if (($ip & $mask) == $net) {
$mark = 1; // Маркер вхождения $ip в подсеть $net/$mask
break;
}
unset($line, $mask, $net);
}
}
unset($cidr, $ip, $nets, $i, $size);
}
unset($file);
if (!empty($mark)) {
// Адрес $ip входит в подсеть $net/$mask
}
?>
Данная статья была взята с сайта: mycrimea.su
|