#!/usr/bin/perl use CGI; use DBI; use Digest::MD5 qw(md5 md5_hex md5_base64); $DB = "dbi:mysql:demoOne:silo.cs.indiana.edu:port=16248"; $username = "dgerman"; $password = "sp00n"; $DB_TABLE = "aaron"; $SECRET = "something secret"; $EXPIRE = 30 * 24 * 3600; # one month $MAX_TRIES = 10; $ID_LENGTH = 8; $q = new CGI; # Open the database -------------------------------------------------------- $DBH = DBI->connect($DB, $username, $password, {PrintError => 0}) || die "Couldn't open database: ", $DBI::errstr; # get the current session ID, or make one ---------------------------------- my ($session_id, $note) = &get_session_id(); # retrieve the state ------------------------------------------------------- my $state = &get_state($session_id) unless $q->param('clear'); $message = $state->{'message'}; $n1 = $state->{'n1'}; $n2 = $state->{'n2'}; $n3 = $state->{'n3'}; $user = $state->{'user'}; $comp = $state->{'comp'}; $turn = $state->{'turn'}; $one = $q->param('one'); $two = $q->param('two'); $three = $q->param('three'); $turn = ""; if ($one ne "on") { $n1 = int(rand(100)) - 50; } if ($two ne "on") { $n2 = int(rand(100)) - 50; } if ($three ne "on") { $n3 = int(rand(100)) - 50; } $options = ""; $c1 = int(rand(100)) - 50; $c2 = int(rand(100)) - 50; $c3 = int(rand(100)) - 50; $message = "Computer draws ($c1, $c2, $c3)."; $val = 0; if ($c1 > $n1) { $val += 1; } elsif ($c1 < $n1) { $val -= 1; } if ($c2 > $n2) { $val += 1; } elsif ($c2 < $n2) { $val -= 1; } if ($c3 > $n3) { $val += 1; } elsif ($c3 < $n3) { $val -= 1; } if ($val > 0) { $message .= " Computer wins."; $comp += 1; } elsif ($val < 0) { $message .= " You win."; $user += 1; } else { $message .= " This is a tie. "; $user += 1; $comp += 1; } $message .= " Score now: $user - $comp. "; $state->{'message'} = $message; $state->{'n1'} = $n1; $state->{'n2'} = $n2; $state->{'n3'} = $n3; $state->{'user'} = $user; $state->{'comp'} = $comp; $state->{'turn'} = $turn; # save the modified state -------------------------------------------------- &save_state($state, $session_id); # start the page ----------------------------------------------------------- print $q->header, $q->start_html(-title => 'Database Sessions with URL Rewriting', -bgcolor => 'white'); print qq{
Your draw:

$n1 $n2 $n3

$message

Press when you're ready to move on.

}; print $q->end_html; $DBH->disconnect; # save the state in the database ------------------------------save_state--- sub save_state { my ($state, $id) = @_; my $sth = $DBH->prepare(<errstr; UPDATE $DB_TABLE SET message=?,n1=?,n2=?,n3=?,user=?,comp=?,turn=? WHERE session_id='$id' END $sth->execute(@{$state}{qw(message n1 n2 n3 user comp turn)}) || die "execute: ", $DBH->errstr; $sth->finish; } # get the state from the database ------------------------------get_state--- sub get_state { my $id = shift; my $query = "SELECT * FROM $DB_TABLE WHERE session_id = '$id'"; my $sth = $DBH->prepare($query) || die "Prepare: ", $DBH->errstr; $sth->execute || die "Execute: ", $sth->errstr; my $state = $sth->fetchrow_hashref; $sth->finish; return $state; } # retrieve the session ID from the path info. if it's -----get_session_id--- # not already there, add it to the path info (more or less) with a redirect sub get_session_id { my (@result); &expire_old_sessions(); my ($id) = $q->path_info() =~ m:^/([a-h0-9]{$ID_LENGTH}):o; return @result if $id and @result = &check_id($id); # if we get here, there's not already an ID in the path info my $session_id = &generate_id(); die "Couldn't make a new session id" unless $session_id; print $q->redirect($q->script_name() . "/$session_id"); exit 0; } # find a new unique ID and insert it into the database -------generate_id--- sub generate_id { # create a new session id my $tries = 0; my $id = &hash($SECRET . rand()); while ($tries++ < $MAX_TRIES) { last if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); $id = &hash($id); } return undef if $tries >= $MAX_TRIES; # we failed return $id; } # check to see that an old ID is valid --------------------------check_id--- sub check_id { my $id = shift; return ($id, '') if $DBH->do("SELECT 1 FROM $DB_TABLE WHERE session_id = '$id'") > 0; return ($id, 'The record of your game may have expired. Restarting.') if $DBH->do("INSERT INTO $DB_TABLE (session_id) VALUES ('$id')"); return (); } # generate a hash value ---------------------------------------------hash--- sub hash { my $value = shift; return substr(md5_hex($value), 0, $ID_LENGTH); } sub expire_old_sessions { # --------------------------expire_old_sessions--- $DBH->do(< $EXPIRE END }