构建一个Perl/CGI投票系统UnLock()方法来刷新I/O并释放变量。(关于这方面的更多信息,请参阅Perl文档中有关MLDBM::Sync模块的内容:man3MLDBM::Sync。)从根本上来说,逻辑流程非常简单,如清单1所示。 |
在确定底层的条件流程之后,剩下的惟一任务就是构建适合以后使用的对象。正如我在前面介绍的那样,可以使用tie'd变量和MLDBM文家锁定来检索和更新所需的哈希数据结构。所使用的对象更像是一些精巧的数据结构,而不像是一些羽翼丰满的对象;在这些对象之间,数据是以某种并行方式处理的:选票也从最初的预选票转换成为最终的正式选票。
换言之,选票清单被用来构建一个DraftBallot,而这个DraftBallot又被用来创建CastBallot和BallotBox类。这样,对于主要的投票CGI程序,耦合性就是最小的。
从另外一方面来说,虽然我通常认为使用一些依赖于外部资源(例如文件)的构造函数不是一个好的实践方法(因为这样可能会引起失败,并导致一些不可预知的状态),但是在这种情况下,以这种方式实现的代码将更易于理解。由于Perl并不依赖于指针,所以没什么理由不利用这种简单性。
允许用户从您的Web服务器上发送电子邮件是一个危险的举动,因为垃圾邮件可以利用您的主机来胡乱发送电子邮件。为了将这种威胁降至最低,脚本通常会检查要发送的电子邮件地址是否是一个可到达的地址。您可以通过修改DraftBallot类中的验证方法voter_is_okay()来加强这种限制,使其在进行验证时参考一个可接受的电子邮件地址。这样可能会要求用户在进行投票之前进行注册。
防止出现重复投票的其他方法包括搜集IP地址或在客户机上设置cookie,但是我不想采用这种方法,因为很多学生可能会在校园中使用共享的公用终端。
在使用SASL认证时,您有两个选择:可以将这个脚本指向一台可以转发使用正确证书的电子邮件的机器,或者使用Perl
很多服务提供商都只允许转发那些来自使用SASL身份验证的客户机的邮件。Net::SMTP_authandAuthen::SASL模块重新编写这个脚本,与外部SMTP服务器直接进行联系。(第二种方法的速度较慢。)
调用$castBallot->dumpHTMLentrys()方法会回显一个详细的信息,指出谁投票给了谁。实际上,我要注释掉这个调用,在选举结束之后使用Linuxat批处理命令来关闭Web服务器。
当服务器关闭之后,您可以注释掉这一部分,并重新启动Web服务器,将其临时设置为
注意,在这个例子下,每个选票都不会被统计两次。在那些确定需要保密的情况中,可以使用一个简短的JavaScript函数来隐藏结果。诚然,有些人可能希望完全采用匿名投票,但是由于俱乐部的选举通常都是通过举手表决的,因此这很难实现安全的投票。
在考虑这种工作流程模式时,我意识到使用基于GET的验证链接以及使用非加密验证链接的必要性,这样可以进行一些实验,读取这些链接,并基于指定的电子邮件地址和一些已知的验证链接来构建一些错误的确认投票。为了防止这种事情的发生,同时为了仍然能够通过非加密链接进行简单的调试,我决定在验证步骤中添加一、两项内容:为每个预选票添加一个惟一的标识符。
这个标识符是基于操作系统中正在执行的脚本的集成标识符(PID)的。为了让预测验证预选票的URL更加困难,我们可以再使用一个随机数。我之所以关心这个问题,是因为会有一些恶意的用户可能会对非常直观的URL模式进行破解,从而试图构建一些虚假的验证选票。这是代码的一部分,它不会直接转换为一个mod_perl版本,因为它要依赖于正在运行的Perl的PID,以及另外一个随机数。如果这个表单是从一个重用的mod_perl实例中生成的,那么在两次调用之间,PID可能并不需要改变。
然后,我又意识到能使这个链接更具迷惑性的方法是使用一个MD5生成的哈希值,从而有效地隐藏所有投票者的信息。这具有双向受益的优点:既可以使它很难被伪造,同时还维护了基于