Prevent a duplicate email going to a database - problem.

Hi everyone,

I have a html form with the action field set as PHP_SELF. It asks for a users name and email. When they submit the form, a success message appears where the form was and the details are added to a MySQL database. That much I have working.

However, I need to add some PHP that will prevent duplicate email entries. This is what I have so far:

[php]<?php
//connect to the database
$dbc = mysqli_connect(‘localhost’, ‘root’, ‘password’, ‘database’) or die(‘Error connecting to MySQL server.’);

if(isset($_POST[‘register’])){
$name = mysqli_real_escape_string($dbc, trim($_POST[‘name’]));
$email = mysqli_real_escape_string($dbc, trim($_POST[‘email’]));

//create the insert statement
$query = “INSERT INTO tablename(name, email, date) VALUES (’$name’, ‘$email’, now())”;

//insert record into the table
$result = mysqli_query($dbc, $query) or die(‘Error querying the database’);

//display thank you to user
echo “Success - you have been added.”;

//close the connection
mysqli_close($dbc);
}

else {
?> [/php]

        [code]<form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>" name="newsletterform">
        <input class="news" name="name" placeholder="Name" required>
        <input class="news" name="email" type="email" placeholder="Email" required>
        <input class="news" id="submitright" name="register" type="submit" value="Subscribe">
        </form>[/code]
       [php] <?php } ?>[/php]

So the above does the basics, takes the details and adds them to a database.

I have found the following code block to prevent duplicates - but when I add it, it throws everything out. Where would I place this code to get the form working correctly?

[php]$check=mysqli_query($dbc,"select * from tablename where email=’$email’ ");
$checkrows=mysqli_num_rows($check);

