andrew2325 has asked for the wisdom of the Perl Monks concerning the following question:

Okay, I figure the easiest way to get help would be to post the entire script here. it's a basic log in/log out script to replace time card systems. it's gpled. i dunno what in the world we have done wrong. this our first attempt at a perl script. i get errors when i try to log in or out, and it doesn't add users to the hash. also, i need to know how to encrypt the passwords.
# AGTS-CLI(Andrew's GTK Time System-Command Line version) # Copyright (C) 2008 Andrew Harris # # This program is free software: you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, email andrew2325@gmail.com! # Contributors: Kelly Royal <netdaemon862@gmail.com> #!/usr/bin/perl while (1) { sub verify { my $username = shift; my %logins = shift; if (exists $logins{$username}) { login($username, %logins); } else { print "$username does not exist in our database.\n"; } } sub login { my %logins = shift; print "Enter your password: "; chomp(my $pass = <STDIN>); if ($pass <=> $logins{$username}) { greeting($username); } else { print "Incorrect password!\n"; } } sub greeting { my $time = localtime; my $username = shift; print "Welcome $username.\n"; print "Current time is $time\n\n\n"; } sub admin { my %logins = shift; print "Administrative Tools\n"; print "1. Add user\n"; print "2. Remove user\n"; print "Enter selection: "; chomp(my $selection = <STDIN>); if ($selection == "1") { print "Enter new user name: "; chomp(my $newname = <STDIN>); print "Enter password for $newname: "; chomp(my $newpass = <STDIN>); $logins{$newname} = $newpass; print "User added.\n"; } } print "Welcome, Main Menu\n"; print "1. Log in\n"; print "2. Log out\n"; print "3. Administration\n"; print "Enter selection: "; my $selection = <STDIN>; my %logins = ("kroyal" => "5678", "aharris" => "1234"); if ($selection == "1") { print "Enter your user name to log in: "; chomp(my $username = <STDIN>); verify($username, %logins); open(MYLOGINFILE, ">>login.txt"); print MYLOGINFILE "$username:$time\n"; close(MYLOGINFILE); } elsif ($selection == "2") { print "Enter your user name to log out: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGOUTFILE, ">>login.txt"); print MYLOGOUTFILE "$username:$time\n"; close(MYLOGOUTFILE); } elsif ($selection == "3") { admin(%logins); } }

Replies are listed 'Best First'.
Re: adding to hash/writing to file errors
by GrandFather (Saint) on May 05, 2008 at 03:37 UTC

    First: use strictures (use strict; use warnings;).

    Second: named subs don't belong inside a while loop (replies to Perl scoping not logical...? may help understand why).

    When you add use strict; you will find the variable $username can't be found. Because you use it in various subs you need to pass it into those subs. You've done that for greeting, but not elsewhere.


    Perl is environmentally friendly - it saves trees
