<?php /** * Гибкая проверка IP-адресов по маске. * * Маска может выглядеть как обычный IP-адрес: * <b>192.168.0.1</b> * * Любая из четырёх частей маски может содержать несколько значений, * разделённых запятыми: * <b>192.168.0.1,2,3,4,5</b> * * Того же значения можно добиться использованием диапазонов: * <b>192.168.0.1-5</b> * * Диапазоны можно комбинировать с использованием запятых: * <b>192.168.0.1,3,5,10-20,30-100,105,200</b> * * Звёздочка, поставленная вместо какой-либо части маски, * обозначает любое значение: * <b>192.168.*.*</b> * * @package s5core */ class S5_Net_IPsChecker { private $allowedIPs = array(); /** * Конструктор. * * Принимает список масок IP-адресов, например: * <code> * new S5_Net_IPsChecker("1.1.1.1", "1.1.1.10", "1.1.1.50-60"); * </code> * * или в виде массива: * <code> * new S5_Net_IPsChecker(array("1.1.1.1", "1.1.1.10", "1.1.1.50-60")); * </code> */ public function __construct () { if (func_num_args() == 0) throw new InvalidArgumentException("Должна быть передана хотя бы одна маска."); $param1 = func_get_arg(0); if (is_array($param1)) { $this->allowedIPs = $param1; } else { $this->allowedIPs = func_get_args(); } if (count($this->allowedIPs) == 0) throw new InvalidArgumentException("Должна быть передана хотя бы одна маска."); foreach ($this->allowedIPs as $ip) { static $ap = '[\d,*-]{1,}'; if (!preg_match("|^$ap\\.$ap\\.$ap\\.$ap$|", $ip)) { throw new InvalidArgumentException("Аргумент $ip не является правильной маской."); } } } /** * Проверка IP-адреса, заданного четырьмя целыми числами. * * Пример: * <code> * $ipc->check(192, 168, 0, 1); * </code> * * @param integer $ip1 Первая часть IP-адреса. * @param integer $ip2 Вторая часть IP-адреса. * @param integer $ip3 Третья часть IP-адреса. * @param integer $ip4 Четвёртая часть IP-адреса. * @return boolean */ public function check ($ip1, $ip2, $ip3, $ip4) { $four_test_parts = array($ip1, $ip2, $ip3, $ip4); for ($ipx=0; $ipx < count($this->allowedIPs); $ipx++) { //Сравниваем переданный адрес с одной из масок. if ($this->checkSingleMask($this->allowedIPs[$ipx], $four_test_parts)) { return true; } } //Цикл по маскам завершился. Если мы попали сюда, это означает, //что проверки всех масок провалались. return false; } private function checkSingleMask ($mask, $four_test_parts) { //4 части: 192, 198, 0, 1 $four_allowed_parts = explode('.', $mask); for ($part_ix=0; $part_ix<4; $part_ix++) { //Если часть не прошла проверку, то вся маска тоже проверку не прошла. if (!$this->checkSinglePart($four_allowed_parts[$part_ix], $four_test_parts[$part_ix])) { return false; } } //Все четыре части маски прошли проверку, //значит проверка всей маски удалась. Можно возвращать true. return true; } private function checkSinglePart ($allowed_part, $test_part) { //Если часть - звёздочка, то проверку можно пропустить, //она считается верной в любом случае. if ($allowed_part == '*') { return true; } else { //Разрешённые диапазоны, которые через запятую, //содержащиеся в одной из частей. $allowed_ranges = explode(',', $allowed_part); //Проход по диапазонам. for ($range_ix = 0; $range_ix < count($allowed_ranges); $range_ix++) { if ($this->checkSingleRange($allowed_ranges[$range_ix], $test_part)) { return true; } } return false; } } private function checkSingleRange ($range, $test_part) { //Берём один из разрешённых диапазонов if (strpos($range, '-')) { $min_max = explode('-', $range); $min = (int)$min_max[0]; $max = (int)$min_max[1]; //Если число попало в диапазон, остальные составляющие диапазона можно не проверять, //ведь часть сошлась. if ($test_part >= $min and $test_part <= $max) return true; } else { if ($test_part == $range) return true; } return false; } /** * IP-адрес для проверки в виде строки "192.168.0.1" * * @param string $testIP * @return boolean */ public function checkString ($testIP) { $parts4 = explode('.', $testIP); return $this->check($parts4[0], $parts4[1], $parts4[2], $parts4[3]); } /** * IP-адрес для проверки в виде упакованного длинного целого, * подходящего для обработки функцией long2ip(). * * @param long $testIP * @return boolean */ public function checkPacked ($testIP) { return $this->checkString(long2ip($testIP)); } } ?> |