Определение IP и местоположения посетителя сайта 6.

Нифига не окончание, а второй сезон.

Пока исключительно небольшие исправления.

— Добавили зарезервированные диапазоны IPv4 адресов и соответствующую проверку Копия в скрипты для машинной обработки данных и в красивый скрипт с оформлением

Посмотреть, как работают, можно соответственно здесь и здесь

— Сделали тестовый скрипт, который IP сам ничего не детектит, а просто обращается к SxGeo. Он все равно еще понадобится.

Использование:
onlysxgeo.php?ip=ip-address
Например:
onlysxgeo.php?ip=8.8.8.8
Или:
onlysxgeo.php?ip=ip-address&f=FIELD_NAME
для включения имя поля в ответ скрипта, по умолчанию имя поля MANUAL
Или
onlysxgeo.php?specdiap
Для вывода списка зарезервированных диапазонов адресов IPv4

— По многочисленным просьбам зрителей сделали самый простой скрипт, который просто выводит все IP из заголовков HTTP_* (например HTTP_VIA и/или HTTP_X_FORWARDED_FOR) и REMOTE_ADDR и источник адреса (имя поля HTTP_* или REMOTE_ADDR).

— Завели отдельный репозиторий на GitHub, куда выложили код из всех предыдущих и новых серий

Репозиторий

Запуск php-скрипта в консоли.

Ворчальная преамбула

Дальше будет банальщина, наверняка всем известная, но все же, вдруг кто не знает, да и себе от склероза.

Есть у меня маленький, но очень полезный горшочек скрипт, за которым надо постоянно ходить на сервер, а тут оказалось, что он понадобился на машине, где никаких интернетов нет, а данные, которые нужно обработать — есть. Я сначала решил сделать из него экзешник, но потом оставил эту затею, ибо с компиляторами PHP под Виндовоз неожиданно образовался какой-то жуткий геморрой. HipHop от Facebook напрочь отказался собираться, сайт Roadsend PHP Compiler сдох, а опять собирать с исходников GitHub стало после шаманства с HipHop откровенно влом, ну плюс MinGW особым удобством не отличается.

Заметил, кстати, удивительную странность — на машине с 12 Гб оперативной памяти и четвероядерным процессором, но под MinGW и, соответственно, Виндой, сборка происходит медленнее, чем на компьютере с Linux, скромным двухведерным процессором и двумя же Гб ОП.

Впрочем, все эти танцы с бубном были совершенно лишними.

Запуск скрипта в консоли

Все оказалось банально и элементарно, php прекрасно работает из консоли. Формат команды:

php.exe [параметры] <скрипт> [параметры_скрипта]

Параметры скрипта

Скрипт может «найти» свои параметры в элементах глобального массива $_SERVER:
$_SERVER['argc'] хранит количество параметров
$_SERVER['argv'] их значения. $_SERVER['argv'] сам является индексированным массивом. В элементе 0 содержится имя файла скрипта.

Примечание:
Начиная с PHP 4.3.0, при использовании CLI SAPI переменные $argc и and $argv зарегистрированы и заполнены соответствующими значениями. В более ранних версиях создание этих переменных, так же, как и для CGI или модуля веб-сервера, требует значение on директивы register_globals. Независимо от версии PHP или статуса опции register_global они всегда доступны как элементы массива $_SERVER или $HTTP_SERVER_VARS. Например: $_SERVER[‘argv’]

Пример

Скрипт, выводящий в консоль свои параметры:

<?php	
	echo "Console test \n\n";
	
	echo "Arguments count: ".$_SERVER['argc']."\n";
	echo "Arguments values:\n";
	
	$i=0;
	
	foreach ($_SERVER['argv'] as $arg)
	{
		echo $i.": ".$arg."\n";
		$i++;
	}	
?>

Результат работы

Если запустить скрипт, например так:

php.exe con-test.php param1 param2 param3 tramparamparamparam

Портабельный скрипт

Все это не имело бы большого смысла, если бы для запуска скрипта пришлось бы тащить с собой Web-сервер или весь дистрибьютив PHP, со всеми модулями и прочим. Для минимального запуска PHP под Windows нужно всего 2 файла: php.exe и php*ts.dll, где * — версия PHP. Например, для использованного мной PHP5, это php5ts.dll

Разные мелочи

— Инклюды. Если скрипт подразумевает использование инклюдов, то их лучше держать либо в директории с главным скриптом, либо в поддиректориях, и прописывать в основном скрипте относительные пути. Т.е. так, как это обычно делается на сервере. Иначе PHP будет искать их либо в include_path, который прописан в php.ini, либо вообще неведомо где, точнее ведомо — это указывается как параметр при сборке самого PHP, если мне не изменяет склероз.

