Некоторое время назад проблема получения данного списка встала перед нами в полный рост. В принципе сам список можно получать в ручном режиме с сайта vigruzki.rkn.gov.ru. Но так как программист скотина ленивая, немедленно было решено это все автоматизировать :) Формировать ежедневно вручную файлы запроса и подписи, а затем проходить процедуру запроса и получения файлов мне как-то не улыбалось. Немного покопавшись в этих ваших энторнетах я обнаружил на сайте [url]habrahabr.ru[/url] статейку по решению проблемы. Сделав все по рекомендациям в статье оказалось что программа немножко сильно не работает. Пришлось немножко напрячь мезушный ганглий и сваять на основе что-нибудь свое.
Первая проблема. Оказалось что скрипт написан на PERL. Я никогда не изучал PERL. В своей работе также его не использую. Поэтому пришлось немного времени потратить на его изучение. Специалисты по PERL скорей всего обнаружат далее кривой с их точки зрения код. "Кто так пишет??!!". В свою защиту скажу что я потратил не более часа времени. Разумеется многие ньюансы я упустил. Так что, "не стреляйте в пианиста! играет как умеет" :)
Итак. Для работы программы требуется:
1. Установить интерпретатор PERL. Я поставил ActivePerl 5.22.0.
1.1.К нему нужно найти и скОчать библиотечку для работы с SOAP. Если не ошибаюсь она называется SOAP::lite.
2. Установить и настроить КриптоПРО для работы с электронной подписью. Расписывать как настраивается КриптоПРО с вашей эл.подписью я не стану. Тем более получение эл.подписи от авторизованного представителя.
Файловая структура проекта имеет следующий вид (у меня). На диске C создана папка RKN. Внутри нее содержатся 3 папки:
logs - содержит лог работы программы
result- папка куда попадает архив принятого файла
source - папка со скриптами (собственно сама программа)
Пример файла логов:
08_04_2016_02:00:03: !!!START!!!
08_04_2016_02:00:03: gotovim failovuyu peremennuyu faila zaprosa
08_04_2016_02:00:03: gotovim failovuyu peremennuyu faila podpisi
08_04_2016_02:00:03: Poluchaem opisanie metodov raboty s servisom cherez wdsl-shemu
08_04_2016_02:00:10: soap: OperatorRequestService=HASH(0x4083044)
08_04_2016_02:00:10: Otpravlyaem zapros getLastDumpDateEx
08_04_2016_02:00:10: Otpravlyaem zapros getResult
08_04_2016_02:00:14: Actualnaya versiya formata vigruzki: 2.2
08_04_2016_02:00:14: Otpravlyaem zapros sendRequest
08_04_2016_02:00:18: Code vigruzki: 958aa2e7e752409b36d075f6c40d7f70
08_04_2016_02:00:18: Otpravlyaem zapros sendRequest
08_04_2016_02:00:18: Pauza 60 sekund
08_04_2016_02:01:18: Otpravlyaem zapros getResult
08_04_2016_02:01:18: Pauza 30 sekund
08_04_2016_02:01:48: Otpravlyaem zapros getResult
08_04_2016_02:01:54: Pauza 30 sekund
08_04_2016_02:02:24: Code otveta: 1
08_04_2016_02:02:24: Text otveta: OK
08_04_2016_02:02:24: Uspeshno prinyat file: C:\rkn\result\register-08_04_2016_02_00_03.zip
08_04_2016_02:02:24: !!!END!!!
А пачиму не по-русски спросите вы? Хаааароший вопрос! Потому что мне лень было заморачиваться разбираться как PERL работает с кодировкой. И чтобы не получать кракозябры вместо кириллицы оставил все так :)
Папка source содержит 3 файла:
start.bat - батник для запуска работы скриптов
make_request.pl - перловый скрипт для формирования файла запроса.
get_register.pl - перловый скрипт для приема файла-архива, содержащий список запрещенных сайтов
Содержимое start.bat:
@echo on
rem удаляем ранее созданные файлы запроса и подписи
DEL C:\rkn\source\request*.* /f/q
rem Запускаем скрипт формирования запросов
perl C:\rkn\source\make_request.pl
rem запускаем утилиту для создания подписи
"C:\Program Files\Crypto Pro\CSP\csptest.exe" -sfsign -sign -detached -add -in C:\rkn\source\request.xml -out C:\rkn\source\request.xml.sig -my santaclaus@mail.ru
rem запускаем скрипт для полученрия списка запрещенных сайтов
perl C:\rkn\source\get_register.pl
Тут думаю все понятно. Если вы свой проект реализуете в другом месте, тогда поправьте пути до него. Пути до КриптоПРО также надо проставить свои. Обратите внимание! Адрес электронной почты должен быть: а) правильный и б) тот что стоит у вас в электронной подписи. В смысле на того кого была зарегистрирована подпись. Иначе будут проблемы с получением
Содержимое make_request.pl
use POSIX qw(strftime);
my $date = strftime "%Y-%m-%d", localtime;
my $date2 = strftime "%H:%M:%S.000+10:00", localtime;
#Удаляем старые файлы с запросом и подписью если такие есть
unlink('C:\rkn\source\request.xml');
unlink('C:\rkn\source\request.xml.sig');
#Формируем xml запрос на сервер
$request='<?xml version="1.0" encoding="windows-1251"?><request><requestTime>'.$date.'T'.$date2.'</requestTime><operatorName>Нзвание моей организации</operatorName><inn>1234567890</inn><ogrn>1234567890123</ogrn><email>santaclaus@mail.ru</email></request>';
#Создаем в рабочей директории файл запроса
my $filename = 'C:\rkn\source\request.xml';
open(my $fh, '>', $filename) or die "Не могу открыть '$filename' $!";
print $fh $request;
close $fh;
Данный скрипт нужно подправить соответствующим образом, указав в нем реквизиты своей организации, как то: название организации, ИНН, ОГРН, электронная почта. Обратите внимание!! Опять нужна правильная электронная почта!! Как не трудно заметить скрипт динамически указывает время запроса. Это все в соответствии с требованиями Роскомнадзора.
Содержимое get_register.pl
use strict;
use warnings;
use SOAP::Lite;
use DBI;
use Data::Dumper;
use MIME::Base64;
use utf8;
use XML::Simple;
use URI;
use Digest::MD5 qw(md5 md5_hex md5_base64);
use Encode qw(encode_utf8);
use POSIX;
use POSIX qw(strftime);
use Time::Local;
use File::Basename;
use Switch;
use Net::Ping;
my ( $req, $sig, $buf );
my $req_file = 'C:\rkn\source\request.xml';
my $sig_file = 'C:\rkn\source\request.xml.sig';
my $now_string = strftime "%d_%m_%Y_%H_%M_%S", localtime;
my $now_date = strftime "%d_%m_%Y", localtime;
my $FileName = 'C:\rkn\result\register-'.$now_string.'.zip';
my $lof_file = 'C:\rkn\logs\work_'.$now_date.'.log';
sub insert_into_log{
my $in_str = $_[0];
my $now_string = strftime "%d_%m_%Y_%H:%M:%S", localtime;
if (-e $lof_file) {
#file exists
open FILE, '>>'.$lof_file;
print FILE $now_string.": ".$in_str."\n";
close FILE;
} else {
#file NOT exists
open FILE, '>'.$lof_file;
print FILE $now_string.": ".$in_str."\n";
close FILE;
}
}
#-----------------------------------------------------------------------
insert_into_log("!!!START!!!");
insert_into_log("gotovim failovuyu peremennuyu faila zaprosa");
# request
open F, '<'.$req_file || die $!;
binmode F;
while( (read F, $buf, 65536) != 0 ) {
$req .= $buf;
}
close F;
insert_into_log("gotovim failovuyu peremennuyu faila podpisi");
# signature
open F, '<'.$sig_file || die $!;
binmode F;
while( (read F, $buf, 65536) != 0 ) {
$sig .= $buf;
}
close F;
insert_into_log("Poluchaem opisanie metodov raboty s servisom cherez wdsl-shemu");
#----------------------------
#Получаем описание методов для работы с сервисом через wsdl-схему
my $soap = SOAP::Lite->service('http://vigruzki.rkn.gov.ru/services/OperatorRequest/?wsdl');
insert_into_log("soap: ".$soap);
insert_into_log("Otpravlyaem zapros getLastDumpDateEx");
my $answ = 0;
my $dfv = "";
while ($answ eq 0) {
insert_into_log("Otpravlyaem zapros getResult");
#Отправляем запрос на сервер
my @r = $soap->getLastDumpDateEx();
if($r[3] eq ""){
insert_into_log("Actualnaya versiya formata vigruzki poluchena ne byla!");
sleep 10;
}else{
$answ = 1;
#dumpFormatVersion
$dfv = $r[3];
insert_into_log("Actualnaya versiya formata vigruzki: ".$dfv);
}
}
$answ = 0;
my $code = "";
while ($answ eq 0) {
insert_into_log("Otpravlyaem zapros sendRequest");
#Отправляем запрос на сервер
my @r2 = $soap->sendRequest($req, $sig, $dfv);
if($r2[2] eq ""){
insert_into_log("Code vigruzki poluchen ne byl!");
sleep 10;
}else{
$answ = 1;
#dumpFormatVersion
$code = $r2[2];
insert_into_log("Code vigruzki: ".$code);
}
}
insert_into_log("Otpravlyaem zapros sendRequest");
binmode(STDOUT, ':utf8');
my $wait_interval = 60;
insert_into_log("Pauza ".$wait_interval." sekund");
sleep $wait_interval;
#sleep 1, print "$_\s" for 1..$wait_interval;
my $result;
my $resultCode = 0;
my @r3;
while ($resultCode eq 0) {
insert_into_log("Otpravlyaem zapros getResult");
@r3 = $soap->getResult($code);
$result = $r3[0];
$resultCode = $r3[2];
insert_into_log("Pauza 30 sekund");
sleep 30;
#sleep 1, print "$_\s" for 1..30;
}
insert_into_log("Code otveta: ".$resultCode);
switch ($resultCode) {
case -1 { insert_into_log("Text otveta: Neverniy algoritm podpisi") }
case -2 { insert_into_log("Text otveta: Neverniy format podpisi") }
case -3 { insert_into_log("Text otveta: Nedeistvitelniy sertifikat podpisi") }
case -4 { insert_into_log("Text otveta: Nekorrektnoe znachenie podpisi") }
case -5 { insert_into_log("Text otveta: Oshibka proverki serificata podpisi") }
case -6 { insert_into_log("Text otveta: U zayavutelya otsustvuet licensia na uslugi dostupa v Internet") }
case -7 { insert_into_log("Text otveta: Otsutstvuet ID zaprosa") }
case -8 { insert_into_log("Text otveta: Neverniy format ID zaprosa") }
case -9 { insert_into_log("Text otveta: Ne naiden zapros po ukazannomu ID") }
case -10 { insert_into_log("Text otveta: Povtorite zapros pozdnee") }
case 0 { insert_into_log("Text otveta: Zapros obrabativaetsa") }
case 1 { insert_into_log("Text otveta: OK") }
else { insert_into_log("Text otveta: Neopredelennaya oshibka") }
}
if($resultCode eq 1){
my $zip = decode_base64($r3[1]);
open F, '>'.$FileName || die "Can't open arch.zip for writing!\n".$! ;
binmode F;
print F $zip;
close F;
insert_into_log("Uspeshno prinyat file: ".$FileName);
}else{
insert_into_log("Prinyat file ne udalos");
}
insert_into_log("!!!END!!!");
Ну собственно вот и оно :)
Как не трудно заметить каждое действие предваряет внесение в лог записи о начале этого действия. А после действия в лог вносится сведения об успешности его. Если на каком-то этапе программа не сработает, тогда будет понятно в логе где копать.
Про почему не на русском я уже говорил.
Мне не правится обращение к элементам массива по их порядковым номерам. Но вариант с обращением по имени почему-то не сработал, глубоко копаться в PERL я не стал. Поэтому код такой корявый.
Программа работает в большинстве случаев. Но иногда виснет когда по какой-то причине не прошел запрос. ну там сайт не работает, энторнета не было или что-то еще. Я не стал дописывать скрипт внося соответствующие проверки. Бог в помощь если кто могёт! :)
Ну вообщем батник start.bat вешаете на запуск по расписанию и радуемся! :)