Проверка валидности IP адреса
Подпрограммы на Perl.
В качестве предварительной проверки и отделения IP адреса от предположим URL, выполним такую проверку:
#!/usr/bin/perl ... if ( $host_IP =~ m/^[\d\.]+$/ ) { # разрешенные символы – цифра и точка # это может быть IP адрес, нужна дополнительная проверка } else { # $host_IP не является IP адресом } ...
Классическая проверка IP адреса на валидность:
if ( $ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ ) { # $ip – правильный ? IP адрес } else { # $ip – неверный IP адрес}
Однако такая проверка совершенно недостаточна, поскольку отдельные части (октеты) в IP адресе могут быть больше 255. Поэтому дополним предыдущий код:
if ( $ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ && ($1 < 256 && $2 < 256 && $3 < 256 && $4 < 256 ) ) { # $ip – правильный IP адрес } else { # $ip – неверный IP адрес}
Проверка предположим $1 >= 0 не нужна, поскольку конструкция \d в шаблоне пропустит только 0 и положительные числа.
Для удобства использования отдельных фрагментов кода в дальнейшем, оформим их в виде подпрограмм.
Можно разбить IP адрес на части и проверить каждую часть в цикле:
# подпрограмма valid_ip возвращает IP адрес в случае успешной проверки и undef в противоположном # случае sub valid_ip { my @oct = grep { $_ >= 0 && $_ <= 255 && $_ !~ /^0\d{1,2}$/ } split /\./, shift; return unless @oct == 4; return join('.', @oct); }
Для случая, когда часть IP адреса может начинаться с нуля, например 012, проверка ($_ >= 0 && $_ <= 255) дополнена кодом && $_ !~ /^0\d{1,2}$/
Мне очень нравится Perl именно из-за подобных конструкций в духе Unix, поэтому хочется рассмотреть основную строчку подпрограммы valid_ip подробнее:
1. Получаем переданное значение подпрограмме в переменную $_ , а именно shift .
2. Разбиваем (превращаем в массив) оператором split значение в переменной $_ в данном случае по точкам. Хотя явным способом переменная $_ здесь не фигурирует (не обозначена).
3. Полученный массив передаем оператору grep , который каждый элемент массива поочередно помещает в свою собственную переменную $_ для выполнения операций сравнения в блоке (обозначенном фигурными скобками). На "выходе" оператора grep получаем массив, состоящий из элементов входного массива, если для этого элемента массива операция сравнения имеет истинное значение. В скалярном контексте возвращаемое оператором grep – это количество успешных сравнений.
Поэтому подпрограмму valid_ip можно переписать:
# valid_ip возвращает 1 в случае валидности IP адреса и undef в противоположном случае sub valid_ip { 4 == grep { $_ >= 0 && $_ <= 255 && $_ !~ /^0\d{1,2}$/ } split /\./, shift; }
Здесь используется то, что возвращаемое подпрограммой значение – это последнее вычисленное. В данном случае это результат операции сравнения с числом 4.
До этого мы рассматривали проверки IP адреса, исходя из количества октетов – 4. Однако для пользователя (посетителя), вводящего данные вручную, удобнее, если мы будем дополнять (заполнять) недостающие октеты нулями. Т.е. IP адрес вида 192.2 превратим в 192.2.0.0
# valid_ip возвращает IP адрес в случае его валидности и undef в противоположном случае sub valid_ip { my @octets = split /\./, shift; for ( my $i = 0; $i <= 3; $i++ ) { if ( defined $octets[$i] ) { return unless ($octets[$i] >= 0 && $octets[$i] <= 255 && $octets[$i] !~ /^0\d{1,2}$/); } else { $octets[$i] = 0; } } return join('.', @octets); }
Если мы хотим сообщить пользователю об ошибке(ошибках) в IP адресе, например "подсветить" ошибочный октет(ы) в CGI скрипте, тогда:
# valid_ip возвращает true и валидный IP адрес или false и IP адрес с "подсвеченными" ошибочными # октетами sub valid_ip { my @octets = split /\./, shift; my $osh = 0; for ( my $i = 0; $i <= 3; $i++ ) { if ( defined $octets[$i] ) { unless ($octets[$i] >= 0 && $octets[$i] <= 255 && $octets[$i] !~ /^0\d{1,2}$/) { $octets[$i] = "<font color='#FF0000'> $octets[$i] </font>"; $osh++; } } else { $octets[$i] = 0; } } return('true', join('.', @octets)) unless ( $osh ); return('false', join('.', @octets)); }
Можно сообщить пользователю детально о каждой ошибке в IP адресе:
# valid_ip возвращает тескт ошибки либо 0 в случае валидности IP sub valid_ip { my $ip = shift; return "Не указан IP" unless ( $ip ); return "Недопустимые символы в IP $ip" unless ( $ip =~ m/^[\d\.]+$/ ); return "Недопустимый IP $ip - начинается с точки" if ($ip =~ m/^\./); return "Недопустимый IP $ip - заканчивается точкой" if ($ip =~ m/\.$/); # Число октетов return "Ошибка - IP адрес должен содержать 4 октета" unless ( 3 == ($ip =~ tr/\./\./) ); # Проверка пустых октетов return "Не указана часть IP - две точки подряд" if ($ip =~ m/\.\./); # Проверка на допустимый диапазон значений в октете foreach (split /\./, $ip) { return "Недопустимое значение в IP адресе $ip - $_" unless ($_ >= 0 && $_ < 256 && $_ !~ /^0\d{1,2}$/ ); } return 0; }
Оставить комментарий
Комментарии
1.
8 июля 2009, 01:14:01
Очень часто еще требуется проверка на класс сети, чтобы отсечь, например, диапазоны локальных адресов.