php.ini Вообще, для запуска PHP он не нужен, но тут может вкрасться чущественная гадость. Если на машине уже установлен PHP, или php.ini подложен каким-то злоумышленником в каталог по умолчанию, для многих сборок под Windows это %WINDIR%, то может случиться неприятность.
Сам PHP ищет свой php.ini сначала в каталоге с самим собой, так что можно туда его подложить.

— Расширения PHP. Можно подложить нужные DLL расширений в подкаталог в каталоге с php.exe и прописать в extension_dir в php.ini относительный путь к каналогу, а в соответствующих параметрах extension — имена DLL

— PHP я цельностянул из Denwer 🙂

Архив с примером и «портабельным» PHP

Источники

1. Создание EXE приложений на PHP Копия
2. Оффлайновые лекционные тетради в клеточку.

Зарезервированные диапазоны IP-адресов и проверка попадания в них адреса.

Преамбула

В IPv4 имеются зарезервированные диапазоны адресов, в некоторых случаях надо проверить, не попал ли адрес в один из них

Таблица зарезервированных адресов


См. в PDF
Или на PasteBin

Надеюсь, ничего не забыл. Таблица нагло выдрана из лекции, но я сверялся с Википедией и другими интернетами.

Вспомогательные функции для проверки

Для порядку заведем регулярное выражение для проверки 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]?)#";

И функцию, которая проверяет, а IP ли вообще у нас на входе:

function isip($ip_str) //соответствие данных формату IP
{	
	global $ip_pattern;
	$ret=FALSE;
	if (preg_match($ip_pattern,$ip_str)) 
	{
		$ret=TRUE;
	}
	return $ret;
}

Теперь функцию, которая будет проверять, попал ли IP в нужный диапазон:

function chkdiapip ($user_ip, $ip_from, $ip_to) //попадает ли ip в нужный диапазон
{
	return ( ip2long($user_ip)>=ip2long($ip_from) &&
 ip2long($user_ip)<=ip2long($ip_to) );
}

Проверка

Создадим двумерный массив со списком диапазонов:

$spec_list = array(										
	array ("0.0.0.0","0.255.255.255", "Current network"),
	array ("255.255.255.255","255.255.255.255", "Broadcast"),
	array ("255.0.0.0","255.255.255.255", "Reserved by the IETF, broadcast"),
	array ("10.0.0.0","10.255.255.255", "Private network"),
	array ("100.64.0.0","100.127.255.255", "Shared Address Space"),
	array ("127.0.0.0","127.255.255.255", "Loopback"),
	array ("169.254.0.0","169.254.255.255", "Link-local"),
	array ("172.16.0.0","172.31.255.255", "Private network"),
	array ("192.0.0.0","192.0.0.7", "DS-Lite"),
	array ("192.0.0.170","192.0.0.170", "NAT64"),
	array ("192.0.0.171","192.0.0.171", "DNS64"),
	array ("192.0.2.0","192.0.2.255", "Documentation example"),
	array ("192.0.0.0","192.0.0.255", "Reserved by the IETF"),				
	array ("192.88.99.0","192.88.99.255", "Anycast"),
	array ("192.88.99.1","192.88.99.1", "IPv6 to IPv4 Incapsulation"),
	array ("192.168.0.0","192.168.255.255", "Private network"),
	array ("198.51.100.0","198.51.100.255", "Documentation example"),
	array ("198.18.0.0","198.19.255.255", "Test IP"),
	array ("203.0.113.0","203.0.113.255", "Documentation example"),
	array ("224.0.0.0","224.255.255.255", "Multicast"),
	array ("240.0.0.0","240.255.255.255", "Future reserved")					
	);

И функцию, которая будет все это безобразие в цикле перебирать, и если IP попадет в какой-то из диапазонов - выдаст диапазон и описание. Если не попадет - вернет -1.

function get_spec_diap ($user_ip, $listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		if (chkdiapip($user_ip, $item[0], $item[1]))
		{
			return $item[0]."\t".$item[1]."\t".$item[2]."\t\n";
		}
	}
	
	return -1;
}

Ну шоб два раза не вставать, сделаем еще и функцию, оглашающую весь список:

function printspecdiap ($listspec)
{
	for ($i=0;$i<sizeof($listspec);$i++)
	{
		$item = $listspec[$i];
		echo $item[0]."\t\t".$item[1]."\t\t\t".$item[2], "\t\t\t\n";
	}
}

Скрипт полностью на PasteBin
На GitHub

фразочка

Слава — Украине,
Вова — России,
Саша — Беларуси.
А Моисей Соломонович Кац, таки Израилю.