Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

Wondering novice...

by threepts (Acolyte)
on Mar 28, 2000 at 14:13 UTC ( [id://6326]=perlquestion: print w/replies, xml ) Need Help??

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);
}

Replies are listed 'Best First'.
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
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.)

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
Re: Wondering novice...
by turnstep (Parson) on Mar 28, 2000 at 21:19 UTC

    In the spirit of TMTOWTDI:

    $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, $_); }
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.
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 }
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.
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.
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
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.
      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.

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.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://6326]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others perusing the Monastery: (5)
As of 2024-03-29 14:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found