Главная > Программирование > Web-программирование > |
FAQ по Perl и программированию для Web |
Секция 2 из 2 - Предыдущая - Следующая
Надо отредактировать конфигурационные файлы (я рассчитываю, что у вас default конфиги apache) (NB: Apache/1.3.6 и выше по умолчанию конфигурируется только файлом httpd.conf. Директивы все остались прежние, просто их слили в один файл)
srm.conf
Директива ScriptAlias
ScriptAlias /cgi-bin/ /usr/local/apache/cgi-bin/
и в файле access.conf прописать
<Directory /usr/local/apache/cgi-bin/>
Options ExecCGI
</Directory>
(если пригляделся, там нужно только раскоментировать опции)
Это позволит вам помещать программы в каталог
/usr/local/apache/cgi-bin/ и они будут видны по URL
http://you/cgi-bin/program_name
Добавить в srm.conf директиву AddHandler cgi-script .cgi
и вы сможете вызывать cgi-программу из любого каталога. Но она должна иметь
окончание .cgi и для нее должно быть разрешено исполнение CGI
(Options ExecCGI в access.conf, написано выше).
Оба способа можно без проблем использовать совместно.
Прежде чем читать дальше, убедитесь в том, что:
error_log для того и служит, чтобы туда смотреть :-)
Возникает, если сервер не может отдать вам содержимое по причине отсутствия полномочий.
Проверьте:
Возникает в случае внутренней ошибки.
Проверьте:
print "Content-Type: text/html\n";
print "<HTML>\n";
Надо писать:
print "Content-Type: text/html\n\n"; # Два "\n"
print "<HTML>\n";
Также, эта ошибка возникает, если CGI-программа завершилась с ненулевым кодом возврата, что часто встречается в случае некомпилируемости вашего скрипта perl'ом.
Совет: делайте
use CGI::Carp qw(fatalsToBrowser)
во время отладки, тогда вам выдадут сообщение об ошибке perl.
apache устанавливает переменную окружения REMOTE_HOST, если ему разрешено проводить dns запросы для определения имени. Для 1.3.x по-умолчанию это выключено. Включается/выключается директивой HostNameLookups, которая может принимать 3 значения: on -- проводить запросы, off -- не запрашивать dns и double -- делать двойные запросы: запрашивать имя хоста, а затем по имени запрашивать ip адрес, для безопасности.
Переменная окружения REMOTE_USER устанавливается apache в случае, если скрипт защищен паролем. Как это сделать рассказано на http://www.apacheweek.com/features/userauth и http://www.apacheweek.com/features/dbmauth
Это perl, вкомпилированный в apache, что придает многие преимущества:
Правда, ничего не дается даром и самый важный недостаток mod_perl -- огромный расход памяти: если обычный apache занимает при работе обычно меньше мегабайта, то apache с mod_perl размером в 10-15 Mb -- вполне нормальное явление. Но, при правильной настройке, значительная часть этой памяти будет shared между копиями процессов.
Основной сайт про mod_perl - http://perl.apache.org, в частности великолепный mod_perl Guide на http://perl.apache.org/guide/.
Программа CGI исполняется один раз, за тем умирает. Под mod_perl же она загружается и исполняется до смерти сервера (в случае использования Apache::Registry, см. далее), поэтому она требует более аккуратного описания - закрывать файлы, не использовать много памяти, и тд.
Более подробно о переписывании программ CGI под mod_perl - http://perl.apache.org/guide/porting.html.
Да, можно. CGI не зависит от используемого языка программирования.
Это далеко неполный список. (Почти полностью списано из CGI_metaFAQ от brian d foy).
Вы можете использовать простой текстовый файл с разделителями. Например, если мы пишем нечто типа телефонной книги, то вполне вероятно предположить, что ни в чьем имени, ни в номере телефона не встретится последовательность ::, так что именно ее и можно использовать в качестве разделителей.
Файл с данными может выглядеть так:
phones.data
Иванов И.И.::888-0000::Какая-то улица, 17, кв 40
Сидоров П.И.::888-8429::Другая улица, 5, кв 21
...... и тд.
тогда программа, которая читает данные, может быть примерно такого вида:
dump_phones.pl
#!/usr/bin/perl
$filename = 'phones.data';
# открываем файл
open DATA, $filename or die "Невозможно открыть $filename: $!";
# читаем построчно из файла
while (<DATA>) {
chomp; # удаление символа конца строки
# теперь в $_ есть строка и мы ее разделяем на переменные
($name, $phone, $address) = split(/::/);
# и выведем на печать
print "Имя: $name, телефон: $phone, адрес: $address\n";
}
close DATA;
Больше проблем возникает в случае, если надо удалить или отредактировать запись, но и их можно довольно просто и элегантно решить, если использовать механизм редактирования на месте (inplace edit) -- при использовании операции "ромб"(<>), можно читать из одного файла, а писать в другой:
change_phones.pl
#!/usr/bin/perl
$^I = '~'; # запускаем inplace edit
while (<>) { # Обратите внимание, что мы не открывали файл: при такой
#конструкции имя файла берется из командной строки
chomp;
($name, $phone, $address) = split(/::/);
if (.... некоторое условие, при котором мы оставляем наши данные ... )
{
print "$name::$phone::$address\n"; # теперь данные есть в новом файле
}
}
если запустить это программу как
change_phones.pl phones.data,то в текущем каталоге будут два файла: phones.data, с записями, которые удовлетворили нашим условиям и phones.data -- предыдущая копия.
Также, во многих случаях, всю программу такого типа можно записать как one-liner:
perl -i~ -n -e 'print if(... условие)'
Для чтения двоичных файлов в Perl можно использовать функции read и unpack. К примеру, если использовать двоичный файл для хранения телефонной книги такого формата:
40 символов -- фамилия, И.О.
10 символов -- номер телефона,
60 символов -- адрес,
то строка описания формата для unpack будет выглядеть так:
$format_str = 'A40 A10 A60', а сама программа, аналогичная первому примеру:
binary_phones.pl
#!/usr/bin/perl
$format_str = 'A40 A10 A60';
open DATA, 'binary.dat' or die "$!";
while (read(DATA, $buf, 40+10+60)) { # <DATA> не покатит: такая
# конструкция будет читать до символа перевода строки, а это не то, что нужно
($name, $phone, $address) = unpack($format_str, $buf);
# Теперь в $name, $phone, $address есть данные и с ними можно делать
# все, что захочется
}
close DATA;
Чтобы вывести в файл такую запись можно использовать конструкцию типа
print FILE pack($format_str, $name, $phone, $address);
Да, можно. На http://www.fi.muni.cz/~adelton/ есть модуль XBase, который позволяет читать/писать dbf. При чтении он даже поддерживает индексы. Кроме того, в комплект поставки также входит модуль DBD::XBase, при помощи которого можно оперировать dbf на SQL (более подробно про DBI -- далее).
К файлам MS Access нельзя обращаться из perl напрямую, по крайней мере, в настоящее время.
К MS Access можно обращаться по ODBC, при помощи DBD::ODBC.
Представьте себе ситуацию когда одновременно работают несколько копий одной и той же программы (к примеру, cgi-скрипты, обслуживающие запросы), читающие/пишущие в один файл, тогда рано или поздно возникнет ситуация при которой один скрипт прочитал данные, произвел над ними некоторые действия и собрался записать их назад в файл, но в это же время другой скрипт тоже прочитал данные, тоже произвел над ними действия, но (!) он прочитал старые данные, которые он и запишет поверх данных, выданных другим скриптом. Таким образом, в файле останутся данные записанные одним из скриптов -- в лучшем случае, в худшем -- структура файла будет испорчена. Чтобы этого избежать в Unix и большинстве других ОС есть системный вызов flock(2) или аналогичный.
К примеру, скрипт который записывает имена вызывающих хостов в файл. (На деле такой список, конечно, можно получить из журнала регистрации web-сервера).
lock_exm.pl
#!/usr/bin/perl
use Fcntl; # Импорт констант
open (HOSTS, '>>hosts.log'); # Файл открыт для добавления записи
flock(HOSTS, LOCK_EX);
# Теперь файл заблокирован: Если любой другой скрипт тоже вызовет flock на
# этом файле, его flock не вернет управление в программу, пока мы не
# разблокируем файл. Обратите внимание: flock -- декларативная функция, если
# один из скриптов ее не использует при записи, то вся ваша блокировка не
# работает.
print HOSTS $ENV{REMOTE_HOST}, "\n"; # записали строку
close HOSTS; # Файл при закрытии разблокируется автоматически
# Вывести сообщение для пользователей
print "Content-Type: text/plain\n\n";
print "Название вашего хоста записано\n";
Более подробный рассказ о flock и пример доступны на http://w3.stonehenge.com/merlyn/WebTechniques/col04.html
Судя по perlfaq5(1), можно использовать модуль File::Lock с CPAN.
DBI -- это интерфейс прикладных программ к СУБД, использующим SQL в качестве языка запросов. Сам DBI определяет только набор функций, переменных и соглашений. Вся непосредственная работа выполняется Database Drivers (DBD) -- модулями, обеспечивающими связь с СУБД. DBI только обеспечивает стандартный интерфейс для этих драйверов.
Полная схема архитектуры при работе DBI выглядит примерно так:
+----------------------+
| Прикладная программа |
+----------------------+
| DBI |
+----------------------+
| DBD |
+----------------------+
| СУБД |
+----------------------+
обеспечивается при помощи метода connect класса DBI:
$dbh = DBI->connect($dsn, $user, $auth, {options});
Это объект, при помощи его методов осуществляются взаимодействия с СУБД.
Строка, определяющая к какой базе данных подсоединятся и другие параметры. Зависит от DBD. На сегодняшний момент стандарта нет, но рекомендовано использовать стиль ODBC:
&dbi:<имя DBD>:databasename=<название БД>;host=<Имя хоста>;port=<порт>&;
Имя пользователя.
Нечто, авторизующее пользователя. Обычно пароль.
Параметры DBI, передаются через анонимный хеш. В настоящее время понимаются три параметра:
если установлен, то при любой ошибке DBI убивает программу
если установлен, то при ошибке DBI вызывает warn
определяет порядок работы с транзакциями.
Например:
$dbh = DBI->connect('dbi:Pg:dbname=apavel', 'apavel', 'SomeSecret', {RaiseError=>1, AutoCommit=>0});Означает: Подсоедение к СУБД PostgreSQL, к базе данных apavel, с именем пользователя apavel и паролем. Все ошибки будут вызывать die, что удобно при отладке, а все изменения будут внесены только при подтверждении (commit) транзакций.
Отсоединение обеспечивается при помощи метода disconnect: $dbh->disconnect();
При работе с базами данных при помощи DBI используются курсоры -- специальные объекты, обеспечивающие последовательный доступ к результатам запросов. (В простейших случаях можно обойтись и без них, я расскажу об этом дальше.)
Пример таблицы, используемый в дальнейшем:
foo.sql
create table foo (
bar varchar(50),
baz int
)
$cursor = $dbh->prepare('select bar, baz from foo');
# теперь $cursor -- курсор, и его необходимо исполнить
$cursor->execute;
# После исполнения запроса, результат можно получить из курсора при помощи
# метода fetchrow_array
while (($bar, $baz) = $cursor->fetchrow_array) {
print "bar is: $bar, baz: $baz\n";
}
Очень часто бывает надо подготовить какой-либо запрос, а потом использовать его с разными значениями данных. DBI предлагает для механизм placeholders: В запросе на месте таких данных указываются вопросительные знаки, а сами значения передаются в метод execute() курсора. Например:
$cursor = $dbh->prepare('select bar from foo where baz=?'); $cursor->execute($baz);Особенно удобно это в случае вставки данных:
$cursor = $dbh->prepare('insert into foo(bar, baz) values(?, ?)'); while ( ... ) { $cursor->execute($bar, $baz); }
Таким образом, СУБД разбирает запрос только один раз, а затем просто исполняет его, что экономит время. (Естественно, это верно только для DBMS с раздельными parse и execute, сейчас ни MySQL, ни PostgreSQL такое не поддерживают, поэтому их реализации DBD просто сохраняют запрос переданный $dbh->prepare() и затем подставляют в него данные при каждом $sth->execute().)
DBI предоставляет несколько методов для такого рода работы: Методы для запросов:
Возвращает одну строку запроса в виде массива
Возвращает весь ответ сервера в виде массива ссылок на массивы.
исполняет запрос
Пример:
#получить значение bar при baz=3
($bar) = $dbh->selectrow_array('select bar from foo where baz=3');
# установить baz в некоторое значение при bar='somestring'
$dbh->do("update set baz=1 where bar='somestring'");
Можно несколькими способами: 1. Просто прокручивая курсор:
$c = $dbh->prepare('select baz, bar from foo');
$c->execute;
# если нужна последовательность с 26 по 50
for ($k = 0; $k < 26; $k++) {
$c->fetchrow_array;
}
# теперь можно вывести данные
print "<table border=1><tr><th>bar</th><th>baz</th></tr>\n";
while (($bar, $baz) = $c->fetchtrow_array) {
print "<tr><td>$bar</td><td>$baz</td></tr>\n";
}
$c->finish; # Закрыть курсор
print "</table>";
2. Используя курсоры СУБД
# Показан синтаксис PostgeSQL
$dbh->do('declare mycursor cursor for select bar, baz from foo');
$dbh->do('move 25');
# И теперь будем получать данные
$c = $dbh->prepare('fetch forward 25 in mycursor');
while (($bar, $baz) = $c->fetchrow_array) {
print ....;
}
$c->finish;
$dbh->do('close mycursor');
3. Для MySQL можно использовать директиву LIMIT
$c = $dbh->prepare('select bar, baz from foo limit 26,25');
while (($bar, $baz) = $c->fetchrow_array) {
print ....;
}
$c->finish;
Вроде как можно при помощи DBD::FreeTDS
Потому что на windows нет flock(2).
Используйте File::Lock с CPAN.
Windows это не unix. Они fork не умеют.
Perl для этого опирается на механизм locale. К счастью, это работает и на windows:
Если надо работать с CP866, пишем
use locale; use POSIX; &POSIX::setlocale(&POSIX::LC_ALL, "Russian_Russia.866"); print uc "Да, здесь будут заглавные буквы";
если KOI8 (sic!):
&POSIX::setlocale(&POSIX::LC_ALL, "Russian_Russia.20866");
если с CP1251 -- просто
use locale;
Со всеми тремя кодировками работают и uc/lc, и /\w/
Проверено под NT на perl 5.005_02, собраном через VC++ 5.0 из исходников, скачанных с CPAN/ports/win32/Standard/
Этому может быть миллион разных причин, но самая часто встречающаяся -- unix и наследники CP/M используют разные последовательности конца строки.
Если вы их загружаете по ftp, включите режим ASCII.
Секция 2 из 2 - Предыдущая - Следующая
Вернуться в раздел "Web-программирование" - Обсудить эту статью на Форуме |
Главная - Поиск по сайту - О проекте - Форум - Обратная связь |