Написание CGI-скриптов на perl'е.
Написание CGI-скриптов на perl'е и методы их
использования при работы сайта под Apache и IIS
Михаил Бабаков
Если вы хотите, что бы ваши CGI-сценарии на perl'е одинаково работали как в
связке Unix + Apache и Win* + IIS и
при этом вам не нужно было бы держать две копии
исходников, то возможно приводимые ниже рецепты вам помогут.
Это был мой первый проект в котором заказчик поставил условие, что сайт должен
работать не только под юниксом, но и под виндовс. Он допускал, что может понадобиться
две версии сайта, но похоже удалось обойтись одной. Вот то как и удалось этого
добится я и опишу. Возможно, где-то кто-то уже описывал аналогичный опыт и я буду
рад если вы пришлете мне ссылку. Все эти эксперименты отбирают много времени.
Я буду рад услышать и ответы на вопросы:
- Как можно настроить IIS для работы с koi8-r?
- Как можно настроить IIS для работы с <!--#virtual include="cgi.pl"-->, чтобы
вставлялся не текст скрипта, а вывод его работы.
Если вы обнаружите в тексте какие-либо не точности или у вас есть дополнения, то
очень прошу сообщить мне об этом.
Я черезвычайно признателен всем пишущим в конференциях ru.cgi.perl и ru.perl
(fido7.ru.cgi.perl и
fido7.ru.perl в нотации Usenet соответственно).
Итак.
Самое первое - посмотреть на описание переменной $^O в документации.
Затем, смириться с тем, что все программы должны возвращать текст в win1251. Т.е.
необходимо перекодировать скрипты. Я для этого использую пару скриптов
1.
Можно было бы обойтись одним и указывать ключик направления перекодировки, но мне показалось
так проще при использовании. Во-всяком случае, вам ни кто не мешает это реализовать. :)
Считаем, что все CGI-скрипты расположены в отдельной директории. Обычно это cgi-bin.
Но здесь и натыкаемся на первый подводный камень. Если провайдер не желает сваливать
все скрипты в одну кучу, то он для каждого виртуального сайта создает отдельную
директорию и в настройках apache переопределяет алиасинг доступа:
ScriptAlias /my-cgi/ /http2d/servers/my.virtual.web/cgi-bin/
Вы, как пользователь, ничего не знаете о реальном пути указанном в третьей части.
Вам достаточно знать, что для ссылки на скрипт вы пишите что-то типа:
<form method="POST" action="/my-cgi/your_script.pl">
Под Windows такой проблемы нет, т.к. IIS сам расширит ссылку /my-cgi/your_script.pl
до полного пути.
Отсюда вывод - надо попросить провайдера ведущего apache'вский сайт в ScriptAlias
заменить последний cgi-bin на my-cgi. Т.е. что-то типа:
ScriptAlias /my-cgi/ /http2d/servers/my.virtual.web/my-bin/
А провайдера ведущего IIS разрешить
исполнение скриптов на директорию my-cgi. Тогда вы получите одинаковые директории
для ваших скриптов под обе платформы и action="/my-cgi/your_script.pl" будет
правильно работать и там и там.
В самом общем случае, если нужны дополнительные модули, а провайдер отказывается
по каким-либо причинам их устанавливать вспомните об use lib qw(/path/to/yours/lib).
Причем, для Windows надо проверять настройку слэшей. Я попадал в ситуацию, когда
в одном случае под виндов требовались прямые слэши, в другом обратные. Но, так или
иначе:
use lib qw(your_siteel-cgi); # или qw(/your_site/my-cgi);
Самое неприятное, то что для Windows требуется указывать полный путь к вашим
библиотекам. Во всяком случае, иначе у меня не получилось.
В некоторых исходниках считается, что переменная $^O под виндовс возвращает "MSWin".
Возможно это и так. Но где уверенность, что завтра это значение не изменится? Поэтому,
я и использую конструкцию "/win/i"2.
Кодировка.
use locale;
use POSIX;
if ($^O !~ /win/i) {
POSIX::setlocale(&POSIX::LC_CTYPE, 'ru_RU.KOI8-R');
POSIX::setlocale(&POSIX::LC_COLLATE, 'ru_RU.KOI8-R');
}
else {
POSIX::setlocale(LC_CTYPE, "Russian_Russia.1251");
}
Безопасность.
Обязательно используйте use strict.
if ($^O !~ /win/i) {
$SIG{ALRM} = sub {die "$0 timed out"};
alarm 600; # умереть через 10 минут
}
$CGI::DISABLE_UPLOADS = 1; # запретить file uploads
$CGI::POST_MAX = 128; # max. ввод
Пути.
Обычно, если CGI-скрипт использует какие-либо внешние файлы, то из под Apache (читай
Unix), работают нормальные правила работы с путями. Т.е. если внешний файл лежит
в корне вашего сайта, то ссылка на него из скрипта находящегося в
my-cgi под Unix будет выглядеть как:
my $f = "../my_file";
Но под Windows все пути разименовываются IIS'ом как от корня сайта, т.е.
my $f = "my_file";
Поэтому, делаем так:
my $DIR = "..";
if ($^O !~ /win/i) {
$DIR = ".";
}
# ... какой-то код ...
my $f = "$DIR/my_file";
В этом случае ссылки на файл будут установлены правильно.
Странно, но иногда под Windows выдача "Content-type: text/htmlnn" приводит к
неожиданным результатам: отображение строки "Content-type: text/html" на экране
броузера. Поэтому:
if ($^O !~ /win/i) {
print "Content-type: text/htmlnn";
}
Если вам необходимо вставлять в html вывод скрипта, а не просто содержимое некоего
файла, то не смотря на все рекомендации использовать
<!--#include virtual="/my_cgi/including.pl"-->
под Windows вам прийдется использовать
<!--#exec cgi="/my_cgi/including.pl"-->
И, кстати, не забудьте при этом дать html-документу расширение .shtml.
Примечания.
1 Раньше я для перкодировки использовал программу под Windows
TextViewer, написанную Георгием Гуляевым
(//gul.nm.ru/ или
//www.freespeech.org/georgy/,
e-mail: gul@gmx.net). Но, во-первых, для ее работы
требуется наличие Windows. Во-вторых, обнаружился маленький глюк.
Если в программе используется определение хэшей, то происходит не адекватное их преобразование
при перекодировке. Например:
my %ucb;
my %lst;
Превращались в
my 0cb;
my t;
Как мне это подпортило крови пока нашел почему не работает уже отлаженный cgi-скрипт! :)
Возможно есть и другие связки символа % с латинскими буквами подвергающиеся
подобным превращениям - я специально не искал.
2 В первом варианте статьи предлагалось использовать "/[Ww][Ii][Nn]/".
Но один товарищ, который к сожалению предпочел остаться анонимом, напомнил о существовании
ключа i в регулярных выражениях. Я буду очень рад если он мне напишет.
Примеры скриптов.
Перекодировка файлов
Из win1251 в koi8-r
#!/usr/bin/perl
use strict;
print "Convert file from win1251 to koi8r encodingn";
my $prg = "w2k.pl";
if ($#ARGV < 1) {
print " use: $prg Infile Outfilen";
exit(0);
};
unless (-e $ARGV[0]) {
print " $prg: file $ARGV[0] don't existsn";
exit;
}
my $in = my $fi = $ARGV[0];
if($fi =~ ///) {
$fi = substr($fi, rindex($fi, "/")+1);
}
my $out = $ARGV[1];
if(-d $out) {
$out =~ s/[/]+$//;
$out .= "/".$fi;
}
print " $prg: $in... ";
open(IN, "$in") || die;
open(OUT, ">$out") || die;
while() {
s/%/%%/g;
printf OUT win2koi($_);
};
close(OUT);
close(IN);
print "$outn";
# from packages Lingua::RU::Charset
sub win2koi
{
my @str = @_; # copy the arguments
map { tr/xB8xA8xFExE0xE1xF6xE4xE5xF4xE3xF5xE8-xEFxFFxF0-xF3xE6xE2xFCxFBxE7xF8xFDxF9 xF7xFAxDExC0xC1xD6xC4xC5xD4xC3xD5xC8-xCFxDFxD0-xD3xC6xC2xDCxDBxC7xD8xDDxD9xD7xDA/xA3xB3xC0-xFF/ } @str;
return @str;
}
Из koi8-r в win1251
#!/usr/bin/perl
use strict;
print "Convert file from koi8r to win1251 encodingn";
my $prg = "k2w.pl";
if ($#ARGV < 1) {
print " use: $prg Infile Outfilen";
exit(0);
};
unless (-e $ARGV[0]) {
print " $prg: file $ARGV[0] don't existsn";
exit;
}
my $in = my $fi = $ARGV[0];
if($fi =~ ///) {
$fi = substr($fi, rindex($fi, "/")+1);
}
my $out = $ARGV[1];
if(-d $out) {
$out =~ s/[/]+$//;
$out .= "/".$fi;
}
print " $prg: $in... ";
open(IN, "$in") || die;
open(OUT, ">$out") || die;
while() {
s/%/%%/g;
printf OUT koi2win($_);
};
close(OUT);
close(IN);
print "$outn";
# from packages Lingua::RU::Charset
sub koi2win
{
my @str = @_; # copy the arguments
map { tr/xA3xB3xC0-xFF/xB8xA8xFExE0xE1xF6xE4xE5xF4xE3xF5xE8-xEFxFFxF0-xF3xE6xE2xFCxFBxE7xF8xFD xF9xF7xFAxDExC0xC1xD6xC4xC5xD4xC3xD5xC8-xCFxDFxD0-xD3xC6xC2xDCxDBxC7xD8xDDxD9xD7xDA/ } @str;
return @str;
}
|