Как из неуникального текста сделать уникальный


Как из неуникального текста сделать уникальный
Как из неуникального текста сделать уникальный



Как из неуникального текста сделать уникальный







Значение REMOTE_ADDR: 185.162.11.66
HTTP заголовки, которые могут содержать информацию об IP адресе:
HTTP_CLIENT_IP: не установлено
HTTP_X_FORWARDED_FOR: не установлено
HTTP_VIA: не установлено
HTTP_X_REAL_IP: не установлено

Один из самых дремучих вопросов в околопхпешном вебе - это определение IP адреса.
Такого количества неправильного кода не написано, наверное, ни для какой другой операции.
Каждый, кто в один прекрасный день узнаёт о существовании переменной HTTP_X_FORWARDED_FOR, тут же воображает себя мегагуру, и заменяет ей REMOTE_ADDR. Потом приходит знание о других переменных (X_REAL_IP, VIA, и ещё вагон и маленькая тележка), изобретаются многослойные мегаконструкции, изобретатели хвастаются друг перед другом их многоэтажностью и сравнивают свои творения с "кодом из PHPbb!".
При этом спроси любого из них - "какой именно адрес они хотят определить?" - ни один не ответит: понимание основ функционирования сети TCP/IP среди пхп-программистов традиционно слабое.
А вот стремление к нахождению Идеального и Единственно Правильного Решения - традиционно сильное.
В результате вместо IP адреса в логи пишется не пойми что.
К примеру, возьмем, казалось бы, простой вопрос "какой именно IP адрес (из цепочки хостов, через которые идет запрос от компьютера клиента к серверу) мы хотим записать в лог?". После того, как выяснилось, что большинство пхп-программистов затрудняются на него ответить, я и решил написать эту заметку.
А это, между прочим, очень важный вопрос. Не ответив на него, наряду с вопросом "Зачем нам нужен IP адрес?", приступать к самому определению бессмысленно.
При том, что большинству читателей этого текста вопросы покажутся бессмысленными.
Ну что ж, попробуем разобраться.

Во-первых. Самые азы. Для тех, кто не знает.
Все элементы массива $_SERVER, начинающиеся со слова "HTTP_" - это HTTP-заголовки.
Как уже знают вдумчивые читатели фака на танке, HTTP заголовки присылает клиент. И прислать может любые.
К примеру, заголовок X-All-Your-Base-Belongs-To-Us: Surrender!
Или, как вы уже, наверное, догадались, заголовок X-Forwarded-For: admin durak
Мне кажется, что записывать столь глубокомысленную строку вместо IP адреса - не самая лучшая идея.
Как и вообще доверять любым переменным, начинающимся с HTTP. Это первое правило, которое надо запомнить с молоком матери: Любые элементы массива $_SERVER, начинающиеся с "HTTP_", можно использовать только в справочных целях! К примеру, HTTP_REFERER записываем, чтобы потом посмотреть. Но ни в коем случае не делаем на него Location.
Во-вторых, определимся с тем, ДЛЯ ЧЕГО нам нужен IP адрес. Если мы хотим записать в лог, то пишем однозначно только REMOTE_ADDR. В этой переменной содержится реальный IP адрес реального хоста в интернете, который произвел соединение с нашим сервером. Единственный реальный адрес. Никаких других сервер не знает.
Апач пишет в логи именно REMOTE_ADDR. Не надо считать авторов веб-сервера дурнее себя.
Что значит - реальный IP адрес? А то и значит. Адрес хоста, который произвел соединение с нашим сервером. Этот адрес по определению может быть только один. Один, а не 5 по цепочке. Рассмотрим типичный пример:
Есть пользовательский компьютер, который, который находится в офисной сети. IP компьютера 192.168.0.22
Офисная сеть включена через роутер в сеть здания. IP роутера - 10.10.0.3
Сеть здания, в свою очередь, подключена к интернету, через роутер. IP роутера - 77.88.22.11
Пользователь заходит на сайт, через НТТР прокси. IP прокси - 212.121.0.8
Так вот, сеть TCP/IP так устроена, что каждый следующий узел ничего не знает о предыдущих. Есть только пара хостов, которые соединяются друг с другом. В самих TCP/IP пакетах никакой информации о предыдущих хостах не предусмотрено.
Поэтому, как это ни обидно, но реальным адресом мы можем считать только последний в цепочке - адрес HTTP прокси.
Больше того. Ну допустим, узнали мы адрес компьютера пользователя (чем кичатся многие определители с помощью activeX и ява-апплетов). Этот адрес - 192.168.0.22. Он из . Компьютеров с такими адресами в мире - миллионы. Найти компьютер по такому адресу - невозможно. Пользы от него - практически никакой. Практически, но не совсем. Почему? Слушаем дальше:
Поскольку в протоколе HTTP текстовые заголовки, то в них можно добавить свой. Что некоторые хосты и делают. В те самые X-Forwarded-For, Via и прочие.
Можем мы их использовать? Можем. Если правильно понимать - для чего.
Для определения "реального IP адреса", как мы уже убедились - нельзя. А для чего же можно? Например - справки. просто записать, на всякий случай. НО! Только в том случае, если мы откажемся от дурацкой идеи найти один идеальный IP адрес. Если мы не будем писать вместо реального всякую лабуду, а будем записывать все похожее на IP адрес с реальным наряду, то почему нет?
Итак, можно записать всё, похожее на IP адрес. Понадобится выявить злостного вредителя - возможно, какой-то интересный айпишник среди заголовков и проскочит.
Для небольшого повышения надежности сессий - тоже можно. Писать в сессию не только реальный, но и все похожие. И все сверять. Хоть один не совпал - сессию рубим.
И в других подобных случаях.
Не забывая: реальный - отдельно, все похожее на IP адрес - отдельно.
Не забывая: особо полагаться на все эти заголовки не стоит.

