threepts has asked for the wisdom of the Perl Monks concerning the following question:
I am currently working on a raffle script to raffle off items. I am working on making it so it checks to see if the email submitted is not already in the db. if it is.. it denys the user, but if its not, it adds it. This code does work "sorta". The code will add the user but its not kicking out my submission if the email is already in the db. It just adds it again. If anyone knows a way of doing this, it would be greatfully appreciated.
open(RAFFLE_DAT,"< tickets.dat") || die "tickets.dat is not found.";
while (defined($line=<RAFFLE_DAT>)) {
($tickennum,$emailaddr)=split(/::/,$line);
if ($emailaddr eq $email) { &bademail();
}
else { &goodemail();
}
close (RAFFLE_DAT);
}
Re:
by lhoward (Vicar) on Mar 28, 2000 at 19:43 UTC
|
One of the easiest approaches would be to use a tied hash. The SDBM_File and Fcntl modules come with perl so you shouldn't have to hunt them down and install them from CPAN.
use Fcntl;
use SDBM_File;
my %db_email;
tie (%db_email, 'SDBM_File', './email.db', O_RDWR | O_CREAT, 0666);
if(defined $db_email{$email}){
# already in DB... process apropriately
}else{
# not yet in DB
$ticketnum=get_next_ticket_num();
$db_email{$email}=$ticketnum;
}
untie(%db_email);
Les Howard
www.lesandchris.com
Author of Net::Syslog and Number::Spell | [reply] [Watch: Dir/Any] |
RE: Wondering novice...
by chromatic (Archbishop) on Mar 28, 2000 at 23:51 UTC
|
If you're going to have be adding a lot of addresses to your data file, be aware that a linear search will not scale well. Your script will become slower and slower the more people you add.
One option (as before) is a tied hash. See perldoc:perltie for details there. Another, if you wish to maintain your .dat file is to use DBD::CSV from CPAN. It's a module that lets you use the standard DBI interface on Comma Separated Value files.
(You can specify a different separator, though.)
Just additional information to help you move beyond novice status.... (The print("--$variable--") idea is very useful. That will probably help more than my suggestion.) | [reply] [Watch: Dir/Any] |
Re: Wondering novice...
by lhoward (Vicar) on Mar 29, 2000 at 18:28 UTC
|
Here's my example cleaned up a litlte bit and looking more like "real"
code. If you encounter any errors when trying to implement, please
post them here. Otherwise it'll be hard to help you fix any problems
you're having.
#!/usr/bin/perl -w
# these USE lines generaly go at the top of your program
# before any other code
use Fcntl;
use SDBM_File;
my %db_email;
tie (%db_email, 'SDBM_File', './email.db', O_RDWR | O_CREAT, 0666) or die "error opening DB file $!";
# you need to be sure that the user running the script has
# apropriate permissions to create/write the DB file
my $email='abc@yahoo.com';
# your code to extract the e-mail address should be here
if(defined $db_email{$email}){
# already in DB... process apropriately
}else{
# not yet in DB
print "assigning ticket\n";
$db_email{$email}=982;
# your ticket num generating code should
# be here instead of a hardcoded assignment
}
untie(%db_email);
Les Howard
www.lesandchris.com
Author of Net::Syslog and Number::Spell | [reply] [Watch: Dir/Any] |
Re: Wondering novice...
by turnstep (Parson) on Mar 28, 2000 at 21:19 UTC
|
$found=0;
open(RAFFLE_DAT,"< tickets.dat") || die "tickets.dat is not found.";
while(<RAFFLE_DAT>) {
chop;
if ($tickennum,$emailaddr)=split(/::/,$line))
if ($emailaddr eq $email) { $found=1; last; }
}
}
close (RAFFLE_DAT) || die "Could not close tickets.dat\n";
if ($found) { &bademail(); }
else { &goodemail; }
Instead of the chop, you could replace the sixth line with:
if ($emailaddr eq "$email\n") { $found=1; last; }
As an aside, if the ticket numbers are arbitrary, you could
always not even use a $tickennum, but just have a list of
emails in the file, and the "ticket number" would be their line
number:
## Assigns email address to each ticket number
$x=0;
while(<RAFFLE_DAT>) {
chop;
$ticket{$x++}=$_; ## or push(@ticket, $_);
}
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: Wondering novice...
by plaid (Chaplain) on Mar 28, 2000 at 21:26 UTC
|
Any of the answers above are the correct ways to go
about it, but on a side note, I just thought i'd add a
comment about debugging code. It's easy to see from the
original code that the condition if ($emailaddr eq $email)
isn't at fault, so a good thing to do might be to go into
the else and add a statement such as
print "-$emailaddr- ne -$email-\n"
This could be helpful in the beginning before there are too
many email addresses in the database, and the hyphens around
each of the variables could help track down hard to find
differences such as whitespace. If this is a CGI script,
you can instead print to STDERR and check your server's
error log. | [reply] [Watch: Dir/Any] [d/l] |
RE: Wondering novice...
by Anonymous Monk on Mar 29, 2000 at 00:59 UTC
|
Seems like you don't chop or chomp your email address from your database before comparing it to the email received. So, you endup comparing email@provider.com\n to email@provider.com...
So, you should do :
while($line = <DATA>){
chop $line; # remove the trailing char: \n
...
# do your stuf
}
| [reply] [Watch: Dir/Any] [d/l] |
Re: Wondering novice...
by threepts (Acolyte) on Mar 30, 2000 at 15:41 UTC
|
ok, finally got around to giving the code a try. ok, The script is 'running' both on the web and via the shell so thats one step. I am adding a differnt email and it says i already have been submitted, both from shell & web. I get no errors though. lhoward, if you are busy and would like to help out a lil more go ahead and email me at threepts@shell.hobbybox.org and i will email ya the exact code i have at the moment. Thanks. | [reply] [Watch: Dir/Any] |
RE: Wondering novice...
by Anonymous Monk on Mar 28, 2000 at 17:12 UTC
|
While a tied hash would be the easiest way to do this, using your method i see a severe lack of chomping.. obviously a newline thrown on $emailaddr is not going to compare true with $email....
open(RAFFLE_DAT,"< tickets.dat") || die "tickets.dat is not found.";
while (<RAFFLE_DAT>) {
chomp;
($tickennum,$emailaddr) = split(/::/, $_);
if ($emailaddr eq $email) {
&bademail();
} else {
&goodemail();
}
will probably work as you expect it.
| [reply] [Watch: Dir/Any] [d/l] |
Re: Wondering novice...
by threepts (Acolyte) on Mar 29, 2000 at 08:26 UTC
|
Well i thank ya all for the replys but i still have one problem.. half the stuff ya explained I have no clue about. ;) But i will look into the things that i do understand. thanks | [reply] [Watch: Dir/Any] |
Re: Wondering novice...
by threepts (Acolyte) on Mar 29, 2000 at 08:39 UTC
|
After testing the different replys people sent, none of them work. Couple get errors, some wont run via the web. etc etc. So once again, thanks for trying. | [reply] [Watch: Dir/Any] |
|
Okay. Well, what errors are you getting? Could you post
them? The solutions the other posters posted should work,
at least with a little tweaking for your own purposes.
It's true that some may not work if you just copy them
verbatim.
I'd second (or third, or fourth) the responses recommending
a hash tied to a DBM file. Were those the samples you
had trouble with? A DBM file associates keys with values
and provides fast access to searching for those keys. They
provide a functionality very similar to (exactly the same as?) Perl's
associative arrays--which, I presume, is why Perl uses associative
arrays to access DBM files.
There are several different DBM packages, and there are
pros and cons to the different solutions. To read more
about the different packages that you can use, look at
the AnyDBM_File manpage. SDBM_File was recommended
by another poster because it comes with Perl and thus
should automatically be on your system. If you start
doing more work with tie and DBM files, you may
want to investigate the DB_File module, because it's
much more robust. However, I don't believe it comes with
Perl.
In the context of DBM files, the tie function is used
to bind an associative array to the DBM file. When you
use the associative array--for example, when you write
something like
my $value = $hash{$key};
--this (eventually) invokes the routine in the DBM library
that looks up a value in the DBM. Essentially, what you're
doing is hiding the DBM implementation behind a simple
associative array; and in general, this is what tie does--
it hides a more complicated implementation behind a simple
Perl variable (be it a scalar, an array, an associative
array, or, according to perltie, a filehandle).
Sorry if this is redundant, i.e. you already knew much
of this stuff; but I thought it might be helpful for you
in trying to figure out what's going on, and why people
are suggesting that you use tie.
As to your particular problem, I suggest that you post the
error messages that you're getting; then perhaps we can
determine what's going wrong. | [reply] [Watch: Dir/Any] [d/l] |
Re: Wondering novice...
by threepts (Acolyte) on Mar 30, 2000 at 09:33 UTC
|
That looks more like my type of code. I will check it out and reply. thanks. | [reply] [Watch: Dir/Any] |
|
|