Re: adding to hash/writing to file errors
by apl (Monsignor) on May 05, 2008 at 11:52 UTC
    GrandFather has already moved you in the proper direction, leaving me free to be curious.
    i dunno what in the world we have done wrong.
    What did you do to try to debug your program? Did you use the Perl Debugger? Did you use print statements? Did you try to determine the minimal program that caused the problem?
      Okay, here is the revised version, now i get this error when it is compiling:
      Global symbol "%logins" requires explicit package name at ./maybe.pl line 62. Execution of ./maybe.pl aborted due to compilation errors.
      # AGTS-CLI(Andrew's GTK Time System-Command Line version) # Copyright (C) 2008 Andrew Harris # # This program is free software: you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, email andrew2325@gmail.com! # Contributors: Kelly Royal <netdaemon862@gmail.com> #!/usr/bin/perl use strict; use warnings; my $time = localtime; sub verify { my $username = shift; my %logins = ("aharris" => "1234", "kroyal" => "5678"); if (exists $logins{$username}) { login($username, %logins); } else { print "$username does not exist in our database.\n"; } } sub login { my %logins = shift; my $username = shift; print "Enter your password: "; chomp(my $pass = <STDIN>); if ($pass <=> $logins{$username}) { greeting($username); } else { print "Incorrect password!\n"; } } sub greeting { my $username = shift; print "Welcome $username.\n"; print "Current time is $time\n\n\n"; } sub admin { print "Administrative Tools\n"; print "1. Add user\n"; print "2. Remove user\n"; print "Enter selection: "; chomp(my $selection = <STDIN>); if ($selection == "1") { print "Enter new user name: "; chomp(my $newname = <STDIN>); print "Enter password for $newname: "; chomp(my $newpass = <STDIN>); $logins{$newname} = $newpass; print "User added.\n"; } } while (1) { print "Welcome, Main Menu\n"; print "1. Log in\n"; print "2. Log out\n"; print "3. Administration\n"; print "Enter selection: "; my $selection = <STDIN>; if ($selection == "1") { print "Enter your user name to log in: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGINFILE, ">>login.txt"); print MYLOGINFILE "$username:$time\n"; close(MYLOGINFILE); } elsif ($selection == "2") { print "Enter your user name to log out: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGOUTFILE, ">>login.txt"); print MYLOGOUTFILE "$username:$time\n"; close(MYLOGOUTFILE); } elsif ($selection == "3") { admin; } }

      When I remove use strict; use warnings;, it runs, but it doesn't add the users/passwords to the hash..
        use strict; requires that you declare all variables using my in all scopes. The variable $username is used in your "login" sub, but it is not declared there, nor is it declared as a global variable. Since your call to "login" is:
        login($username, %logins);

        I believe you might want:

        sub login { my $username = shift; my %logins = shift;

        You only declare your $time variable in your "greeting" sub, but you use it in the "while" loop.

        first i had use strict; use warnings; in there, but it wouldn't run the script. just gave a warning about line 83. then i removed it to see if it would work without the debugging.
        Did you consider fixing the bug that caused the warning on line 83?

        use warnings; use strict; aren't debugging aids. They help reveal badly constructed Perl. You debug your program after it compiles cleanly.

Re: adding to hash/writing to file errors
by andrew2325 (Initiate) on May 05, 2008 at 17:09 UTC
    Here are the changes that I have made.
    # AGTS-CLI(Andrew's GTK Time System-Command Line version) # Copyright (C) 2008 Andrew Harris # # This program is free software: you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, email andrew2325@gmail.com! # Contributors: Kelly Royal <netdaemon862@gmail.com> #!/usr/bin/perl use strict; use warnings; my $time = localtime; sub verify { my $username = shift; my %logins = shift; if (exists $logins{$username}) { login($username, %logins); } else { print "$username does not exist in our database.\n"; } } sub login { my %logins = shift; my $username = shift; print "Enter your password: "; chomp(my $pass = <STDIN>); if ($pass <=> $logins{$username}) { greeting($username); } else { print "Incorrect password!\n"; } } sub greeting { my $username = shift; print "Welcome $username.\n"; print "Current time is $time\n\n\n"; } sub admin { my %logins = shift; print "Administrative Tools\n"; print "1. Add user\n"; print "2. Remove user\n"; print "Enter selection: "; chomp(my $selection = <STDIN>); if ($selection == "1") { print "Enter new user name: "; chomp(my $newname = <STDIN>); print "Enter password for $newname: "; chomp(my $newpass = <STDIN>); $logins{$newname} = $newpass; print "User added.\n"; } } while (1) { print "Welcome, Main Menu\n"; print "1. Log in\n"; print "2. Log out\n"; print "3. Administration\n"; print "Enter selection: "; my $selection = <STDIN>; my %logins = ("kroyal" => "5678", "aharris" => "1234"); if ($selection == "1") { print "Enter your user name to log in: "; chomp(my $username = <STDIN>); verify($username, %logins); open(MYLOGINFILE, ">>login.txt"); print MYLOGINFILE "$username:$time\n"; close(MYLOGINFILE); } elsif ($selection == "2") { print "Enter your user name to log out: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGOUTFILE, ">>login.txt"); print MYLOGOUTFILE "$username:$time\n"; close(MYLOGOUTFILE); } elsif ($selection == "3") { admin(%logins); } }

    Now when I run it, only one of the default users work and you can't add users. I get the following errors when logging in:
    Welcome, Main Menu
    1. Log in
    2. Log out
    3. Administration
    Enter selection: 1
    Enter your user name to log in: aharris
    Odd number of elements in hash assignment at ./maybe.pl line 23, <STDIN> line 2.
    Odd number of elements in hash assignment at ./maybe.pl line 33, <STDIN> line 2.
    Enter your password: 1234
    Use of uninitialized value $logins{"aharris"} in numeric comparison (<=>) at ./maybe.pl line 37, <STDIN> line 3.
    Welcome aharris.
    Current time is Mon May 5 11:58:30 2008
Re: adding to hash/writing to file errors
by andrew2325 (Initiate) on May 07, 2008 at 04:03 UTC
    I made the changes as you guys instructed and made some changes of my own, now I encounter an unusual error.
    Welcome, Main Menu
    1. Log in
    2. Log out
    3. Administration
    Enter selection: 3
    Administrative Tools
    1. Add user
    2. Remove user
    Enter selection: 1
    Enter new user name: ggamber
    Enter password for ggamber: 9898
    User added.
    Welcome, Main Menu
    1. Log in
    2. Log out
    3. Administration
    Enter selection: 1
    Enter your user name to log in: ggamber
    Enter your password: 9898
    Use of uninitialized value $username in hash element at ./agts-cli.pl line 39, <STDIN> line 7.
    Use of uninitialized value in string eq at ./agts-cli.pl line 39, <STDIN> line 7.
    Incorrect password!
    New code:
    #!/usr/bin/perl # # AGTS-CLI(Andrew's GTK Time System-Command Line version) # Copyright (C) 2008 Andrew Harris # # This program is free software: you can redistribute it and/or mod +ify # it under the terms of the GNU General Public License as published + by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, email andrew2325@gmail.com! # Contributors: Kelly Royal <netdaemon862@gmail.com> use strict; use warnings; my $time = localtime; my %logins = ("aharris" => "1234", "kroyal" => "5678"); sub verify { my $username = shift; if (exists $logins{$username}) { login($username, %logins); } else { print "$username does not exist in our database.\n"; } } sub login { my %logins; my $username; print "Enter your password: "; chomp(my $pass = <STDIN>); if ($pass eq $logins{$username}) { greeting($username); } else { print "Incorrect password!\n"; } } sub greeting { my $username = shift; print "Welcome $username.\n"; print "Current time is $time\n\n\n"; } sub admin { print "Administrative Tools\n"; print "1. Add user\n"; print "2. Remove user\n"; print "Enter selection: "; chomp(my $selection = <STDIN>); if ($selection == 1) { print "Enter new user name: "; chomp(my $newname = <STDIN>); print "Enter password for $newname: "; chomp(my $newpass = <STDIN>); $logins{$newname} = $newpass; print "User added.\n"; } } while (1) { print "Welcome, Main Menu\n"; print "1. Log in\n"; print "2. Log out\n"; print "3. Administration\n"; print "Enter selection: "; my $selection = <STDIN>; if ($selection == 1) { print "Enter your user name to log in: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGINFILE, ">>login.txt"); print MYLOGINFILE "$username:$time\n"; close(MYLOGINFILE); } elsif ($selection == 2) { print "Enter your user name to log out: "; chomp(my $username = <STDIN>); verify($username); open(MYLOGOUTFILE, ">>login.txt"); print MYLOGOUTFILE "$username:$time\n"; close(MYLOGOUTFILE); } elsif ($selection == 3) { admin; } }