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

Good morning, fellow monks. I have a question that is more of a design question, one of many to follow this week as I wrap up some more code on my new dynamic website for Plucker. This one concerns a Voting Booth:

I'd like to incoporate the ability to have a voting booth style "slashbox"/"nodelet" on the website. I've written smaller ones before, but this one will be getting substantially more hits, and I'll want to be using GD/jpgraph (or similar technologies) to graph the results.

The interesting question becomes, what is a really good way to make sure the ballots aren't "stuffed" in the voting mechanism. I have seen several ideas in the past, which all have good and bad points:

Has anyone implemented a solution that doesn't suffer from stuffed ballots, race attacks, locking conditions (mysql-based storage would solve the last two), etc.? I've personally used file-level storage of the bits, but never done any voting mechanisms using mysql as a storage mechanism.

Implementing the perl around it is no problem for me, unless it's really unusual structures. Modules in this space? CPAN didn't bring up much.

Here's some sample code from one I wrote about 5 years ago. It suffers from many problems if implemented now:

########################################### # Grab the user's vote and store it in the # appropriate file. If the file does not # exist it will be created on the fly. ########################################### sub record_vote { if ($cookie_state != 1) { $votes_file = "vote/platform/$poll"; open (VOTES, "$votes_file"); while (<VOTES>) { $count1 = $_; } close VOTES; $count1 += 1; open (VOTES, ">$votes_file"); print VOTES $count1; close VOTES; } } ########################################## # Calculate the vote totals ########################################## sub calculate_vote { opendir(DIR, $some_dir) || die "can't opendir $some_dir: $!"; @vote_dir_files = grep { !/^\./ && -f "$some_dir/$_" } readdir(DIR) +; closedir DIR; foreach $fred (@vote_dir_files) { open FILE, "$some_dir/$fred" or die; while (<FILE>) { $value = $_; } close FILE; $files{$fred} = $value; $totals = ($totals + $value); } } ########################################## # Display the vote results and the chart # with varying widths for the percentage # of votes ########################################## sub results { my $vote_width = 0; $table_width = "440"; $table_remaining = ($table_width - 110); $vote_status = "(<b>You've already voted for $cookie_value</b>)" if ($cookie_state == '1'); # Lots of HTML here to "pretty-up" the displayed # output, removed for this SoPW post for $key (sort { $files{$b} <=> $files{$a} } keys %files) { $vwm = ($table_remaining/$files{$key}) unless $vwm; $vote_width = ($files{$key}); my $percentage_width = ($files{$key}/$vwm); my $unrounded_vote_percent = ($files{$key}/$totals)*100; my $rounded_vote_percent = sprintf("%.2f", $unrounded_vote_percent) +; my $blank_cell = (($files{$key})*$vwm);
...and so on. This particular one is subject to race attacks, but I tried to use a cookie-based approach at the time to stop ballot stuffing. This is no longer a viable approach, since many of the European visitors keep cookies and Javascript disabled, for reasons of security.

Is there anyother series of approaches that might work for this?

Replies are listed 'Best First'.
Re: "Session Tracking" Voting Booth CGI
by Ryszard (Priest) on Jun 03, 2002 at 12:47 UTC
    Session id's. Nice and simple, and will scale if your back end is tuned.

    1. Create a voting schema, normalise and index it nicely, so you can store multiple polls.
    2. Track users via session id's
    3. Associate session id's to users
    4. Add a row to the voting tables for each poll for each user
    5. Each time the user click "vote" check to see if they have voted already.

    Of course this will only work if you work with registered users. As mentioned you'll need lots of testing with load and performance.

    HTH!

      Good ideas, Ryszard, but unfortunately I don't have registered users (yet). There is a new site, my.plkr.org which will incorporate similar functionality, but putting the voting booth option on that site just "doesn't fit" with the rest of the purpose.

      Is there a way to do this without requiring registered IDs of users? Perhaps a hybrid, serializing a hash of the incoming IP/hostname and store that in the DB?

        I dont really think there is a method of doing this accurately without identifying the user explicitly.

        I would depend on your market as to wich method you would use. For example, if your market is highly technical then perhaps cookies would be a bad idea as the techies may turn them off. OTOH if you market is maily dialup, you may get lots of incorrect stats based on that. (I havent even mentioned proxies and invisible proxies)

        I guess it depends on your market and which on is the lesser of twee evils for you.

        As merlyn mentions you could generate a gif and have the user type that in along with their vote. You may get a smaller number of votes, (as its a pita to enter) but better quality - it also doesnt prevent double voting.

Re: "Session Tracking" Voting Booth CGI
by dwiz (Pilgrim) on Jun 03, 2002 at 11:13 UTC
    I never wrote a column on that. :-)
    Well it is similar anyway. HTH

    -dwiz
Re: "Session Tracking" Voting Booth CGI
by Aristotle (Chancellor) on Jun 03, 2002 at 22:17 UTC
    Unless you're associating votes with registered accounts, there is no way you can avoid stuffing. The other problems however can be solved independently of whether you follow a file-based or database approach and are merely a matter of proper programming practice.

    Makeshifts last the longest.