Написание CGI-скриптов на perl'е.


Прислал: Михаил Бабаков [ 21.11.2000 @ 18:18 ]
Раздел:: [ Статьи по Perl ]


Написание CGI-скриптов на perl'е и методы их использования при работы сайта под Apache и IIS
Михаил Бабаковї

Если вы хотите, что бы ваши CGI-сценарии на perl'е одинаково работали как в связке Unix + Apache и Win* + IIS и при этом вам не нужно было бы держать две копии исходников, то возможно приводимые ниже рецепты вам помогут.

Это был мой первый проект в котором заказчик поставил условие, что сайт должен работать не только под юниксом, но и под виндовс. Он допускал, что может понадобиться две версии сайта, но похоже удалось обойтись одной. Вот то как и удалось этого добится я и опишу. Возможно, где-то кто-то уже описывал аналогичный опыт и я буду рад если вы пришлете мне ссылку. Все эти эксперименты отбирают много времени.

Я буду рад услышать и ответы на вопросы:

  1. Как можно настроить IIS для работы с koi8-r?
  2. Как можно настроить 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; }