Preventing duplicate signups

2001-05-17 Thread Rob Bloodgood

So, like many of you, I've got a signup system in place for bringing on new
customers.

My signup script is reasonably straightforward.  I use CGI::Validate to make
my parameters pass muster (along with a little judicious JavaScript on the
signup form), Apache::Session::Oracle to maintain state between the multiple
pages of the signup, CGI::FastTemplate to print a pretty success page, and
DBI to create the account records at successful creation.

At one time it was straight CGI but I've since updated it for mod_perl.

Anyway, my only problem is that I can't seem to prevent duplicate signups,
e.g. reloading the last page to create multiple accounts.

This is my dupe detection code:

if (my (%post) = cookie('Signup')) {
local $^W = 0;
my $match = 0;
foreach (qw/ email url password / ) {
$match++ if param($_) and $post{$_} eq param($_)
}
if ($match == 3) {
# I tried this first, but some browsers are stupid.
# print header(-status='204 No Content');
print header(-status='304 Not Modified');
exit;
}
}

Naturally, I set the corresponding cookie in the Header of the Thank you
for signing up template output.

But it doesn't work.  I still get duplicate accounts, and I'm at a loss as
to how to attack this problem.  (this is the 3rd or 4th approach I've
tried).

Suggestions?

TIA!

L8r,
Rob

#!/usr/bin/perl -w
use Disclaimer qw/:standard/;





RE: Preventing duplicate signups

2001-05-17 Thread Rob Bloodgood

 A really simple trick would be rather than to use a cookie, if
 you are saving state to DB anyway.  Set a flag in the DB and test
 for its existence.

 sub handler{
 
 my $s = session-new();
 $s-continue();

 my $flag = $s-get('flag');
 if($flag){
 # do something else
 }
 else{
 # run insert for new signup
 }
 
 }

There should be a word for this...
2 minutes after I finished sending my post, I realized exactly this thing.
Since I'm already accessing the DB w/ Apache::Session, I get miscellaneous
flags thrown in for free... since the rest of the signup scripts only uses
the hash keys in %session that it knows about.

So, after a successful signup (read, creation of the new account record in
the database), I simply stash the new acctid into %session:
$session{id} = $id;

Now here's the fun part.
While writing this script originally, I put in a debug statement like so:

# bypass SQL activity
goto TEMPLATE if $ENV{REMOTE_ADDR} eq $my_ip and $session{email} ne
$my_email;

So the next time a signup comes in, I can check for the existence of
$session{id}.  If it exists... well, read the updated code:

goto TEMPLATE if exists $session{id} or $ENV{REMOTE_ADDR} eq $my_ip and
$session{email} ne $my_email;

Since the template gets the rest of its values straight from %session
anyway, the only other change I had to make was s/$id/$session{id}/.

Problem solved!

Now, of course, I have to provide for the previous behavior whereby a person
could validly sign up multiple accounts if they were pointing to different
urls, but hey!  I've nailed the PROBLEM.  Now I just have to adjust the
behaviors slightly.

L8r,
Rob




Re: Preventing duplicate signups

2001-05-17 Thread clayton cottingham

Rob Bloodgood wrote:
 
 So, like many of you, I've got a signup system in place for bringing on new
 customers.
 
 My signup script is reasonably straightforward.  I use CGI::Validate to make
 my parameters pass muster (along with a little judicious JavaScript on the
 signup form), Apache::Session::Oracle to maintain state between the multiple
 pages of the signup, CGI::FastTemplate to print a pretty success page, and
 DBI to create the account records at successful creation.
 
 At one time it was straight CGI but I've since updated it for mod_perl.
 
 Anyway, my only problem is that I can't seem to prevent duplicate signups,
 e.g. reloading the last page to create multiple accounts.
 
 This is my dupe detection code:
 
 if (my (%post) = cookie('Signup')) {
 local $^W = 0;
 my $match = 0;
 foreach (qw/ email url password / ) {
 $match++ if param($_) and $post{$_} eq param($_)
 }
 if ($match == 3) {
 # I tried this first, but some browsers are stupid.
 # print header(-status='204 No Content');
 print header(-status='304 Not Modified');
 exit;
 }
 }
 
 Naturally, I set the corresponding cookie in the Header of the Thank you
 for signing up template output.
 
 But it doesn't work.  I still get duplicate accounts, and I'm at a loss as
 to how to attack this problem.  (this is the 3rd or 4th approach I've
 tried).
 
 Suggestions?
 
 TIA!
 
 L8r,
 Rob
 
 #!/usr/bin/perl -w
 use Disclaimer qw/:standard/;



i might suggest making your database use stronger indexing
to prevent duplicate data in the database
that way the db would throw an error
that could be caught

we use first name last 
name and email address 
to create a combined
index 
that seems to do fine



Re: Preventing duplicate signups

2001-05-17 Thread G.W. Haywood

Hi Rob,

On Thu, 17 May 2001, Rob Bloodgood wrote:

 But it doesn't work.  I still get duplicate accounts, and I'm at a loss
[snip]
 Suggestions?

As you're using Oracle, why not use a constraint?

73,
Ged.





Re: Preventing duplicate signups

2001-05-17 Thread Jeffrey W. Baker



On Thu, 17 May 2001, Rob Bloodgood wrote:

 So, like many of you, I've got a signup system in place for bringing on new
 customers.

 My signup script is reasonably straightforward.  I use CGI::Validate to make
 my parameters pass muster (along with a little judicious JavaScript on the
 signup form), Apache::Session::Oracle to maintain state between the multiple
 pages of the signup, CGI::FastTemplate to print a pretty success page, and
 DBI to create the account records at successful creation.

When you send out the signup form, include a random 32-character
hexadecimal string as a hidden input, and record in your database that the
code has been sent out.  When the form is submitted, ensure that the code
which accompanies it is valid, by looking in the database.  Then mark the
code as already used.  When the user reloads, your program will see that
the code he is sending was sent before, and can ignore his duplicate
request.

Jeffrey




Re: Preventing duplicate signups

2001-05-17 Thread James G Smith

Rob Bloodgood [EMAIL PROTECTED] wrote:
 A really simple trick would be rather than to use a cookie, if
 you are saving state to DB anyway.  Set a flag in the DB and test
 for its existence.

 sub handler{
 
 my $s = session-new();
 $s-continue();

 my $flag = $s-get('flag');

Be careful of race conditions.  If things are timed right, two requests could 
run in parallel with just enough time differential to get around this test.  
You may want to see if there is a way to lock on something so this code 
section is serialized for any particular user.  If you're using a web farm, 
good luck.  Otherwise, either shared memory or a file link should be 
sufficient (non-NFS).

 if($flag){
 # do something else
 }
 else{
 # run insert for new signup
 }
 
 }
-- 
James Smith [EMAIL PROTECTED], 979-862-3725
Texas AM CIS Operating Systems Group, Unix





Re: Preventing duplicate signups

2001-05-17 Thread James G Smith

Haven't had enough time for my previous reply to make it back to me so I could 
reply to it

If using SQL, you might be able to do row or table locking to get around any 
race conditions.

Rob Bloodgood [EMAIL PROTECTED] wrote:
 A really simple trick would be rather than to use a cookie, if
 you are saving state to DB anyway.  Set a flag in the DB and test
 for its existence.

 sub handler{
 
 my $s = session-new();
 $s-continue();

 my $flag = $s-get('flag');
 if($flag){
 # do something else
 }
 else{
 # run insert for new signup
 }
 
 }
-- 
James Smith [EMAIL PROTECTED], 979-862-3725
Texas AM CIS Operating Systems Group, Unix