Как сделать так, чтобы скрипт работал в фоновом режиме, как демон?
Варианта два. Первый - воспользоваться модулем Proc::Daemon, второй - сделать все самому, примерно так:
use strict;
require 'sys/syscall.ph';
# Устанавливаем путь по умолчанию
$ENV{PATH} = '/bin:/usr/bin';
# Чисто для прикола
$0='mydaemon';
# Отделяемся от родителя
fork() && exit;
# Отключаемся от терминала
close STDOUT; close STDERR; close STDIN;
# Делаем корень текужим каталогом
chdir '/';
# Создаем новую сессию и становимся лидером
# группы процессов, чтоб нас случайно не прибили
syscall(&SYS_setsid);
# Перехватываем сигналы, для корректного выхода
$SIG{'INT'} = $SIG{'QUIT'} = $SIG{'TERM'} = 'quit';
$SIG{'HUP'} = 'ignore';
# Делаем наши темные дела
...
# Выходим
quit();
sub quit {
# Помещаем сюда код для корректного
# прекращения работы
...
exit(0);
}
Если Вы хотите написать демона, реализующего работу через сеть, рекомендуем ознакомиться с модулем Net::Daemon.
Как сдеалать так, чтобы программа гарантированно работала только в одном экземпляре?
Способ первый, принятый в мире Unix:
$pidfile = '/var/run/mydaemon.pid';
if (-e $pidfile) {
# aha, pid file is here, but process could be dead by now
my $myfile=file_name($0);
unless (open(PIDFILE,$pidfile)) {
# too dangerous to start because I can't read old PID
exit 1;
}
my $oldpid=;
close PIDFILE;
# see if there is a process with such pid
if ($oldpid > 1 && kill(0,$oldpid)) {
# another proccess is running already
exit 1;
} else {
# that process is long dead
}
}
# write pid file
open (PID, ">$pidfile") or die;
print PID $$;
close(PID);
# do some work
...
# remove pid file
unlink $pidfile;
exit(0);
Способ второй, основанный на блокировании файлов:
# make a lock
$lockfilename="/tmp/mydaemon.lock";
unless (open (LOCKFILE,">$lockfilename")) {
die "cannot open lock file\n";
}
unless (flock (LOCKFILE,LOCK_EX|LOCK_NB)){
print "my copy is already running\n";
exit(0);
}
# do some work
...
# unlock lock file
close(LOCKFILE);
unlink($lockfilename);
Где взять версию Perl для Windows?
Perl для Windows можно взять на web-сайте Active State
Tool Corp. - http://www.activestate.com. Дополнительные пакеты (DBI,
GB, MD5, LWP) для Perl под Windows -
http://www.activestate.com/PPMpackages/. Полезные советы по работе с
Perl под Windows (настройка работы под MS IIS, работа с ADO и ODBC)
можно посмотреть на Robin's Perl for Win32 pages.
Как инсталлировать дополнительные модули Perl для
Windows?
Вариант I - инсталляция из сети:
В состав поставки ActivePerl входит инструмент для
инсталляции пакетов Perl Package Manager (PPM). Для инсталляции
необходимого Вам пакета нужно запустить PPM, например, в ДОС сессии,
набрав команду
C:\>ppm
после этого можно инсталлировать нужный пакет
(модуль):
install <имя_модуля>
(пример: install DBD-CSV)
PPM установит его и пропишет в прилагаемый файл
документации.
Вариант II - инсталляция скаченного пакета
(модуля):
Вам нужно разархивировать скаченный модуль. После этого
найти файл, соответствующий названию пакета и имеющий расширение
'.ppd', и набрать команду:
ppm install <файл с расширением .ppd
(пример: ppm install libwin32.ppd)
PPM также позволяет Вам паковать свои собственные
модули в PPM-пакеты. Дополнительная информация о том, как это
сделать, и о том, где взять необходимые для этого программы nmake,
tar и gzip содержится в руководстве по ActivePerl в разделе
'ActivePerl Components' -> 'PPM' -> 'How do I make a PPM
package?'
Как сконфигурировать Микрософт IIS 4.0 для работы с
ActivePerl?
Частичный перевод раздела ActivePerl FAQ - Web Server
Config из руководства, поставляемого вместе с ActivePerl.
Чтобы настроить IIS или PWS 4.0, для запусков сценариев
Perl сделайте следующее:
- Запустите IIS 4.0 Internet Service Manager.
- Выберите нужную Вам папку (уровень) в дереве
директорий из которой будут запускаться Ваши приложения. Вы можете
выбрать сервер целиком, веб-сервер, или создать виртуальную
директорию.
- Выберите пункт из меню.
- ...
- Нажмите кнопку . Запуститься диалоговое окно
конфигурации.
- Выбор закладку и нажмите . Запуститься диалог
настройки приложений.
- Для того, чтобы запускать Perl как приложение CGI,
наберите полный путь к Perl.EXE и добавьте в конце %s %s. При
запуске Perl сценария в первый %s будет подставляться полный путь
на сценарий, а во второй %s -параметры сценария.
- Для запуска Perl для ISAPI, наберите полный путь на
PerlIS.DLL. Указывать %s %s в этом случае не требуется.
- В качестве расширения для приложений (в поле ),
укажите .pl или .plx (или то, которое Вы хотите использовать для
ваших Perl сценариев).
- Настройка теперь завершена. Нажмите <ОК> и
нажмите еще раз <ОК> для сохранения изменений.
- Закройте IIS 4.0 Internet Service Manager. Так как
IIS работает как сервис, Вы должны убедиться в том, что файлы и
переменные окружения доступны для него (возможно, Вам придется
перезапустить сервис).
Комментарии:
- Пункты 4, 5, 6 описывают какое из окон появиться
при выборе сервера целиком, веб - сервера и виртуальной
директории.
- Рекомендую также посмотреть http://www.geocities.com/SiliconValley/Park/8312/perlis.htm
- ответы на проблемы с Microsoft Webserver. Там приводятся
указания по самостоятельной настройке реестра, описываются
различия в работе CGI и ISAPI и т.п.
Как получить значение переменной по имени?
Как получить значение переменной, имя которой записано
в другой переменной?
Пример 1:
$var1 = 'lalala';
$var2 = 'var1';
$res = ${$var2};
Значение $res будет - lalala
Пример 2 (посложнее):
$complex_var = 'qqqq';
$simplex_var = 'zzzz';
$modifier = 'complex';
$result = ${"${modifier}_var"};
Значение $result будет - qqqq
Можно ли скомпилировать из Perl исполняемый
файл?
Вы можете воспользоваться программой Perl2Exe. Это
утилита для преобразования Perl сценариев в выполняемые файлы, не
требующие присутствия интерпретатора языка Perl.
Perl2Exe может сгенерировать модули для Win32 и многих
клонов Unix.
Perl2Exe также позволяет Вам создавать не консольные
программы, с использованием Tk.
Разработчик - IndigoSTAR Software. "Домашняя
страница"
Еще один продукт IndigoSTAR Software - SendMail for
Windows(TM) - Windows версия популярной программы Unix Sendmail. Она
позволяет отправлять сообщений из командной строки, CGI сценария или
BAT-файла.
А как мне проверить соответствие введенного пароля
зашифрованному?
Первых два символа пароля соджержат шифровальный ключ.
Если взяв их зашифровать проверяемый пароль, то зашифрованные строки
должны совпасть. Пример:
if (crypt($entered_passwd,subst($crypted_passwd,0,2))
eq $crypted_passwd) {
# Пароль верен
} else {
# Пароль не верен
}
Как получить статистику по файлу (время создания,
изменения и т.п.)?
Как минимим двумя способами!
Вариант 1:
if (-e $filename) { print "Файл существует.\n"; }
if (-z $filename) { print "Файл существует с нулевым размером.\n"; }
if ($size = -s $filename) { print "Файл существует, размер $size.\n"; }
if (-r $filename) { print "Файл может мной читаться.\n"; }
if (-w $filename) { print "Файл может мной исправляться.\n"; }
if (-x $filename) { print "Файл может исполняться.\n"; }
if (-o $filename) { print "Файл мой!\n"; }
if (-f $filename) { print "Файл - это файл.\n"; }
if (-d $filename) { print "Файл - это каталог.\n"; }
if (-l $filename) { print "Файл - это символическая ссылка.\n"; }
if (-p $filename) { print "Файл - это FIFO.\n"; }
if (-S $filename) { print "Файл - это сокет.\n"; }
if (-b $filename) { print "Файл - это блок-ориентированный файл.\n"; }
if (-c $filename) { print "Файл - символьное спец. устройство.\n"; }
if (-t $filename) { print "Файловый манипулятор открыт для терминала.\n"; }
if (-u $filename) { print "У файла установлен бит setuid\n"; }
if (-g $filename) { print "У файла установлен бит setgid\n"; }
if (-k $filename) { print "У файла установлен бит запрета (бит-липучка)\n"; }
if (-T $filename) { print "Файл - текстовый.\n"; }
if (-B $filename) { print "Файл - двоичный.\n"; }
$modific_time = int(-M $filename);
print "возраст файла (с момента изменения) в днях $modific_time.\n";
$access_time = int(-A $filename);
print "дней с последнего чтения файла $access_time.\n";
$ctime = int(-C $filename);
print "возраст изменения файлового дескриптора в днях $ctime";
Вариант 2:
Воспользоваться функцией stat
stat FILEHANDLE
stat EXPR
stat возвращает список из 13-ти элементов. Параметры
FILEHANDLE - дескриптор, или EXPR - название. Если EXPR опускается,
это равносильно вызову stats `$_.
В случае неудачи возвращает пустой список.
($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,
atime,$mtime,$ctime,$blksize,$blocks) = stat($filename);
где:
0 dev device number of filesystem
1 ino inode number
2 mode file mode (type and permissions)
3 nlink number of (hard) links to the file
4 uid numeric user ID of file's owner
5 gid numeric group ID of file's owner
6 rdev the device identifier (special files only)
7 size total size of file, in bytes
8 atime last access time in seconds since the epoch
9 mtime last modify time in seconds since the epoch
10 ctime inode change time (NOT creation time!) in seconds since the epoch
11 blksize preferred block size for file system I/O
12 blocks actual number of blocks allocated
Модуль File::stat обеспечивает удобный, механизма
доступа к файлам по именам:
Примеры:
($READ_TIME, $MOD_TIME) = (stat($filename))[8,9];
$READ_TIME = localtime($READ_TIME);
$MOD_TIME = localtime($MOD_TIME);
print "\n последнее обращение к $filename- $READ_TIME";
print "\n последнее изменение $filename- $MOD_TIME";
$mode = (stat($filename))[2];
printf "Права доступа к файлу %04o\n", $mode & 07777;
Как можно стандартизировать (оформить в виде
процедуры) получение выборки из БД, чтобы получать набор записей с
именованными полями?
Это можно сделать так:
sub QueryArrayOfHashes
my ($DB, $query) = @_;
my ($result,$data_hash,@items,$key,$val,%hash);
$result = $DB->prepare($query);
$result->execute or return;
while ($data_hash=$result->fetchrow_hashref)
%hash=%$data_hash;
push @items,{%hash};
}
$result->finish;
@items;
}
Комментарии:
$data_hash - ссылка на хэш
%$data_hash == %{$data_hash} - получение самого хэша из
ссылки
{%hash} = разименованный хэш - чтоб получился массив
хэшей, а не просто один массив
@items в данном случае == return @items
Пример использования:
use DBI;
...
$dbh=DBI->connect('DBI:mysql:mysql:localhost', $user, $password,
{RaiseError => 1})
or die "connecting : $DBI::errstr\n";
@res = QueryArrayOfHashes($dbh, "select user, password from user");
for ($i=0; $i<=$#res; $i++) {
print "\n[Record #$i]::\n";
foreach $key (sort keys %{$res[$i]}) {
# запись вида $a[1]{b} эквивалентна $a[1]->{b}
print $key, "\t", $res[$i]{$key}, "\n";
}
}
$dbh->disconnect;
Как мне сделать аутентификацию на Перле, а не
средствами веб-сервера?
Для того, чтобы браузер выдал запрос логина и пароля,
скрипт должен выдать следующие заголовки:
print "WWW-Authenticate: Basic realm=\"что то там\"\n";
print "Status: 401 Unauthorized\n\n";
print "Ошибка авторизации!\n";
При этом "что то там" - это имя области авторизации, по
правилам для области с одним именем должен всегда срабарывать один и
тот же пароль. Проблема заключается в том, что ответ пользователя
сидит в заголовке HTTP-запроса, в поле Authorization, которое
скрипту через переменные окружения не передаётся. Для сервера Апаче
эта проблема решается прописыванием в файле конфигурации следующих
строк:
RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^(.*) - [E=HTTP_CGI_AUTHORIZATION:%1]
Всё что он делает - это добавляет в переменную
окружения HTTP_CGI_AUTHORIZATION, в которую пишется содержимое HTTP
заголовка Authorization, таким образом означенное поле становится
доступным для анализа внутри скрипта. Формат этого поля следующий:
"login:password", причём эта строка закодирована в Base64, получить
эти составляющие можно так:
use MIME::Base64;
$ENV{HTTP_CGI_AUTHORIZATION} =~ s/basic\s+//i;
($REMOTE_USER,$REMOTE_PASSWD) =
split(/:/,decode_base64($ENV{HTTP_CGI_AUTHORIZATION}));
Как сделать upload картинки через форму?
В случае, если вам не претит воспользоваться модулем
CGI, это будет выглядеть примерно так:
use CGI qw/:standard/;
# Код для формы
print "Content-Type: text/html\n\n";
print <<EOF;
<html><head><title>file upload</title></head>
<body>
<form method="post" enctype="multipart/form-data" action="upload.pl">
<input type="file" name="picture">
<input type="submit" name="Submit" value="Submit">
</form>
</body>
</html>
EOF
insert_image() if (param());
sub insert_image {
# путь к директории для закачки директория
# должна иметь право на запись для
# пользователя, под которым работает веб-сервер
my $downpath = "download/";
my $in=param('picture');
# выделяем имя файла из параметра
my ($name) = $in =~ m#([^\\/:]+)$#;
open(OUT,">$downpath$name");
binmode(OUT);
# читаем входной поток и пишем в файл
while (<$in>) {
print OUT $_;
}
close(OUT);
# выводим надпись о закачке файла <$name>
print "<h2>Upload file: $name</h2>";
}