Статьи

Загрузка файлов с использованием CGI и Perl Article

Создание скрипта загрузки файла

Обработка данных, отправляемых браузером при загрузке файла, является довольно сложным процессом. К счастью, библиотека Perl CGI, CGI.pm

Используя два метода объекта запроса CGI, param и upload, мы можем получить имя загруженного файла и дескриптор файла соответственно. Используя дескриптор файла, мы можем прочитать содержимое файла и сохранить его в новом файле в нашей области загрузки файлов на сервере.

1. Перво наперво

В верхней части нашего сценария нам нужно создать строку shebang. Затем мы переводим интерпретатор Perl в строгий режим, чтобы сделать наш сценарий максимально безопасным, и включаем модули Perl CGI и File :: Basename для использования в сценарии. Мы также будем использовать модуль CGI :: Carp для отображения ошибок на веб-странице, а не для вывода общего сообщения «500 Server Error» (это хорошая идея закомментировать эту строку в производственной среде):

#!/usr/bin/perl -wT

использовать строгое;
использовать CGI;
используйте CGI :: Carp qw (fatalsToBrowser);
использовать File :: Basename;

Обратите внимание на использование ключа -w Почти всегда хорошая идея вставить -w Кроме того, переключатель -T Это гарантирует, что любой ненадежный ввод в скрипт, такой как имя файла загруженного файла, будет помечен как испорченный; Затем мы должны явно «очистить» эти данные перед их использованием. (Если вы попытаетесь использовать испорченные данные, Perl выдаст ошибку.) Подробнее об этом чуть позже.

2. Установка пределов безопасности

Чтобы предотвратить перегрузку сервера огромными загрузками файлов, мы ограничим допустимый размер загружаемого файла до 5 МБ; это должно быть достаточно большим, чтобы обработать большинство цифровых фотографий:

$CGI::POST_MAX = 1024 * 5000;

Мы также создадим список «безопасных» символов для имен файлов. Некоторые символы, такие как косая черта ( / Вообще говоря, буквы, цифры, подчеркивания, точки и дефисы являются безопасными ставками:

my $safe_filename_characters = "a-zA-Z0-9_.-";

3. Каталог загрузки

Нам нужно создать местоположение на нашем сервере, где мы можем хранить загруженные файлы. Мы хотим, чтобы эти файлы (фотографии) были видны на нашем веб-сайте, поэтому мы должны хранить их в каталоге под корнем нашего документа, например:

my $upload_dir = "/home/mywebsite/htdocs/upload";

Вам нужно будет создать каталог с именем «upload» в корне документа вашего веб-сайта, а затем установить $upload_dir Убедитесь, что ваш каталог может быть прочитан и записан вашим скриптом; на общем сервере UNIX это обычно означает установку mode777chmod 777 upload Если вы не уверены, что вам нужно делать, обратитесь к своему веб-хостингу.

4. Чтение переменных формы

Следующим шагом является создание объекта CGI (мы назначаем его для $query это позволяет нам получать доступ к методам в библиотеке CGI.pm. Затем мы можем прочитать имя файла нашего загруженного файла и адрес электронной почты, который пользователь ввел в форму:

my $query = new CGI;
my $filename = $query->param("photo");
my $email_address = $query->param("email_address");

Если при загрузке файла возникла проблема — например, файл был больше, чем параметр $CGI::POST_MAX$filename Мы можем проверить это и сообщить о проблеме пользователю следующим образом:

if ( !$filename )
{
print $query->header ( );
print "There was a problem uploading your photo (try a smaller file).";
exit;
}

5. Как сделать имя файла безопасным

Мы не можем обязательно доверять имени файла, которое было отправлено браузером; Злоумышленник может манипулировать этим именем файла, чтобы делать неприятные вещи, такие как загрузка файла в любой каталог на веб-сервере или попытка запуска программ на сервере.

Первое, что мы сделаем, это используем подпрограмму fileparse в модуле File :: Basename, чтобы разделить имя файла на его начальный путь (если есть), само имя файла и расширение файла. Затем мы можем спокойно игнорировать ведущий путь. Это не только помогает предотвратить попытки сохранить файл в любом месте на веб-сервере, но и некоторые браузеры отправляют полный путь к файлу на жестком диске пользователя, что, очевидно, бесполезно для нас:

my ( $name, $path, $extension ) = fileparse ( $filename, '..*' );
$filename = $name . $extension;

Приведенный выше код разбивает полное имя файла, переданное браузером, на часть имени ( $name$path$extension Чтобы найти расширение, мы передаем регулярное выражение '..*'. Затем мы присоединяем расширение обратно к имени, чтобы восстановить имя файла без начального пути.

Следующим этапом в нашем стремлении очистить имя файла является удаление любых символов, которых нет в нашем списке безопасных символов ( $safe_filename_characters Мы будем использовать оператор замены Perl ( s/// Пока мы это делаем, мы преобразуем любые пробелы в имени файла в подчеркивания, так как подчеркивания легче обрабатывать в URL:

$filename =~ tr/ /_/;
$filename =~ s/[^$safe_filename_characters]//g;

Наконец, чтобы вдвойне убедиться, что наше имя файла теперь безопасно, мы сопоставим его с нашим регулярным выражением $safe_filename_characters Мы также должны сделать это для отмены переменной $filename Эта переменная испорчена, потому что она содержит потенциально небезопасные данные, переданные браузером. Единственный способ освободить испорченную переменную — использовать сопоставление регулярного выражения для извлечения безопасных символов:

if ( $filename =~ /^([$safe_filename_characters]+)$/ )
{
$filename = $1;
}
else
{
die "Filename contains invalid characters";
}

(Обратите внимание, что вышеупомянутая функция die

6. Получение дескриптора файла

Как я упоминал выше, мы можем использовать метод загрузки, чтобы получить дескриптор загруженного файла (который фактически указывает на временный файл, созданный CGI.pm). Мы делаем это так:

my $upload_filehandle = $query->upload("photo");

7. Сохранение файла

Теперь, когда у нас есть дескриптор нашего загруженного файла, мы можем прочитать его содержимое и сохранить его в новом файле в нашей области загрузки файлов. Мы будем использовать имя загруженного файла — теперь полностью очищенное — как имя нашего нового файла:

open ( UPLOADFILE, ">$upload_dir/$filename" ) or die "$!";
binmode UPLOADFILE;

while (<$ upload_filehandle>)
{
распечатать UPLOADFILE;
}

закрыть UPLOADFILE;

Обратите внимание на функцию die в конце первой строки выше; если при записи файла произошла ошибка, эта функция останавливает выполнение скрипта и сообщает об ошибке (хранится в специальной переменной $! Между тем, функция binmode Это предотвращает повреждение загруженного файла на серверах не-UNIX (например, на машинах Windows).

8. Благодарность Пользователю

Мы загрузили наш файл! Последний шаг — отобразить быстрое благодарственное письмо пользователям и показать им их загруженную фотографию и адрес электронной почты:

print $query->header ( );
print <<END_HTML;
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Thanks!</title>
<style type="text/css">
img {border: none;}
</style>
</head>
<body>
<p>Thanks for uploading your photo!</p>
<p>Your email address: $email_address</p>
<p>Your photo:</p>
<p><img src="/upload/$filename" alt="Photo" /></p>
</body>
</html>
END_HTML

Готовый сценарий

Ваш законченный скрипт CGI должен выглядеть примерно так:

#!/usr/bin/perl -wT

использовать строгое;
использовать CGI;
используйте CGI :: Carp qw (fatalsToBrowser);
использовать File :: Basename;

$ CGI :: POST_MAX = 1024 * 5000;
my $ safe_filename_characters = «a-zA-Z0-9 _.-«;
my $ upload_dir = «/ home / mywebsite / htdocs / upload»;

мой $ query = новый CGI;
my $ filename = $ query-> param («photo»);
my $ email_address = $ query-> param («email_address»);

если (! $ имя файла)
{
напечатать $ query-> header ();
print «При загрузке фотографии возникла проблема (попробуйте файл меньшего размера).»;
выход;
}

my ($ name, $ path, $ extension) = fileparse ($ filename, ‘.. *’);
$ filename = $ name. $ Расширения;
$ filename = ~ tr / / _ /;
$ filename = ~ s / [^ $ safe_filename_characters] // g;

if ($ filename = ~ / ^ ([$ safe_filename_characters] +) $ /)
{
$ filename = $ 1;
}
еще
{
die «Имя файла содержит недопустимые символы»;
}

my $ upload_filehandle = $ query-> upload («photo»);

открыть (UPLOADFILE, «> $ upload_dir / $ filename») или умереть «$!»;
binmode UPLOADFILE;

while (<$ upload_filehandle>)
{
распечатать UPLOADFILE;
}

закрыть UPLOADFILE;

напечатать $ query-> header ();
печать << END_HTML;
<! DOCTYPE html PUBLIC «- // W3C // DTD XHTML 1.0 Strict // EN» «DTD / xhtml1-strict.dtd»>
<html xmlns = «http://www.w3.org/1999/xhtml» xml: lang = «en» lang = «en»>
<Голова>
<meta http-equ = «Content-Type» content = «text / html; charset = utf-8» />
<Название> Спасибо! </ Title>
<style type = «text / css»>
img {border: none;}
</ Стиль>
</ HEAD>
<Тело>
<p> Спасибо за загрузку вашей фотографии! </ p>
<p> Ваш адрес электронной почты: $ email_address </ p>
<p> Ваше фото: </ p>
<p> <img src = «/ upload / $ filename» alt = «Photo» /> </ p>
</ Body>
</ Html>
END_HTML

Сохраните этот файл на жестком диске и назовите его upload.cgi

Теперь мы создали наш серверный скрипт, мы можем разместить скрипт и форму на нашем сервере и протестировать загрузку файла.

Перейти на страницу: 1 | 2 | 3