Reputation: 1806
I try to make a secure method that checks if a username or email is not taken and I'm not sure if this is the right way. How can I do this better?
private function checkAvailability() {
try {
$conn = new PDO(DB_SERVER, DB_USER, DB_PASS);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = ("SELECT COUNT(*) FROM users WHERE username = :username OR email = :email");
$st = $conn->prepare($sql);
$st->bindValue(":username", $_POST["username"], PDO::PARAM_STR);
$st->bindValue(":email", $_POST["email"], PDO::PARAM_STR);
$st->execute();
if($st->fetchColumn() > 0) {
$sql = ("SELECT COUNT(*) FROM users WHERE username = :username");
$st = $conn->prepare($sql);
$st->bindValue(":username", $_POST["username"], PDO::PARAM_STR);
$st->execute();
if($st->fetchColumn() > 0) {
throw new Exception("That username is already taken");
} else {
throw new Exception("That e-mail is already registered.")
}
return 0;
} else {
return 1;
}
$conn = null;
} catch (PDOException $e) {
echo "Database error: " . $e->geMessage();
} catch (Exception $e) {
echo "Registration failed: " . $e->geMessage();
}
}
public function registerUser() {
if(self::checkAvailability) {
// register user
}
}
Upvotes: 0
Views: 686
Reputation: 4715
You are already on the right path here.
The query SELECT COUNT(*) FROM users WHERE username = :username OR email = :email
can be a performance problem, because the db can't use any index here. So you might want to split that in two statements one for username and one for email. That would also help you determining which error occured.
Also you don't need every hit in the db just the first, so a limit 1
is also usefull.
Upvotes: 2