第四步:编写代码
为了节省时间,我们可以使用基本的Perl 脚本模板 ,把迷你邮件程序这篇教程里使用一些例程剪贴、粘贴到新程序里。
Perl脚本模板
#!/usr/local/bin/perl # ---------------------------------------------------------------------------- # Program Name v1.0 # Copyright (C) 1998 Dave Edis, All Rights Reserved # http://www.edisdigital.com/ # ---------------------------------------------------------------------------- $SIG = $SIG = &HTML_Error; # 显示错误信息 # 查找当前cgidir目录的路径 if (=~m#^(.*)#){ $cgidir = ""; } # 在win/dos平台下,目录是C:dir elsif (=~m#^(.*)/# ){ $cgidir = ""; } # 在Unix平台下,目录是 /usr/bin/ else {`pwd` =~ /(.*)/; $cgidir = ""; } # 或者使用 `pwd` 作为 cgidir目录 $cgiurl = $ENV; # 脚本的web 路径 $filelock = "$cgidir/filelock"; # 文件锁定目录 $|++; # 不缓冲输出 ### 数据文件 $datafile = "$cgidir/file.dat"; ### 变量 $var = "value"; require "$cgidir/edis-lib.cgi"; # 装入 Edis 库例程 # ---------------------------------------------------------------------------- # 主程序 : 测试条件,给出命令 # ---------------------------------------------------------------------------- print "Content-type: text/html "; # 输出内容头信息 %in = &ReadForm; # 读取 CGI 表单输入 if ($in) { ⋐ } # elsif ($in) { ⋐ } # else { ⋐ } # 缺省动作 exit; # ---------------------------------------------------------------------------- # 子程序 : 子例程说明 # ---------------------------------------------------------------------------- sub Sub { } # ---------------------------------------------------------------------------- # HTML_Error : 显示HTML出错信息并退出 # ---------------------------------------------------------------------------- sub HTML_Error { print "Content-type: text/html "; &FileUnlock($filelock); # 文件解除锁定 print "@_"; exit; } # ---------------------------------------------------------------------------- # Programming by Dave Edis
新的子例程
要加入的新的子例程是:
这两个例程由cookie例程调用,确保在cookie里的特殊字符-比如等号,逗号等-不会被错误地解释成cookie数据的分隔符。
最后,我们要建立一个“登录”例程,用来检查口令;还要建立一个“退出登录”例程,在用户退出应用程序时调用退出例程来清除cookie口令。这样,用户要想再次打开应用程序,就需要再次输入口令。
这里是完整的库文件。
#!/usr/local/bin/perl # ---------------------------------------------------------------------------- # pass-lib.cgi v1.0 - Password Protection Perl Library # Copyright (C) 1998 Dave Edis, All Rights Reserved # http://www.edisdigital.com/ # ---------------------------------------------------------------------------- package Passlib; # 查找当前目录路路径 if (=~m#^(.*)#){ $cgidir = ""; } # 在win/dos平台下,cgidir目录在C:dir elsif (=~m#^(.*)/# ){ $cgidir = ""; } # 在unix平台下,cgidir目录在 /usr/bin/ else {`pwd` =~ /(.*)/; $cgidir = ""; } # 或者使用unix 的`pwd` 作为 cgidir目录 $cgiurl = $ENV; # 脚本的web路径 ### 用途 # require "$cgidir/pass-lib.cgi"; # 装入口令库例程 # &Passlib::Login("magic"); # 检查登录口令 # &Passlib::Logoff; # 清空口令cookie # ---------------------------------------------------------------------------- # 主程序:测试条件,给出命令 # ---------------------------------------------------------------------------- my(%in) = &ReadForm; # 读取表单数据 my(%ck) = &ReadCookie; # 读取Cookie数据 # ---------------------------------------------------------------------------- # Login : 检测用户是否拥有正确的登录口令 # 用法 : &Login("password"); # ---------------------------------------------------------------------------- sub Login { my($pw) = $_[0]; # 设置口令值 unless ($pw) { return; } # 如果没有口令,返回 ### 登录表单子例和 ### 这些例程检测用户在登录页输入的口令是否正确 if ($in && $in eq $pw) { # 输入的口令正确 &SetCookie("passlib_pw","$in"); # 设置口令cookie return; # 继续执行程序 } elsif ($in && $in ne $pw) { # 输入的口令不正确 print "Content-type: text/html "; # 输出内容头信息 print &Template("$cgidir/_passlib_invalid.html"); # 输出无效登录页 exit; # 退出 } ### COOKIE 子例程 ### 这些例程检测在用户口令cookie里保存的口令是否正确 elsif ($ck && $ck eq $pw) { # cookie口令正确 return; # 继续执行程序 } else { # cookie 口令正确或者不存在 print "Content-type: text/html "; # 输出内容头信息 print &Template("$cgidir/_passlib_login.html"); # 输出登录页 exit; # 退出 } }
# ---------------------------------------------------------------------------- # Logoff : 清除保存在用户计算机上的口令cookie # 用法: &Logoff; # ---------------------------------------------------------------------------- sub Logoff { &SetCookie("passlib_pw",""); # 清空口令cookie } # ------------------------------------------------------------------------ # ReadForm : 解析由表单GET 或POST来的输入数据,返回表单字段名、字段值的混合对 # # 用法 : %in = &ReadForm; # ------------------------------------------------------------------------ sub ReadForm { my($name,$value,$pair,@pairs,$buffer,%hash); # 把变量本地化 # 把 GET 或 POST 表单读入缓冲变量 $buffer if ($ENV eq 'POST') { read(STDIN, $buffer, $ENV); } elsif ($ENV eq 'GET') { $buffer = $ENV; } @pairs = split(/&/, $buffer); # 分解字段名/字段值组合 foreach $pair (@pairs) { # foreach 循环把组合 ($name, $value) = split(/=/, $pair); # 分触到到字段名变量 $name 和字段值变量 $value $value =~ tr/+/ /; # 用 " "替换"+" $value =~ s/%([A-F0-9])/pack("C", hex())/egi; # 用字符代码%hex 16进制值 $hash = $value; } ### 把图片形式的提交按钮表单名称($var.x & $var.y) 转回正常形式($var) foreach (keys %hash) { if (/^(.*)(.x|.y)$/) { $in{} = "true"; }} return %hash; } # ------------------------------------------------------------------------ # Template : 打开模板文件,翻译变量,返回实际内容 # # 用法 : print &Template("$cgidir/filename.html"); # ------------------------------------------------------------------------ sub Template { local(*FILE); # 文件句柄 local($file); # 文件路径 local($HTML); # HTML 数据 $file = $_[0] || die "Template : No template file specified "; open(FILE, ") { $HTML .= $_; } close(FILE); $HTML =~ s/$(w+)/${}/g; return $HTML; }
# ---------------------------------------------------------------------------- # Cookie : 设置/读取浏览器cookies的Perl例程。 # : Cookies 的尺寸最大为4K,每个主机最多只能发送20个cookie。 # # 用法 : &SetCookie("name","value"); # : %cookie = &ReadCookie; # ---------------------------------------------------------------------------- sub SetCookie { my($cookie_info); my($name,$value,$exp,$path,$domain,$secure) = @_; # $name - cookie名称 (比如: username) # $value - cookie 值 (比如: "joe user") # $exp –到期日期,在指定日期cookie将被删除。格式为:Wdy, DD-Mon-YYYY HH:MM:SS GMT # $path – 只有访问这个路径时,才发送Cookie (比如: /); # $domain – 只有访问这个域 时,才发送Cookie (比如: .edis.org) # $secure – 只有使用安全的https连接时,才发送Cookie unless (defined $name) { die("SetCookie : Cookie name must be specified "); } if ($exp && $exp !~ /^[A-Z], dd-[A-Z]-d dd:dd:dd GMT$/i) { die("SetCookie : Exp Dat format isn't: Wdy, DD-Mon-YYYY HH:MM:SS GMT "); } if ($name) { $name = &URL_Encode($name); } if ($value) { $value = &URL_Encode($value); } if ($exp) { $cookie_info .= "expires=$exp; "; } if ($path) { $cookie_info .= "path=$path; "; } if ($domain) { $cookie_info .= "domain=$domain; "; } if ($secure) { $cookie_info .= "secure; "; } print "Set-Cookie: $name=$value; $cookie_info "; }
sub ReadCookie { my($cookie,$name,$value,%jar); foreach $cookie (split(/; /,$ENV)) { # 对于每个发送的cookie ($name,$value) = split(/=/,$cookie); # 都分解到字段名/字段值组合里 foreach($name,$value) { $_ = &URL_Decode($_); } # URL 解码字符串 $jar=$value; # 并放在%jar 组合里 } return %jar; # 返回 %jar 组合 }
# ---------------------------------------------------------------------------- # URL : URL 编码/解码的Perl例程。 URL 编码是一个通用的编码方案 # 凡是A-Za-z0-9+*.@_- 以外的字符都用三个字符代替,格式是 # 一个"%" 号,后面跟着两个16进制数。 # # 用法 : $URL_encoded = &URL_Encode("$plaintext"); # : $plaintext = &URL_Decode("$URL_encoded"); # ---------------------------------------------------------------------------- sub URL_Encode { my($text) = $_[0]; # 要进行URL编码的文本 $text =~ tr/ /+/; # 用"+"代替 " " $text =~ s/[^A-Za-z0-9+*.@_-]/ # 用%号接16进制的形式 uc sprintf("%%%02x",ord($&))/egx; # 替换不常用字符 return $text; # 返回进行了URL编码处理的文本 } sub URL_Decode { my($text) = $_[0]; # 要进行URL解的URL编码文本 $text =~ tr/+/ /; # 用"" 代替 "+ " $text =~ s/%([A-F0-9])/pack("C", hex())/egi; # 用解码后的普通文本代替%号接16进制的字符 return $text; # 返回解码后的普通文本 } 1; # 必须返回正数值 # ---------------------------------------------------------------------------- # Programming by Dave Edis
把所有部件装配起来
完成以上步骤之后,全部剩下要做的是:把口令保护功能加到程序里。下面是一个简单的脚本“Hello World.”,可以演示需要做的工作:
<xmp> #!/usr/local/bin/perl print "Content-type: text/html "; print "Hello World"; </xmp>
要把口令保护加到这个程序里,只要增加两行代码。这两行代码需要插到所有打印内容头信息的语句之前,否则它们会被打印两次之后才结束。
<xmp> #!/usr/local/bin/perl require "pass-lib.pl"; &Passlib::Login("magic"); print "Content-type: text/html "; print "Hello World"; </xmp>
这个程序的口令是“magic.”
我们提供了所有相关文件的ZIP压缩包,请单击这里下载。