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

Hi Monks, I am very new to CGI scripting and I am using ActivePerl 5.8.8 and running Apache 2.2.8 on a Windows XP machine. I am trying to figure out how to move the user to a new page on successful login (checking against a Sybase database which is working fine). I am using the print redirect() function and it simply prints the location on the same page (loginpage.cgi), instead of actually moving to the new page (librarian.cgi). This is my code (The relevant line is print $q->redirect("http://localhost/cgi-bin/librarian.cgi");):
#!/usr/bin/perl -w use CGI qw(:standard); use CGI::Carp qw/fatalsToBrowser warningsToBrowser/; #fatalsToBrowser(1); use DBI; use strict; use Data::Dump qw(dump); my $q = CGI->new(); print $q->header(-cache_control=>"no-cache, no-store, must-revalidate" +); print <<BodyHTML; <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http:/ +/ www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd "> <html lang="en" xml:lang="en" xmlns=" http://www.w3.org/1999/xhtml"> <head> <title>Login Page</title> </head> <body> <form name = "login" action = "loginpage.cgi " method = "GET"> <table> <tr> <td> User Name<br />(25 characters or less) </td> <td> Password<br />(8 - 15 alphanumeric characters) </td> </tr> <tr> <td><input type = "text" name = "UserName" id = "UserName" size = "25" maxlength = "25" tabindex = "0" /> </td> <td><input type = "text" name = "Password" id = "Password" size = "15" maxlength = "15" tabindex = "1" /> </tr> <tr> <td> <input type = "submit" value = "Login" tabindex = "2" /> </td> </tr> <tr> </tr> </table> </form> BodyHTML my ($DBserver, $DBdatabase, $DBuser, $DBpassword) = ('LOCALHOST','test +db','kbuttler','gghy'); my $dbh = DBI->connect("DBI:Sybase:server=$DBserver;database=$DBdataba +se",$DBuser,$DBpassword) or die "Can't connect to Sybase database: $DBI::errstr\n"; my $usernamequery = param("UserName"); my $username_q = $dbh->quote($usernamequery); my $passwordquery = (param("Password")); my $password_q = $dbh->quote($passwordquery); my $sth1 = $dbh->prepare("select username from logintable where userna +me = $username_q "); $sth1->execute(); my $row1 = $sth1->fetchrow_arrayref(); if ( $row1->[0] eq $usernamequery ) { my $sth2 = $dbh->prepare("select password from logintable where pa +ssword = $password_q "); $sth2->execute(); my $row2 = $sth2->fetchrow_arrayref(); $sth2->finish(); if ( $row2->[0] eq $passwordquery ) { print $q->redirect("http://localhost/cgi-bin/librarian.c +gi"); } else { &dienice(qq(The password is invalid.)); exit; } } else { &dienice(qq(Username does not exist.)); exit; } $sth1->finish(); $dbh->disconnect; print end_html; sub dienice { my ($msg) = @_; print "<h1>$msg</h1>"; exit; }
Thanks in advance for any help. -Ken

Replies are listed 'Best First'.
Re: how to move to new page on successful login
by pc88mxer (Vicar) on Feb 25, 2008 at 20:38 UTC
    The redirect has to go in the HTTP header, so you would use it instead of print $q->header(...). This means that you have to defer printing the header (or redirection) until after you've checked the user's login info.
      Hi pcc88mxer, Thanks a lot for the reply. I do not quite understand how to defer printing the header after I have checked the user info. Could you kindly elaborate? Without the header at the beginning (before the HTML block), the server is throwing an error and the page is not being created. How do I make the redirect go to HTTP header (so that I can use it instead of q->header(...))? I am sorry.. but I am really new to all this. Thanks and regards, Ken
        You'll either do the redirect or you print the header and emit an HTML page:

        use CGI; ... $q = new CGI; my $login_ok = check_login($q); if ($login_ok) { $q->redirect(...); } else { $q->header(...); # emit html page }

        Move the code that checks for the user's credentials before the code that prints anything.

Re: how to move to new page on successful login
by CountZero (Bishop) on Feb 25, 2008 at 20:44 UTC
    I see some serious problems with your CGI-script.

    What stops a user from directly going to http://localhost/cgi-bin/librarian.cgi?

    You check for a valid user + password combination in your script and once you reach the other pages, how do these scripts know the user is valid and allowed to reach these pages?

    Usually this is done through session-management and cookies and many modules exist that already implement this. Have a look at CGI::Session in that respect.

    And while your are looking at modules, CGI::Auth or CGI::Session::Auth may just do what you are trying to achieve!

    Perhaps you are trying to re-invent a web-framework and then modules such as Catalyst or CGI::Application are what you are looking for?

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Hi Countzero, Your points are very valid and I understand that I need something far more robust to actually restrict access to librarian.cgi. However, I have just started learning CGI/DBI and I want to figure out how to do a simple redirect, which somehow I cannot accomplish even after 6 hours of googling. Thanks and regards, Ken
Re: how to move to new page on successful login
by derby (Abbot) on Feb 25, 2008 at 20:36 UTC

    That's because you've all ready printed html.

    Try something like this:

    my $q = CGI->new(); if( $q->param() ) { # call validate routine } else { # call display login routine }

    -derby
Re: how to move to new page on successful login
by almut (Canon) on Feb 25, 2008 at 23:41 UTC
    <form name = "login" action = "loginpage.cgi " method = "GET">

    Just another side remark.  It's generally better to use the POST method to submit forms that are transmitting sensitive information like passwords etc.  With POST, the info will not be part of the URL (such as loginpage.cgi?username=ken&password=secret&...), as it's the case when using GET, thus reducing the likelihood that passwords will end up in logfiles of webservers, proxies, etc... (yes, I've noticed you're using cache_control, but those directives are more of an advisory nature, ultimately).

    It's bad enough already that (with HTTP) the entire traffic goes over the wire in the clear anyway, but you certainly don't want passwords to be stored persistently in logfiles... for the unsuspecting admin to stumble across inadvertently :) — remember that people often use the same password in multiple places, so knowing one might compromise more than this immediate web resource.

Re: how to move to new page on successful login
by zentara (Cardinal) on Feb 25, 2008 at 20:42 UTC
    I don't mess with cgi much, but here is something to try, a WAG :-)
    #notice single quotes print $q->redirect(-uri => 'http://localhost/cgi-bin/librarian.cgi');

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      Thanks zentara but that suggestion did not make a difference. Regards, Ken
        Have you tried the print Location trick? Although I think it falls into the same boat as the header discussion by others.
        #!/usr/bin/perl $url1 = 'http://zentara.zentara.net'; $url2 = 'http://zentara.zentara.net/~zentara'; if ($ENV{'HTTP_USER_AGENT'} =~ /Mozilla/ and not $ENV{'HTTP_USER_AGENT'} =~ /compatible/i ) { print "Location: $url1\n\n"; } else { print "Location: $url2\n\n"; }

        I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: how to move to new page on successful login
by scorpio17 (Canon) on Feb 26, 2008 at 14:35 UTC
    Some time ago I started a tutorial on how to use CGI::Application to create a simple login page. You might like to use it as a starting point. It never made it past the "request for comments" stage, but you can still find it here. Good luck!