2012-02-12 39 views
1

我一直在研究一个cgi文件,该文件将检查用户是否想要注册其凭据时是否已经使用了用户名。如果使用用户名,它应该通知他们,如果不是,则将其凭据保存到原始平面文件。我在比较foreach语句中赋予值的变量时遇到问题。如果用户输入的名称与已存储的名称相同,我告诉foreach将用户名分配给变量。我有它适当地分配变量,但后话我想告诉它在foreach之外再次比较这些变量,所以操作只能进行一次。这里是我当前的代码比较在foreach语句中分配的变量的问题

#!/usr/bin/perl 
use warnings; 
use strict; 
use CGI qw(:standard); 
use CGI::Carp qw/fatalsToBrowser warningsToBrowser/; 
use Digest::MD5 qw(md5 md5_hex md5_base64); 

#telling what variables are still to be used as global 
our ($username, ,$user, $nametaken); 

#assigning some local variables 
my $username = param("username"); 
my $password = param("password"); 
my $hashpass = md5_hex($password); 

print header, start_html(); 

#creating an array from the flatfile that usernames and passwords are stored 
my @users = do { open my $fh, "<", "password.txt" or die $!; map { chomp; split /:/ } <$fh> }; 

#comparing the values in the array to the username entered 
foreach my $user (@users) { 
if ($user eq $username) { 
    #printing here to test if it is comparing correctly which it is 
    print p("$user\n"); 
    #assigning the $user value to $nametaken so it can be compared to later 
    my $nametaken = $user; 
    #printing here to test if the variable was correctly assigned, which it is 
    print p("$nametaken\n"); 
    } 
} 

#printing here to test if the variable was correctly assigned, which it is not printing 
#so the foreach must be causing some king of issue for this variable after it is done and I don't know what that is 
print p("$nametaken\n"); 

#Here is where I am trying to check if the username already exists and then save the user credentials if it does not 
if ($nametaken eq $username) { 
print p("Username already taken, Try again"); 
} 

#As of now the else statement is running everytime and saving new user credentials even if a username is already taken 
else { 
open my $fh, ">>", "password.txt" or die $!; 
print $fh "$username:$hashpass\n"; 
print p("Your account has been created sucessfully"); 
close $fh; 

} 
print end_html(); 
+0

啊,我们的朋友,如果反模式。 – hobbs 2012-02-12 21:21:05

+0

为什么使用'qw(...)'和'qw /.../',只需选择一个。我实际上推荐使用'qw'...''或'qw“...”'来在StackOverflow上使用,因为它更好地突出显示。 – 2012-02-14 06:09:47

回答

4

您声明一个新的内部你foreach循环的词法范围的变量$nametaken - 或者说,if {}块内:my $nametaken = $user;

,可能与$nametaken变量共享相同的名称你在外面,但它是一个完全不同的变量,其范围为if块 - 一旦您退出if,该变量就完全被遗忘了。无论你分配给它什么价值都会丢失。

你可以在这里看到更多的细节有关词法变量:

http://perldoc.perl.org/perlsub.html#Private-Variables-via-my%28%29


从战术解决您的问题,您只需从内取出my声明,如果:$nametaken=$user;

为了正确地做到这一点,以Perl的方式,你应该重新思考你对问题的方法。您可以使用foreach循环来检测列表中是否有值,但它绝对不是最好的(可读性明智,有时甚至是性能明智的)Perl技术。更惯用的方法是使用哈希查找:

my %users = map { ($_ => 1) } @users; # Create a hash with users being keys 
if ($users{$username}) { 
    print "$username already taken!\n"; 
} 
+0

太棒了,我改变了我的代码并实现了哈希查找。工作完美。谢谢!你能解释一下哈希设置吗?当你写地图{($ _ => 1)}时,这是什么意思? – Jared 2012-02-12 23:02:48

+0

@Salmonerd - 我可以:)你可能想要使它成为一个单独的问题 - 这是一个有点独特的主题,可能对其他用户有用 – DVK 2012-02-12 23:10:06

+0

@ DVK-也许你可以看看我最新的问题,关于尝试使用散列查找用于登录验证。我真的很想更好地理解他们,我想要对他们做的事情真的超过了我的经验水平。感谢您的帮助。 – Jared 2012-02-13 00:59:04

2

为什么$nametaken不具有价值外foreach环是因为它已被词法范围的原因而只内foreach定义。


总是有这样做的方法不止一种:

my ($nametaken) = grep { /$username/ } @users; 

if ($nametaken) { ... } else { ... } 

或者干脆:

if (grep { /$username/ } @users) { ... } else { ... } 

这是通常当你在Perl较少的临时变量减少噪音。

+0

他已经在循环外有'我们的$ nametaken',所以这仍然会给出重复的声明。 – cjm 2012-02-12 17:36:46

+0

@cjm:Ack。没有注意到。删除了不相关的示例。 – Zaid 2012-02-12 17:41:44

3
my $nametaken = $user; 

创建一个名为$nametaken一个变量无关,与你的外循环宣布$nametaken

+0

是的,这是问题,对于Perl和变量的范围以及如何声明它们仍然很新颖。感谢您指出显而易见的事情,我想我已经把自己的脑袋缠绕起来了一点。 – Jared 2012-02-12 22:44:21