Итак. Из всего вышеизложенного делается простой вывод.
IP адрес в скрипте может быть только один. Лежит он в переменной REMOTE_ADDR.
Следовательно, вожделенный код получания "идеального IP адреса" выглядит, как
$ip=$_SERVER['REMOTE_ADDR']
Точка.
Далее. Если мы хотим воспользоваться "заголовками, похожими на IP адрес" (лучше всего, во избежание недоразумений, совсем не считать их адресами хостов, а HTTP заголовками особого формата. Тем более, что никакого стандарта на содержимое заголовков X-Forwarded-For, Via и прочих - нет. Там могут оказаться IP адреса чарез запятую, или доменные имена или не через запятую. Не говоря уже о подделках!), то нет смысла судорожно искать все имена заголовков, где может встретиться адрес. Проще искать сами адреса.
Берем, пишем простой код, который в цикле перебирает массив $_SERVER, и регулярным выражением выцепляет все заголовки, в которых встречается подхдящая под шаблон IP адреса строка. Если встретилась, то весь заголовок - с именем и всем содержимым - добавляем в массив или в строку. Которая хранится отдельно от IP адреса, в текстовом виде.
Соответственно, в нужном месте повторяем операцию, и сверяем. IP адрес с IP адресом, строку похожих заголовков - со строкой похожих заголовков.
function get_all_ip() {
  $ip_pattern="#(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)#";
  $ret="";
  foreach ($_SERVER as $k => $v) {
    if (substr($k,0,5)=="HTTP_" AND preg_match($ip_pattern,$v)) $ret.=$k.": ".$v."\n";
  }
  return $ret;
}
Такой вот, несложный код.
Правда, нужда в нем, если задуматься, очень невелика. Разве что, для тех же сессий. А для справки, про запас... не проще ли писать вообще все HTTP заголовки, пришедшие в скрипт? И это поинформативнее будет, чем выцеплять какой-то один адрес из HTTP_X_REAL_IP.
Да и для сессий следует применять с осторожностью - IP адрес может оказаться, к примеру, в реферере...

Недавно я выяснил удивительную вещь. Оказывается, на свете существуют криворукие хостеры, у которых на сервере нет REMOTE_ADDR (а точнее есть, но в нем лежит... адрес самого сервера!). И пихают они адрес удаленного хоста кому куда бог на душу положит. Некоторые - вы будете смеяться - в HTTP_X_FORWARDED_FOR. Говорят, в некоторых больших программных продуктах есть даже специальная настройка для таких случаев - "Получать IP-адреса из заголовка X_FORWARDED_FOR".
Разумеется, этот курьёз не опровергает сказанного выше, и не стоит кидаться писать автоматические определители IP с его учетом. Все подобные случаи должны разбираться только в ручном режиме, самим программистом. Который сначала убедится - где именно в HTTP_X_FORWARDED_FOR лежит нужный адрес - в начале цепочки запятых или в конце, напишет правильный рег, и только потом в настройки сайта добавит код
$_SERVER['REMOTE_ADDR']=get_ip_from_xff();
Примечание для хостеров: mod_realip или mod_rpaf
Примечание для пользователей: разумеется, таких хостеров надо избегать, как калёного железа. Наверняка ведь это не единственная их криворукость?
Примечание для админов собственных хостов: Разумеется, при наличии цепочки локальных прокси, их надо правильно настраивать.
И, разумеется, этот факт ничуть не противоречит сказанному выше.
Бонус:
Прекрасная история, как по нотам иллюстрирующая всё вышесказанное:

Источник: http://phpfaq.ru/tech/ip




Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Как из неуникального текста сделать уникальный

Похожие новости: