You've got a race condition issue with your logic. If two users attempt to create the same username and/or email at almost the same time, the system will report to both that the username/email address is available, then throw an error on the second attempt to actually insert that username or email address into the database. You'd be better off simply trying to insert the data and catching the PDO Exception on a unique key violation - this also cuts the number of queries run from 3 to 1 on successful registration attempts.
[RESOLVED] JSON
Didn't think of that, I'll add to my to do list, arguing with email activation currently
Rather than make a new thread, currently trying to figure out why this won't work.
<?php require_once 'connection.php'; ?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="css/mystyle.css">
<title>Game of Thrones social</title>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(document).ready(function() {
$("form").on("submit", function(event) {
event.preventDefault();
$("span.error").empty()
$.getJSON('registerForm.php', $(this).serialize(), function(data) {
if (!data.errors) {
alert(data.message) // deal with a no-error response ( all is good)
}else{
$.each(data.errors,function(i,datum){
$("[name='"+datum.name+"']").next().html(datum.error)
})
}
});
});
});
</script>
</head>
<body>
<form action="" method="GET">
<div class="formControl">
<input type="input" name="username" placeholder="Username" value="<?php echo isset($_POST['username']) ? $_POST['username'] : '' ?>">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="text" name="email" placeholder="E-mail" value="<?php echo isset($_POST['email']) ? $_POST['email'] : '' ?>">
<span class="error"></span>
</div>
<div class="formControl">
<input type="password" name="password" placeholder="Password">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="password" name="repeatPassword" placeholder="Repeat password">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="hidden" name="code" value="<?php echo substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1).substr(md5(time()),1); ?>">
<span class="error"> </span>
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
<?php
require_once'connection.php';
header('Content-Type: application/json');
$errors = [];
$username = trim($_GET['username']);
$email = trim($_GET['email']);
$password = trim($_GET['password']);
$repeatPassword = trim($_GET['repeatPassword']);
$code = $_GET['code'];
$query = $db->prepare("SELECT username.username FROM username WHERE username.username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"username","error"=>"Username taken"];
}
if(filter_var($username, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{3,25}/"]]) === FALSE){
$errors[]= ["name"=>"username","error"=>"invalid Id (3 to 25 characters)"];
}
if(preg_match('/[^a-z_\-0-9]/i', $username))
{
$errors[]= ["name"=>"username","error"=>"invalid Id (Usernames may not contain symbols)"];
}
if(filter_var($email,FILTER_VALIDATE_EMAIL) === FALSE) {
$errors[]= ["name"=>"email","error"=>"invalid Email"];
}
$emailQ = $db->prepare("SELECT username.eMail FROM username WHERE username.eMail = :email LIMIT 1");
$emailQ->bindValue(':email', $email, PDO::PARAM_STR);
$emailQ->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"email","error"=>"Email registered"];
}
if(filter_var($password, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{6,25}/"]]) === FALSE){
$errors[]= ["name"=>"password","error"=>"invalid password (6 to 25 characters)"];
}
if(!preg_match("/(?=[a-z]*[0-9])(?=[0-9]*[a-z])([a-z0-9-]+)/i",$password)) {
$errors[]= ["name"=>"password","error"=>"Password must contain numbers and letters"];
}
if($password !== $repeatPassword){
$errors[]= ["name"=>"repeatPassword","error"=>"passwords don't match"];
}
$salt= uniqid(mt_rand(), true);
$options=['salt'=>$salt, 'cost'=>12];
if (count($errors) === 0) {
// everything is OK, the browser should send us to the next page
echo json_encode(["message"=>"Please view your emails to activate your account"]);
$sql = "INSERT INTO username (username,password, eMail ,joinedDate, active, activecode) VALUES (:username, :password, :email ,NOW(), 0, :code)";
$query = $db->prepare($sql);
$query->execute(array(
':username'=> $username,
':password'=> $cryptpwd=crypt($password,'$2y$12$'.$salt.'$'),
':email'=> $email,
':code'=> $code
));
echo $message = '
http://gotsocial.co.uk/active.php?activecode='.$code.'.
';
$to = $email;
$subject = 'Game of Thrones Social';
$from = "register@gotsocial.co.uk";
$result = mail($to, $subject, $message, "From: $from");
}
echo json_encode($errors);
When it fails validation it gives me an undefined alert rather than falling pack on the server side validation
Currently it's running here:
Updated to this but still nothing
<?php
require_once'connection.php';
header('Content-Type: application/json');
$errors = [];
$username = trim($_GET['username']);
$email = trim($_GET['email']);
$password = trim($_GET['password']);
$repeatPassword = trim($_GET['repeatPassword']);
$code = $_GET['code'];
$query = $db->prepare("SELECT username.username FROM username WHERE username.username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"username","error"=>"Username taken"];
}
if(filter_var($username, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{3,25}/"]]) === FALSE){
$errors[]= ["name"=>"username","error"=>"invalid Id (3 to 25 characters)"];
}
if(preg_match('/[^a-z_\-0-9]/i', $username))
{
$errors[]= ["name"=>"username","error"=>"invalid Id (Usernames may not contain symbols)"];
}
if(filter_var($email,FILTER_VALIDATE_EMAIL) === FALSE) {
$errors[]= ["name"=>"email","error"=>"invalid Email"];
}
$emailQ = $db->prepare("SELECT username.eMail FROM username WHERE username.eMail = :email LIMIT 1");
$emailQ->bindValue(':email', $email, PDO::PARAM_STR);
$emailQ->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"email","error"=>"Email registered"];
}
if(filter_var($password, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{6,25}/"]]) === FALSE){
$errors[]= ["name"=>"password","error"=>"invalid password (6 to 25 characters)"];
}
if(!preg_match("/(?=[a-z]*[0-9])(?=[0-9]*[a-z])([a-z0-9-]+)/i",$password)) {
$errors[]= ["name"=>"password","error"=>"Password must contain numbers and letters"];
}
if($password !== $repeatPassword){
$errors[]= ["name"=>"repeatPassword","error"=>"passwords don't match"];
}
$salt= uniqid(mt_rand(), true);
$options=['salt'=>$salt, 'cost'=>12];
if (count($errors) === 0) {
// everything is OK, the browser should send us to the next page
echo json_encode(["message"=>"Please view your emails to activate your account"]);
$sql = "INSERT INTO username (username,password, eMail ,joinedDate, active, activecode) VALUES (:username, :password, :email ,NOW(), 0, :code)";
$query = $db->prepare($sql);
$query->execute(array(
':username'=> $username,
':password'=> $cryptpwd=crypt($password,'$2y$12$'.$salt.'$'),
':email'=> $email,
':code'=> $code
));
$params = array(
'to' => $email,
'subject' => 'Game of',
'html' => 'http://gotsocial.co.uk/active.php?activecode='.$code,
'text' => 'the plain text',
'from' => 'register@gotsocial.co.uk'
);
print_r($params);
}
echo json_encode($errors);
You need to look at the network response you are getting back from the server. When you have errors, there is no data.errors element, because you haven't given the array you are json encoding an index name of 'errors', like the 'message' index name you are supplying in the success condition.
In addition to the race condition already mentioned, you have a security hole in the activation code. By passing it through the form, rather than generating it in the registerForm.php code, anyone can supply their own code value and won't need to have access to the email account being used. They can just register, supply their own code, then simply visit your site with that code in the url to complete registration.
<?php
require_once'connection.php';
header('Content-Type: application/json');
$errors = [];
$username = trim($_GET['username']);
$email = trim($_GET['email']);
$password = trim($_GET['password']);
$repeatPassword = trim($_GET['repeatPassword']);
$code = $_GET['code'];
$query = $db->prepare("SELECT username.username FROM username WHERE username.username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"username","error"=>"Username taken"];
}
if(filter_var($username, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{3,25}/"]]) === FALSE){
$errors[]= ["name"=>"username","error"=>"invalid Id (3 to 25 characters)"];
}
if(preg_match('/[^a-z_\-0-9]/i', $username))
{
$errors[]= ["name"=>"username","error"=>"invalid Id (Usernames may not contain symbols)"];
}
if(filter_var($email,FILTER_VALIDATE_EMAIL) === FALSE) {
$errors[]= ["name"=>"email","error"=>"invalid Email"];
}
$emailQ = $db->prepare("SELECT username.eMail FROM username WHERE username.eMail = :email LIMIT 1");
$emailQ->bindValue(':email', $email, PDO::PARAM_STR);
$emailQ->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"email","error"=>"Email registered"];
}
if(filter_var($password, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{6,25}/"]]) === FALSE){
$errors[]= ["name"=>"password","error"=>"invalid password (6 to 25 characters)"];
}
if(!preg_match("/(?=[a-z]*[0-9])(?=[0-9]*[a-z])([a-z0-9-]+)/i",$password)) {
$errors[]= ["name"=>"password","error"=>"Password must contain numbers and letters"];
}
if($password !== $repeatPassword){
$errors[]= ["name"=>"repeatPassword","error"=>"passwords don't match"];
}
if (count($errors) === 0) {
// everything is OK, the browser should send us to the next page
$sql = "INSERT INTO username (username,password, eMail ,joinedDate, active, activecode) VALUES (:username, :password, :email ,NOW(), 0, :code)";
$query = $db->prepare($sql);
$query->execute(array(
':username'=> $username,
':password'=> $cryptpwd=crypt($password,'$2y$12$'.$salt.'$'),
':email'=> $email,
':code'=> $code
));
echo $message = '
http://gotsocial.co.uk/active.php?activecode='.$code.'.
';
$to = $email;
$subject = 'Game of Thrones Social';
$from = "register@gotsocial.co.uk";
$result = mail($to, $subject, $message, "From: $from");
echo json_encode(["message"=>"Please view your email account to activate your account"]);
}
if (count($errors) === 0) {
}
else{
echo json_encode(["errors"=>$errors]);
}
This is the problem
echo $message = '
http://gotsocial.co.uk/active.php?activecode='.$code.'.
';
$to = $email;
$subject = 'Game of Thrones Social';
$from = "register@gotsocial.co.uk";
$result = mail($to, $subject, $message, "From: $from");
Yes I know I haven't corrected the race conditions yet, honestly not learnt how to do it yet, it's on my to do list after I figure this out.
cluelessPHP;11054873 wrote:This is the problem
echo $message = ' http://gotsocial.co.uk/active.php?activecode='.$code.'. '; $to = $email; $subject = 'Game of Thrones Social'; $from = "register@gotsocial.co.uk"; $result = mail($to, $subject, $message, "From: $from");
Indeed that does look problematic. What do you mean "this is the problem?"
cluelessPHP;11054873 wrote:Yes I know I haven't corrected the race conditions yet, honestly not learnt how to do it yet, it's on my to do list after I figure this out.
Basically, you'll drop the 2 queries that check for existing values that match the user-supplied email and username altogether. Validate the other data, then run the insert inside a try...catch() block. Assuming you've set PDO to throw exceptions and you've got a unique index set up covering both username and email in the table, the catch() block will catch the PDOException containing a unique index violation message and code. If it does, return an error message to the user requesting that they try again. I wouldn't recommend you tell the user which key was a duplicate as that lets a malicious user know that either the username or the email exists - just tell the user that the combination is invalid. No need to make a determined hacker's life easier by giving them a valid username or email and making sure they only have to guess the password...
sneakyimp;11054875 wrote:Indeed that does look problematic. What do you mean "this is the problem?"
If I take it out, my success message will display, if I leave it in my success message won't show but I will get an email sent to my email address
You need to remove the echo statement from that block of code. It is sending output to the client that is not of the expected format and it interferes with the processing of the json encoded output.
I don't know if I should laugh or cry...it worked
I see that you are trying to output JSON with this script. Have you bothered to examine the actual output that comes out? If there are any E_NOTICE or E_WARNING messages that get thrown, this will result in garbled JSON output but it may nevertheless be quite informative.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link rel="stylesheet" href="css/mystyle.css">
<title>Game of Thrones social</title>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(document).ready(function() {
$("form").on("submit", function(event) {
event.preventDefault();
$("span.error").empty()
$("span.success").empty()
$.getJSON('registerForm.php', $(this).serialize(), function(data) {
if (!data.errors) {
$(".success").append(data.message) // deal with a no-error response ( all is good)
}else{
$.each(data.errors,function(i,datum){
$("[name='"+datum.name+"']").next().html(datum.error)
})
}
});
});
});
</script>
</head>
<body>
<span class="success"></span>
<form action="" method="POST">
<div class="formControl">
<input type="input" name="username" placeholder="Username" value="">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="text" name="email" placeholder="E-mail" value="">
<span class="error"></span>
</div>
<div class="formControl">
<input type="password" name="password" placeholder="Password">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="password" name="repeatPassword" placeholder="Confirm Password">
<span class="error"> </span>
</div>
<div class="formControl">
<input type="hidden" name="code" value="<?php echo substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1).substr(md5(time()),1); ?>">
<span class="error"> </span>
</div>
<input type="submit" value="Submit">
</form>
</body>
</html>
<?php
require_once'connection.php';
error_reporting(E_ALL);
ini_set('display_errors', '1');
header('Content-Type: application/json');
$errors = [];
$username = trim($_GET['username']);
$email = trim($_GET['email']);
$password = trim($_GET['password']);
$repeatPassword = trim($_GET['repeatPassword']);
$code = $_GET['code'];
$query = $db->prepare("SELECT username.username FROM username WHERE username.username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"username","error"=>"Username taken"];
}
if(filter_var($username, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{3,25}/"]]) === FALSE){
$errors[]= ["name"=>"username","error"=>"invalid Id (3 to 25 characters)"];
}
if(preg_match('/[^a-z_\-0-9]/i', $username))
{
$errors[]= ["name"=>"username","error"=>"invalid Id (Usernames may not contain symbols)"];
}
if(filter_var($email,FILTER_VALIDATE_EMAIL) === FALSE) {
$errors[]= ["name"=>"email","error"=>"invalid Email"];
}
$emailQ = $db->prepare("SELECT username.eMail FROM username WHERE username.eMail = :email LIMIT 1");
$emailQ->bindValue(':email', $email, PDO::PARAM_STR);
$emailQ->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"email","error"=>"Email registered"];
}
if(filter_var($password, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{6,25}/"]]) === FALSE){
$errors[]= ["name"=>"password","error"=>"invalid password (6 to 25 characters)"];
}
if(!preg_match("/(?=[a-z]*[0-9])(?=[0-9]*[a-z])([a-z0-9-]+)/i",$password)) {
$errors[]= ["name"=>"password","error"=>"Password must contain numbers and letters"];
}
if($password !== $repeatPassword){
$errors[]= ["name"=>"repeatPassword","error"=>"passwords don't match"];
}
if (count($errors) === 0) {
// everything is OK, the browser should send us to the next page
$salt= uniqid(mt_rand(), true);
$options=['salt'=>$salt, 'cost'=>12];
$sql = "INSERT INTO username (username,password, eMail ,joinedDate, active, activecode) VALUES (:username, :password, :email ,NOW(), 0, :code)";
$query = $db->prepare($sql);
$query->execute(array(
':username'=> $username,
':password'=> $cryptpwd=crypt($password,'$2y$12$'.$salt.'$'),
':email'=> $email,
':code'=> $code
));
$message = '
http://gotsocial.co.uk/active.php?activecode='.$code.'.
';
$to = $email;
$subject = 'Game of Thrones Social';
$from = "register@gotsocial.co.uk";
$result = mail($to, $subject, $message, "From: $from");
echo json_encode(["message"=>"Please view your email account to activate your account"]);
}
if (count($errors) === 0) {
}
else{
echo json_encode(["errors"=>$errors]);
}
This was the results so far, next is reading about condition races
That doesn't look like JSON output to me.
There is a JSON way for doing emails? I did think I was mixing languages again but wasn't sure
There isn't a "JSON way" for doing anything; it's just an object notation language. A convention for writing structured data (which in this case uses the syntax JavaScript uses for the job).
cluelessPHP;11054907 wrote:There is a JSON way for doing emails? I did think I was mixing languages again but wasn't sure
No.
If you had followed laserlight's advice and read the docs on JSON (instead of typing "pass") then you might have a better grasp on the fact that JSON is not a programming language. It's a means of encoding variables and data objects in a Javascript-compatible format. From json.org:
JSON (JavaScript Object Notation) is a lightweight data-interchange format.
You have repeatedly posted your PHP code without any detail of what the problem is. It would appear from that you are posting that you are trying to output some JSON code because the lines at the end look like this:
echo json_encode(["message"=>"Please view your email account to activate your account"]);
or this:
echo json_encode(["errors"=>$errors]);
You also pointed out what you thought was the problem but we've got no real explanation of what is or is not working. dbismad rightfully pointed out that if you are trying to output JSON code then you should NOT be echoing other stuff before you output something with json_encode. Looking at that last code you posted, it looks like maybe you fixed that problem.
Given your posts here, I think the concept of race conditions might be a bit advanced for you, but here's a start:
https://en.wikipedia.org/wiki/Race_condition
sneakyimp;11054911 wrote:Given your posts here, I think the concept of race conditions might be a bit advanced for you, but here's a start:
https://en.wikipedia.org/wiki/Race_condition
Given the fact I'm still a student I'd say a lot of things are "a bit advanced for me" thanks ever so much for the encouragement though.
I'd been thinking of something else when I typed that, yes I'm going to more than one website for resources, I actually have a folder of code snipets that laserlight has suggested, I'm fully aware the laserlight knows far more than me, I'm fairly positive you know far more than me as well, anytime I learn something new I'll look at the code suggestions that were made, at the time I might not have understood them completely but I always store them and refer back to them at a later date
Well I spent some time reading about race conditions and exceptions I commented out all of my validation to attempt this, I'm fairly sure I miss read the examples?
<?php
require_once'connection.php';
error_reporting(E_ALL);
ini_set('display_errors', '1');
header('Content-Type: application/json');
$errors = [];
$username = trim($_GET['username']);
$email = trim($_GET['email']);
$password = trim($_GET['password']);
$repeatPassword = trim($_GET['repeatPassword']);
$code = substr(str_shuffle("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, 1).substr(md5(time()),1);
$query = $db->prepare("SELECT username.username FROM username WHERE username.username = :username LIMIT 1");
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
/*
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"username","error"=>"Smoke me a kipper i will be back for breakfast"];
}
if(filter_var($username, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{3,25}/"]]) === FALSE){
$errors[]= ["name"=>"username","error"=>"invalid Id (3 to 25 characters)"];
}
if(preg_match('/[^a-z_\-0-9]/i', $username))
{
$errors[]= ["name"=>"username","error"=>"invalid Id (Usernames may not contain symbols)"];
}
if(filter_var($email,FILTER_VALIDATE_EMAIL) === FALSE) {
$errors[]= ["name"=>"email","error"=>"invalid Email"];
}
$emailQ = $db->prepare("SELECT username.eMail FROM username WHERE username.eMail = :email LIMIT 1");
$emailQ->bindValue(':email', $email, PDO::PARAM_STR);
$emailQ->execute();
if ( $query->rowCount() > 0 ) {
$response=1;
$errors[]= ["name"=>"email","error"=>"Email registered"];
}
if(filter_var($password, FILTER_VALIDATE_REGEXP,["options"=> [ "regexp" => "/.{6,25}/"]]) === FALSE){
$errors[]= ["name"=>"password","error"=>"invalid password (6 to 25 characters)"];
}
if(!preg_match("/(?=[a-z]*[0-9])(?=[0-9]*[a-z])([a-z0-9-]+)/i",$password)) {
$errors[]= ["name"=>"password","error"=>"Password must contain numbers and letters"];
}
if($password !== $repeatPassword){
$errors[]= ["name"=>"repeatPassword","error"=>"passwords don't match"];
}
*/
if (count($errors) === 0) {
// everything is OK, the browser should send us to the next page
$salt= uniqid(mt_rand(), true);
$options=['salt'=>$salt, 'cost'=>12];
try {
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO username (username,password, eMail ,joinedDate, active, activecode) VALUES (:username, :password, :email ,NOW(), 0, :code)";
$query = $db->prepare($sql);
$query->execute(array(
':username'=> $username,
':password'=> $cryptpwd=crypt($password,'$2y$12$'.$salt.'$'),
':email'=> $email,
':code'=> $code
));
$message = '
http://gotsocial.co.uk/active.php?activecode='.$code.'.
';
$to = $email;
$subject = 'Game of Thrones Social';
$from = "register@gotsocial.co.uk";
$result = mail($to, $subject, $message, "From: $from");
echo json_encode(["message"=>"Please view your email account to activate your account"]);
} catch(PDOException $e) {
if ($e->errorInfo[1] == 1062) {
//output error message
$errors[]= ["name"=>"username","error"=>"Smoke me a kipper i will be back for breakfast"];
}
}
}
else{
echo json_encode(["errors"=>$errors]);
}
This is the post maxxd made about the race condition -
maxxd;11054753 wrote:You've got a race condition issue with your logic. If two users attempt to create the same username and/or email at almost the same time, the system will report to both that the username/email address is available, then throw an error on the second attempt to actually insert that username or email address into the database. You'd be better off simply trying to insert the data and catching the PDO Exception on a unique key violation - this also cuts the number of queries run from 3 to 1 on successful registration attempts.
You should have a total of ONE sql query in your code, an INSERT query. The username and email columns must be defined as unique keys/indexes, so that any insertion of duplicate values will trigger an error. Your code will need to test for the error number for this condition. You can either run a test and display the error number or look it up in the mysql documentation. If the INSERT query runs without any errors and the number of affected rows is greater than zero (in case you are doing things where one query will affect more than one row), the submitted values where unique and were inserted. If the query fails with a duplicate key error number, you know the value(s) where not unique and are already in use. Your error handling logic would need to test for the specific mysql error number for a duplicate key error and setup and output a message to the visitor. Unfortunately, telling the user if a username/email is in use will allow bot scripts/people to find valid usernames and emails on your system and you should code in flood detection and reporting logic to slow down and tell you (the site owner) about any such probing attempts.