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

I crave the benevolence of some wisdom as I'm trying to write a script which updates a database and creates a fake user address using (I hoped) random numbers and the auto-incremented db index at a faked subdomain (in case the same random number ever does appear twice). I've run into two problems.
Firstly, I'm trying to check if an address exists and if it does go onto the next email to check that but my code is currently stopping the entire process and exiting out of the loop if it comes across a duplicate at next.
Secondly, I've not been able to get the code to call the correct item from the index to insert it into string I'm creating. Is there a better way of coding some sort less random sub string (like a timestamp) which can at least be unique?
use strict; use warnings; use File::Find; use DBI; my $admin = 'admin'; my $dbh = DBI->connect("dbi:mysql:list:localhost", "user", "pword") or + die "Connection Error: $DBI::errstr\n";; my $sthcheck; my $sthcaluser; my $sth; my $sthuser; my ($email, $password, $caluser, $opt_out, $founduser); my $dir = "file"; find (\&wanted, $dir); sub wanted { my @useroutput; open (IN, "$_") or die "Can't open $_"; @useroutput = <IN>; close(IN); chomp @useroutput; foreach my $person (@useroutput) { my ($email, $password) = split(/:/, $person); #need to check if user email exists. If not then add if (!defined $sthcheck) { $sthcheck = $dbh->prepare_cached("SELECT name FROM user WHERE + name = ?") or die "Couldn't prepare statement: " . $dbh->errstr; } $sthcheck->execute($email); ($founduser) = $sthcheck->fetchrow_array(); next $person unless !$founduser; if ($password eq "no_password" ) { $password =~ s/no_password//; } #get the last id my $db_id = $sth->{'mysql_insertid'}; if (!$db_id) { $db_id = 0; } my $caluser = create_random() . "-" . $db_id . "\@foo.bar.com"; my $opt_out="F"; if (!defined $sth) { $sth = $dbh->prepare_cached("INSERT INTO user(name, pass, cal_nam +e, opt_out) VALUES (?,?,?,?)") or die "Couldn't prepare statement: " +. $dbh->errstr; } $sth->execute($email, $password, $caluser, $opt_out); #insert user role into db my $sthadmin = $dbh->prepare ("INSERT INTO user_role(name, role) + VALUES (?,\"admin\")") or die "Couldn't prepare statement: " . $dbh- +>errstr; if (!defined $sthuser) { $sthuser = $dbh->prepare_cached("INSERT INTO user_role(name, role +) VALUES (?,\"user\")") or die "Couldn't prepare statement: " . $dbh- +>errstr; } #if section to place helpline as the site admin if (grep $email eq $_, $admin ) { $sthadmin->execute($email); } else { $sthuser->execute($email); } } } sub create_random { my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9, qw(! @ $ % ^ & *) ); my $user_name = join("", @chars[ map { rand @chars } ( 1 .. 10 ) ]) +; return $user_name; } $sth->finish(); $dbh->disconnect();
I tried using use diagnostics but the line it gave was the $sth->execute which is referenced at find (\&wanted, $dir); but I'm fairly sure the error is in my trying to call $db_id as when I tried $db_id=$dbh->last_insert_id($catalog, $schema, $table, $field) it returned Mo&72sEbUI-0@foo.bar.com and the 0 was repeated after the - for all the emails. I'd be grateful for some advice on sorting this script out. Thanks.

Replies are listed 'Best First'.
Re: Trying to create a fake address through random numbers and a looping issue
by JavaFan (Canon) on Oct 31, 2008 at 15:47 UTC
    Firstly, I'm trying to check if an address exists and if it does go onto the next email to check that but my code is currently stopping the entire process and exiting out of the loop if it comes across a duplicate at next.
    That's probably because you have next $person instead of next.
      Thanks, that's sorted the first problem.
Re: Trying to create a fake address through random numbers and a looping issue
by BrowserUk (Patriarch) on Oct 31, 2008 at 16:30 UTC

    If the problem is ensuring that your fake addresses are always unique, why not just append an incrementing number from within the script?

    my $uniq = 0; sub create_random { my @chars = ( "A" .. "Z", "a" .. "z", 0 .. 9, qw(! @ $ % ^ & *) ); my $user_name = join("", @chars[ map { rand @chars } ( 1 .. 10 ) ]) +; return $user_name . $uniq++; }

    If you need to keep the uniqueness across runs, store a single field for the number in the DB, query it when the script starts and store it before you exit.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Trying to create a fake address through random numbers and a looping issue
by JavaFan (Canon) on Oct 31, 2008 at 15:52 UTC
    it returned Mo&72sEbUI-0@foo.bar.com and the 0 was repeated after the - for all the emails.
    Grepping for mysql_insertid in the DBD::mysql manual page suggests you find the mysql_insertid attribute in the database handle, not the statement handle.
      Thanks, JavaFan. Tried that as well and I'm still getting the -0 in each instance. I suspect the most sensible thing to do is to rethink that section of code and using the id and do some more reading around the subject.
Re: Trying to create a fake address through random numbers and a looping issue
by JavaFan (Canon) on Oct 31, 2008 at 17:22 UTC
    Note that $db_id will always be 0 for the first email you generate. That's because at that moment, you haven't inserted anything yet. You may want to query the database for LAST_INSERT_ID instead.