PHP: Как определить IP адрес пользователя?
Сегодня поговорим о том, как определить IP адрес пользователя в PHP, как его проверить с помощью регулярных выражений, как его конвертировать в число и обратно, как его хранить в базе данных MySQL, а так же о том, какие ip адреса заранее зарезервированы..
Вступление
IP адрес - это сокращение от Internet Protocol Address. Это числовой идентификатор компьютера или устройства в локальной сети или сети интернет. Бывают двух версий:
- IPv4 (32 бита), пример: 192.168.0.1
- IPv6 (128 бит), пример: 0000:0000:0000:0000:0000:0000:0000:1 или ::1
В этой статье мы поговорим про ip-адреса версии IPv4, т.е. об ip адресах из диапазона: 0.0.0.0 - 255.255.255.255
Как получить IP адрес посетителя в PHP
IP адрес пользователя, в PHP, передается в глобальном массиве $_SERVER. Получить его можно использовав ключ массива REMOTE_ADDR, пример:
1 2 3 4 5 6 |
<?php $ip = $_SERVER['REMOTE_ADDR']; echo $ip; |
В результате выполнения скрипта, вы получите ip адрес посетителя.
Какой адрес будет показан при входе с моего ПК, на веб-сервер на моем ПК?
В случае, если Вы установили веб-сервер на свой ПК (например, Openserver) и открываете страницу опять же со своего ПК, вы увидите адрес 127.0.0.1. Это нормально, при переносе на нормальный хостинг, будет показан Ваш внешний IP.
Что будет при попытке получить ip-адрес выполнив скрипт из консоли?
Если Вы попробуете запустить такой скрипт из консоли, например создав файл ip.php с содержимым:
1 2 3 4 5 6 |
<?php error_reporting(-1); $ip = $_SERVER['REMOTE_ADDR']; echo $ip; |
и затем в консоли выполните:
1 2 3 |
# php ip.php |
то вы получите ошибку, в которой будет написано, что PHP не может найти значение по указанному ключу
1 2 3 |
Notice: Undefined index: REMOTE_ADDR in ip.php on line 3 |
Дело в том, что эти переменные устанавливает веб-сервер и при запуске "напрямую" они не будут установлены
Как проверить откуда запускается скрипт из консоли или через веб-сервер?
Проверить откуда запускается скрипт можно с помощью функции php_sapi_name()
1 2 3 4 5 6 7 |
<?php $ip = null; if ((php_sapi_name() != 'cli')) { $ip = $_SERVER['REMOTE_ADDR']; } |
Более надежными способом будет дополнительная проверка на существование ключа массива, вот так:
1 2 3 4 5 6 7 |
<?php $ip = null; if ((php_sapi_name() != 'cli') && isset($SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } |
Если у Вас возникнет вопрос, почему просто не проверить через isset, отвечаю: переменная REMOTE_ADDR может быть установлена с помощью переменных окружения, тогда проверка isset пройдет, но значение может не соответствовать действительности. Да, можно проигнорировать проверку с помощью php_sapi_name(), но вы должны отдавать себе отчет в том, что вы делаете и почему именно так.
Как проверить IP адрес с помощью регулярного выражения?
Проверить IP адрес с помощью регулярного выражения можно простой проверкой:
1 2 3 4 5 6 7 8 9 |
$ip = $_SERVER['REMOTE_ADDR']; if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$~', $ip)) { echo 'Корректный'; } else { echo 'Не корректный'; } |
Здесь проверяется, что в $ip содержится такая строка:
1 2 3 |
(1-3 цифры от 0 до 9) точка (1-3 цифры от 0 до 9) точка (1-3 цифры от 0 до 9) точка (1-3 цифры от 0 до 9) |
Более точной будет проверка ip-адреса вот таким выражением:
1 2 3 4 5 6 7 8 9 |
$ip = $_SERVER['REMOTE_ADDR']; if (preg_match('~^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])){3}$~', $ip)) { echo 'Корректный'; } else { echo 'Не корректный'; } |
Здесь проверяется, что в $ip содержится такая строка:
1 2 3 |
(цифра от 0 до 255) точка (цифра от 0 до 255) точка (цифра от 0 до 255) точка (цифра от 0 до 255) |
Как определить IP адрес посетителя, находящегося за прокси сервером?
Достоверно на 100% определить нельзя. Можно попытать удачи с переменными HTTP_CLIENT_IP и HTTP_X_FORWARDED_FOR, но надо помнить что все переменные массива $_SERVER начинающиеся на HTTP_* это заголовки запроса, которые могут быть подделаны, переопределены, полностью отсутствовать, иметь не верный формат или содержать какую-нибудь гадость, например, sql-инъекцию.
Обычно используют так:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ip = null; if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif(!empty($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } echo $ip |
В случае, если Вы решите использовать именно такой код, я рекомендую проверять его с помощью регулярки описанной выше, чтобы отфильтровать не валидные ip и гадости. Вот так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php error_reporting(-1); $ip = null; if (php_sapi_name() != 'cli') { if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['<span class="crayon-s">HTTP_X_FORWARDED_FOR</span>']; } elseif(!empty($_SERVER['REMOTE_ADDR'])) { $ip = $_SERVER['REMOTE_ADDR']; } if (!preg_match('~^(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])(\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[0-9]{2}|[0-9])){3}$~', $ip)) { $ip = null; } } echo $ip |
Как хранить IP адрес в базе данных MySQL?
Лично я предпочитаю хранить IP адрес в MySQL в поле типа VARCHAR(15), по длине самого длинного IPv4 адреса = 255.255.255.255
Другой способ, это привести IP адрес в к типу UNSIGNED INT. Это позволяет экономить память: 4 байта у UNSIGNED INT против 15 у CHAR.
Преобразовать IPv4 адрес к типу INT в PHP можно так
1 2 3 4 5 6 7 8 9 |
// ip адрес в число echo ip2long('127.0.0.1'); > 2130706433 // число в ip адрес long2ip('2130706433'); > 127.0.0.1 |
Тоже самое можно сделать и на стороне MySQL, для этого надо использовать функции INET_ATON() и INET_NTOA()
Запомнить эти функции достаточно просто:
ATON = Address TO Numaber
NTOA = Number TO Adress
Пример использования
1 2 3 4 5 6 7 8 9 |
# ip адрес в число SELECT INET_ATON('127.0.0.1'); > 2130706433 # число в ip-адрес SELECT INET_ATON('2130706433'); > 127.0.0.1 |
Выбор, что использовать для хранения VARCHAR или INT стоит за проектировщиком БД и удобством использования в будущем.
Какие IP адреса являются предопределенными?
Для локальных сетей предопределены такие диапазоны IP адресов:
- 10.0.0.0/8 или 10.0.0.0 - 10.255.255.255
- 172.16.0.0/12 или 172.16.0.0 - 172.31.255.255
- 192.168.0.0/16 или 192.168.0.0 - 192.168.255.255
Для коммуникаций внутри хоста (между программами запущенными на вашем ПК) используется диапазон ip-адресов: 127.0.0.0/8 или 127.0.0.0 - 127.255.255.255 .
Блок с 169.254.1.0 по 169.254.254.255 (подсеть 169.254.0.0/16 за исключением подсетей 169.254.0.0/24 и 169.254.255.0/24) —
используется для автоматической настройки сетевого интерфейса в случае отсутствия DHCP
Author: | Tags: /
| Rating:
Leave a Reply