如何使用CGI.pm模块和Perl上传文件

注意 :如果只需要perl代码,则可以跳到文章结尾。 介绍

将文件从本地计算机上传到远程Web服务器具有许多有用的目的,其中最明显的是文件共享。 例如,您将图像上载到服务器以通过Internet与其他人共享图像。 Perl已准备就绪,可以通过CGI.pm模块上传文件,而CGI.pm模块一直是核心模块,它允许用户执行许多操作而无需了解很多底层技术。

本文本身不是perl教程。 我不会在幕后做很多细节工作,而这些细节都会使一切正常。 有些部分必须包括简短的解释,当然也包括perl代码,但目的不是要教读者perl编程或一般的Internet概念。 我假设您具有HTML的使用经验,并且过去可能已经上载并安装了一两个perl脚本,并且知道该怎么做。 考虑本文更多是“如何做”课程。

我将向您介绍的perl脚本仅使用perl随附的核心模块,因此您无需安装任何模块。 您所需要的只是任何最新版本的perl。 当然,必须在要运行脚本的服务器上安装perl。 您还可以访问在线资源列表,以获取有关本文将要讨论的许多详细信息的更一般的信息。

入门

首先,您需要一个表格。 您可以随时在Internet上看到它们。 您填写一些信息,然后单击一个按钮以将数据发送到服务器。 那是一种形式。 准确的名称是CGI(通用网关接口)形式。 CGI是一种协议,它仅表示一组规则,允许您的计算机与远程服务器进行通信。 只要将服务器设置为可以接受CGI表单数据,并且大多数情况下,一切都很好。 您确实不需要了解任何信息,因此不必担心听起来令人困惑。

CGI表格

以下是一个非常简单的CGI表单:一个文件字段,用户在其中选择要上传的文件;一个文本字段,在此用户输入其电子邮件地址。 我仅以文本字段为例,如果您只需要文件上载字段,则不需要。 您可以选择添加许多其他表单字段,甚至添加更多“文件”字段,这些字段将同时将所有数据发送到服务器。


<FORM ACTION="/cgi-bin/upload.pl" METHOD="post" ENCTYPE="multipart/form-data">
<INPUT TYPE="file" NAME="photo">
<INPUT TYPE="text" NAME="email">
<INPUT TYPE="submit" NAME="Submit" VALUE="Submit Form">
</FORM> 
上面的表单将嵌入HTML文档中,并带有HTML文档应具有的所有适当标签。 如果不确定这些内容,则应该阅读基本的HTML(或网页)教程。 对于文件上传脚本,ENCTYPE =“ multipart / form-data”和TYPE =“ file”是最重要的。 ACTION =“ / cgi-bin / upload.pl”告诉表单将​​数据发送到哪里。 在这种情况下,您的cgi-bin文件夹中的perl脚本名为upload.pl,其中大多数cgi / perl脚本应存储在Web服务器上。 将表单另存为名为upload.html或您喜欢的任何名称的网页,然后将其上传到您的虚拟主机帐户。 如果您没有网络托管帐户,则从这一点开始并不需要太多。 CGI脚本

几乎所有作为CGI进程运行的perl脚本都需要以shebang行开头。 最常见的shebang行是:

#!/usr/bin/perl
它只是告诉服务器在哪里可以找到perl。 您的服务器所需的shebang行可能有所不同。 大多数网络主机会将这些信息发布在其网站的某个位置。 为了良好的perl编码实践和安全性,我们将在shebang行上添加一个开关:-T。 注意 :它必须是大写的T。
#!/usr/bin/perl -T
T代表“异味”模式。 作为脚本的程序员,这实际上是为了防止您犯一个可怕的错误,并允许CGI表单的用户将数据发送到服务器,而该数据可能以不安全的方式使用。 这个文件上传程序实际上非常简单,不会允许用户执行任何此类操作,但是作为CGI进程运行的所有perl脚本都应使用-T开关,因此出于这个原因我将其包括在内。 模组

模块有点像可以在perl程序中使用的单独的perl程序。 许多人编写的模块已成为其他perl程序员一直使用的标准。 我们将使用以下模块:


use strict;
use warnings;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use File::Basename; 
前两个不是模块,而是实用程序。 它们会影响perl本身的功能。 我不会为了本文的目的对它们进行解释。 您将不得不相信我,它们在几乎所有perl程序中都非常重要。 “ CGI”模块是将为我们完成所有繁重工作的模块。 它将处理表单数据并将其存储在服务器上。 “ CGI :: Carp”模块确实用于调试,如果有问题,可以帮助您使脚本运行。 如果有任何致命错误导致脚本失败,它将在屏幕上显示一条错误消息。 这些错误也将在服务器错误日志中打印出来。 “ File :: Basename”是一个模块,可用于将文件名/文件路径拆分为单独的部分,以方便脚本处理。 我们将使用它来获取脚本中的文件名和文件扩展名。 设定一些限制

我认为,所有CGI脚本都应限制可传输到服务器的数据量。 否则,一些带有T1线路的傻瓜将开始向您的服务器传输千兆字节的数据,或者使其他用户无法使用该数据,或者用完您分配的所有磁盘空间。 这是我们可以使用CGI模块设置限制的方法:


$CGI::POST_MAX = 1024 * 5000; # adjust as needed (1024 * 5000 = 5MB)
$CGI::DISABLE_UPLOADS = 0; # 1 disables uploads, 0 enables uploads 
第一行确定脚本将允许在服务器上存储的最大数据量(以字节为单位)。 这不是完美的,因为它必须先接收所有数据,然后才能知道有太多数据。 因此,一个人仍然可以尝试发送比您想要的更多的数据,但是脚本将拒绝它。 但在大多数情况下,它运行良好。 第二行使您可以轻松地完全禁用文件上载。 如果您要对网站进行某种类型的维护并且不希望人们在此期间上载文件,则可能偶尔需要这样做。 创建一个新的CGI对象或雇用一个管家

这是使用CGI模块(以及许多其他模块)的出色之处。 要访问CGI模块的所有功能,只需将以下行添加到脚本中:

my $query = CGI->new;
这将创建$ query对象,我们将在脚本的其余部分中使用该对象。 这个对象有点像我们的私人管家。 我们告诉管家使用简单的命令该怎么办,他便为我们做。 注意 :$ query可以是任何有效的标量名称。 注意 :CGI-> new不是绝对必要的。 还有另一种使用CGI模块大多数功能的方法,称为“标准”。 如果您有兴趣,请阅读CGI模块文档。 休斯顿,我们有一个问题

我希望您知道这意味着什么,如果不用,请不要担心。 代码的下一部分将检查CGI模块的版本是否足够新,足以按照我们想要的方式使用。 任何仍使用低于2.47的版本的服务器都应关闭,但是为了完整起见,我将其包括在内。


unless ($CGI::VERSION >= 2.47) { 
   error('Your version of CGI.pm is too old. You must have version 2.47 or higher to use this script.')
}
} 
如果版本太旧,脚本会向“ error()”子例程发送一条错误消息,警告用户错误。 上载文件的存储位置

这行可能是您最担心的原因:

my $upload_dir = '/home/you/public_html/uploads';
您必须确定什么是“ / home / you / public_html / uploads”。 由于您可能希望这些文件对访问您网站的用户可见,因此您希望将这些文件放在根Web文件夹下的文件夹中。 大多数服务器将根Web文件夹称为“ public_html”,有些将其称为“ www”。 “ public_html”的路径通常类似于: / home / you / public_html /

其中“您”是您的唯一标识符。 它可能是您网站名称的一部分或其他名称。 大多数网络主机会将这些信息发布在其网站上的某个位置。 在最后添加“上传”:

/ home / you / public_html / uploads

这就是将存储文件上传的文件夹。 如果您不希望人们看到文件,则可以将其放置在与根Web文件夹平行的文件夹中:

/ home / you /上载

或可能高于它:

/ home / uploads 验证用户输入或拒绝Riff-Raff

CGI编程的第一条规则是:

永远不要相信用户的输入 。 由于缺乏信任,所有CGI脚本都应执行所谓的验证用户输入。 在我们的案例中,我们没有太多的用户输入,只有一个电子邮件地址和要上传的文件。 但是您仍然必须检查它们两者。 互联网上的文件名实际上应该只包含一组有限的字符,它们是:

a至z,A至Z,0至9 _(下划线)。 (点)-(破折号)

以正式格式写成:“ a-zA-Z0-9 _.-”

我们将使用此字符列表来检查(并在必要时更改)要上传的文件名。 我们像这样定义该列表:

my $filename_characters = 'a-zA-Z0-9_.-';
注意 :像许多perl一样,这可以通过许多不同的方法来完成。 我试图使其保持相当简单,因此出于可读性和简单性的考虑,选择使用此方法。 在表单字段中阅读

在这里,我们告诉管家$ query,让我们的“访客”进入我们的“家”。


my $file = $query->param("photo") or error('No file selected for upload.') ;
my $email_address = $query->param("email") || 'Annonymous'; 
请注意括号中的名称如何与我们上面的表单字段中的名称匹配:

<INPUT TYPE="file" NAME="photo">
<INPUT TYPE="text" NAME="email"> 
案件也很重要。 “照片”与“照片”不同。 我们将param()调用的值放入一些perl变量中,以便我们可以对其进行更改并稍后在脚本中使用它们。

如果没有选择要上传的文件,脚本将向“ error()”子例程发送一条错误消息,警告用户错误。 如果未输入电子邮件地址,则将为$ email_address分配一个“匿名”值。

一些浏览器将整个路径发送到文件,而不仅仅是文件名。 如果需要,下一行将从文件路径中解析文件名和文件扩展名(即:.jpg .gif .txt等)。 “ fileparse()”是File :: Basename模块的功能:

my ($filename,undef,$ext) = fileparse($file,qr{\..*});
如果浏览器发送了诸如“ c:\ windows \我的文档\青蛙图片\大青蛙!!!。gif”之类的信息,我们最终只会得到“大青蛙!!” 和“ .gif”。

接下来的几行验证并在必要时更改文件名,以确保其符合我们的字符列表:


# append extension to filename
$filename .= $ext; 
# convert spaces to underscores "_"
$filename =~ tr/ /_/; 
现在“ big frog !!!。gif”将是“ big_frog !!!。gif”。

# remove illegal characters
$filename =~ s/[^$filename_characters]//g; 
现在$ filename将等于“ big_frog.gif”。 现在是我们经过验证的文件名。

接下来的几行将允许您的脚本通过“取消保留”文件名来使用文件名在服务器上存储数据。 这是-T开关在图片中出现的位置。 允许用户输入用作文件名被认为是不安全的! 我不会详细介绍。 可以说,perl程序假定您(程序员)知道您在做什么,并且不会向您抛出错误,并且会中止脚本以允许以不安全的方式使用不安全的输入。


# satisfy taint checking
if ($filename =~ /^([$filename_characters]+)$/) {
   $filename = $1;
} 
如果由于某种原因文件名不满足以上条件(并且总是如此),则“ else”条件将向“ error()”子例程发送一条错误消息,警告用户错误。

else{
   error("The filename is not valid. Filenames can only contain these characters: $filename_characters")
} 
下一个“除非”条件会对电子邮件地址进行非常粗略的验证。 为了可靠地验证电子邮件地址,我建议使用Email :: Valid模块。 我没有在脚本中包含它,因为它不是核心模块。

unless ($email_address eq 'Annonymous' or ($email_address =~ /^[\w@.-]+$/ && length $email_address < 250)) {
   error("The email address appears invalid or contains too many characters. Limit is 250 characters.")
}     
上载档案

如果脚本到此为止,则假定一切都很好,现在将文件上传到目标目录,并将其存储在文件名($ filename)下。

“ $ query-> upload()”是将CGI格式的文件字段名称转换为文件句柄的函数:<$ upload_filehandle>。

my $upload_filehandle = $query->upload("photo");
在这里,我们使用文件名在$ upload_dir中打开一个新文件。
open (UPLOADFILE, ">$upload_dir/$filename") or error("Can't open/create \"$upload_dir/$filename\": $!");
此行告诉perl在文件句柄上使用二进制模式:
binmode UPLOADFILE;
“ while”循环将用户正在上传的文件读入我们上面打开的文件中。

while ( <$upload_filehandle> ) {
   print UPLOADFILE;
} 
现在关闭文件:
close UPLOADFILE;
打印“谢谢”消息以提醒用户一切顺利,并显示图像和电子邮件地址。

我们的“管家” $ query使用各种命令为我们处理所有HTML代码打印工作。


print $query->header(),
      $query->start_html(-title=>'Upload Successful'),
      $query->p('Thanks for uploading your photo!'),
      $query->p("Your email address: $email_address"),
      $query->p("Your photo $filename:"),
      $query->img({src=>"../uploads/$filename",alt=>''}),
      $query->end_html; 
“ error()”子例程

最后但并非最不重要的是我们唯一的私有子例程。 它只是打印从脚本发送给它的错误消息。 再次,$ query为我们处理HTML代码打印。 子例程的最后一行exit(0)告诉perl在打印错误消息后结束脚本。 如果不包含exit()函数,perl将继续尝试处理脚本的其余部分。


sub error {
   my $error = shift;
   print $query->header(),
         $query->start_html(-title=>'Error'),
         $error,
         $query->end_html;
   exit(0);
} 
评论

如上所述,CGI编程的第一条规则是:永远不要信任用户输入。 CGI脚本不应允许用户发送脚本不期望的数据或以不安全的方式处理数据。 CGI安全性不在本文讨论范围之内,但是“资源”部分中有在线资源,您可以阅读以获取更多详细信息。

使用CGI模块上传文件非常容易。 确实,一旦您熟悉了范围广泛的CGI模块所提供的许多方法/功能,这将非常容易。 只需对我在本文中编写的代码进行少量更改,您就可以允许用户同时上传多个文件,并且还包含许多其他CGI表单数据。 CGI模块是现有的更大的perl模块之一,文档虽然很丰富,但仍会使新手perl程序员感到困惑。

我发布的脚本可以在生产环境中使用,但是请记住,电子邮件地址字段未正确验证。 如前所述,当您需要验证电子邮件地址时,请使用Email :: Valid模块。 您可能需要安装它,但这是另一篇文章的主题。

凯文(又名KevinADC)

资源资源

网站:

Perldoc网站所有在线的perl文档。 搜索CPAN综合Perl存档网络。 巨大的Perl模块存储库

和更多。

CGI安全性CGI安全性入门。

Perl语法:

严格严格的实用说明文档(在perldoc上)。 Warnings警告Pragma文档(在perldoc上)。

核心模块:

CGI CGI模块文档(在perldoc上)。 CGI :: Carp CGI :: Carp模块文档(在perldoc上)。 File :: Basename File :: Basename模块文档(在perldoc上)。

其他模块:

Email :: Valid Email :: Valid模块文档(在cpan上)。

本文受《

创用CC许可完整的脚本

#!/usr/bin/perl -T 
use strict;
use warnings;
use CGI;
use CGI::Carp qw/fatalsToBrowser/;
use File::Basename; 
$CGI::POST_MAX = 1024 * 5000; #adjust as needed (1024 * 5000 = 5MB)
$CGI::DISABLE_UPLOADS = 0; #1 disables uploads, 0 enables uploads 
my $query = CGI->new; 
unless ($CGI::VERSION >= 2.47) { 
   error('Your version of CGI.pm is too old. You must have verison 2.47 or higher to use this script.')
} 
my $upload_dir = '/home/mywebsite/htdocs/upload'; 
# a list of valid characters that can be in filenames
my $filename_characters = 'a-zA-Z0-9_.-'; 
my $file = $query->param("photo") or error('No file selected for upload.') ;
my $email_address = $query->param("email") || 'Annonymous'; 
# get the filename and the file extension
# this could be used to filter out unwanted filetypes
# see the File::Basename documentation for details
my ($filename,undef,$ext) = fileparse($file,qr{\..*}); 
# append extension to filename
$filename .= $ext; 
# convert spaces to underscores "_"
$filename =~ tr/ /_/; 
# remove illegal characters
$filename =~ s/[^$filename_characters]//g; 
# satisfy taint checking
if ($filename =~ /^([$filename_characters]+)$/) {
   $filename = $1;
}
else{
   error("The filename is not valid. Filenames can only contain these characters: $filename_characters")
} 
# this is very crude but validating an email address is not an easy task
# and is beyond the scope of this article. To validate an email
# address properly use the Emaill::Valid module. I do not include
# it here because it is not a core module.
unless ($email_address =~ /^[\w@.-]+$/ && length $email_address < 250) {
   error("The email address appears invalid or contains too many characters. Limit is 250 characters.")
}     
my $upload_filehandle = $query->upload("photo"); 
open (UPLOADFILE, ">$upload_dir/$filename") or error($!);
binmode UPLOADFILE;
while ( <$upload_filehandle> ) {
   print UPLOADFILE;
}
close UPLOADFILE; 
print $query->header(),
      $query->start_html(-title=>'Upload Successful'),
      $query->p('Thanks for uploading your photo!'),
      $query->p("Your email address: $email_address"),
      $query->p("Your photo $filename:"),
      $query->img({src=>"../uploads/$filename",alt=>''}),
      $query->end_html;  
sub error {
   print $query->header(),
         $query->start_html(-title=>'Error'),
         shift,
         $query->end_html;
   exit(0);
} 
本文受知识共享许可保护。
附加的文件
档案类型:txt upload.txt (2.4 KB,1871次观看)

From: https://bytes.com/topic/perl/insights/672398-how-upload-files-using-cgi-pm-module-perl

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值