if($checkrows>0) {
echo “customer exists”;
} else { [/php]

Any help would be great, Andy :wink:

Well, Andy, duplicate emails can be annoying. There are many ways to check for them. First, you can use the
date the email was written. The only problem with this is if the email was altered slightly to fix a bad text and
the user wants to resend it with slightly different data, you might want the second email to be sent. If your page
that sends the email is not set up correctly, you can sometimes get a second email sent. In this case the text
in the email would be the same. Therefore, you could have your code check for both date/time and content. If
the time is within one minute of the last post AND/OR the same content, you can bypass saving the data in the
database. You need to think out what you want to check for first. Then code it.

Now, dates are fairly easy to check. The date in the database, of course, should have it’s field set to “datetime”.
This saves the date and time in a set format. To check the date/time of a field to see if it is within a set time, you
can use code something like this: (A few examples from a site I use…)

This checks for profiles to see if they are six months old, if they are the user needs to update their profile.
[php]
// Check the last time they visited their profile page. If over six months then go to profile page.
if (is_null($row[“last_profile_update”]) OR ($row[“last_profile_update”]<=date(“Y-m-d H:i:s”, strtotime("-6 months")))) header(“Location: UserProfile.php”);
[/php]
( Note that this one also checked for no profile ever updated…)

This one checks for an entry within one day of the current time…
[php]
// Check the for posts during last 24 hours
if ($row[“post_date”]<=date(“Y-m-d H:i:s”, strtotime("-24 hours"))) {
// Handle recent posts…
[/php]

So, to check to see if a post was done within one minute, you could use this…
[php]
// Check for possible double-post
if ($row[“post_date”]<=date(“Y-m-d H:i:s”, strtotime("-1 minute")))) {
// Post is less than one minute from last one, check content…
if ($row[“post_content”]==$current_post_content) {
// Post was withing one minute and has same content, do not process this post…
[/php]
(In this version it checks for a repost within one minute and also checks content to see if it is identical.)

You could also do a query that would look for identical posts, but, this usually will not locate any. The chances
of a user typing exactly the same data is very small. Even if it was a small yes or no answer to a question, it
would be hard to duplicate. ( Yes. Yes yes YES! etc…) So, this would be a waste of time.

Not sure if this is what you need, but, hope it helps…

Oh, also, I forgot to add…

The code you posted checks for a previous email address. This is good to use when you register new users.
(I always check the user database to make sure that the user is not making two accounts.) But, any user should
be allowed to make more than one post, so, the code you posted would not be used for checking for posts unless
you are only allowing one entry per user per subject. ???

Hi ErnieAlex,

thanks for the detailed reply. Yes, I am only looking to accept users names / emails once. They would be added to a list, so if a newsletter was to be sent out, each person on the list would only receive the newsletter once.

When I add the code to check for duplicates, it only runs correctly if the form is set to show all the time. However, I want the form to show initially, then disappear once submitted to show only the success message in its place, I can’t seem to figure that part out i.e. where does the duplicate code go within my own code.

Thanks for your suggestion.

Andy :wink:

Well, in that case, you need to think out the logic of your process.

You should never place a duplicate email into your user’s list. Always dump them when the user registers to your
site. Then, you will never have a duplicate in your list. So, your site has several sections. The first one is your
user system. It adds new users as they register and that is where you check for previously entered addresses.
When you check the data that a new user enters, you would check the email at that point.l If it already exists in
your user table, then you would not allow them to be entered. They should get a message stating that it was
already used and if they want to register, they need to use a different one.

In that manner, you will never get duplicates and your mailing list will be correct…

I personally never like checking for duplicate emails; I instead validate the email and only use the verified email.

For example

[php]if ( $user && $user->email === ‘member’ ) {
/* Perform the certain task! */
}[/php]

The reason I do that is so that the bad guys don’t realize that the email is a valid email address, plus it prevents a valid person from getting locked out. Well that’s how I handle, there might be duplicate email addresses in the database, but only one will be validated and verified. You must have a control somewhere and an email address is a good option. A better option is a telephone number, but right now only big companies can afford it.

Usually you want emails to be unique in your database, then it will simply throw an error if you try to insert a email that is already registered.

[php]ALTER TABLE tablename ADD UNIQUE (email)[/php]

What [member=71845]JimL[/member] said is the right way to do it.

Additionally, you do not want to check if it already exists. You want to attempt to insert the data. If it is a duplicate, the DB will error from the constraint. You can catch the error and handle it however you choose.

The problem with checking if it exists comes when you get two people checking simultaneously if the same data exists.

This will create a “Race Condition” whereby both users will get an OK to insert. You will either get a duplicate entry (without the DB constraint) or one guy gets entered and the other doesn’t.


Hi JimL

thanks for that suggestion, I tried that and it works to a point with one slight issue.

  1. Set my email field to unique within MySQL:
ALTER TABLE tablename ADD UNIQUE email;
  1. Set up a message within the PHP code:
or die(mysqli_errno($dbc) == 1062 ? "your already listed on our database" : 'Error querying database.');
  1. Saved everything.

  2. Entered a name / email combination that I knew already existed and submitted the form.

  3. The following message appeared:
    your already listed on our database. So it picked up on error 1062. Excellent that worked - thanks.

The only issue is that it stops loading the rest of the page script. So anything that comes after that form on the web page does not load e.g. the footer, which is just plain HTML. I know die means to stop processing - but I thought that was only for the php script not anything outside of that.

How can I ensure everything loads / displays correctly after that form when using this method?

Thanks, Andy :wink:

“die” stops PHP dead in its tracks so you usually don’t want to use that.

Read up on mysqli error handling
http://php.net/manual/en/mysqli.error.php

Thanks JimL,

I suppose or die is really only for debugging purposes and not for deploying an actual application. I shall read up on your link and see if I can come up with a solution to the problem, as it stands, it might be better to create a simple delete script for admin to delete duplicate entries when/if they occur.

Thanks,

Andy :wink:

Use a Try/Catch block to handle the error

In PDO it would be like

[php]try{
insert duplicate email
}
catch (PDOException $e)
{
if ($e->getCode() == ‘23000’)
{
$error[] = “Duplicate not allowed.”;

            }

}[/php]

[member=46186]Kevin Rubio[/member] Then he also has to config mysqli to actually throw errors, as it doesn’t do it by default ???
http://php.net/manual/en/class.mysqli-sql-exception.php

It is the “correct” way to do it though, just another point won for the PDO-side

I disavow any knowledge of the existence of Mysqli or any of its quirks. If your not using PDO your doing it wrong.

Sponsor our Newsletter | Privacy Policy | Terms of Service