Checking if row exists under criteria (PDO, prepare???) - php

The code below indicates my attempts to try and find out whether a row exists with the criteria gave in the code. It defaults to the else statement, correctly, but doesn't work with the 'if' statement if the if statement appears to be true (there are no emails down as ashfjks#sdhja.com), and instead the code proceeds. The latter part of this code is mostly to expand on the situation. the row can only exist or not exist so I don't understand why it's not strictly doing one or the other. I am converting into PDO for site secuirty, thats why not all is in PDO, yet. I am sorry if this question is too localised?
$stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?");
$stmt->execute(array("$email"));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC);
while($row = $stmt->fetch()) {
if ( ! $row3) {
// Row3 doesn't exist -- this means no one in the database has this email, allow the person to join
$query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())";
mysqli_query($dbc, $query);
$query = "SELECT * FROM table WHERE username = '$username'";
$data2 = mysqli_query($dbc, $query);
while ($row = mysqli_fetch_array($data2)) {
$recipent = '' . $row['user_id'] . '';
$query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')";
mysqli_query($dbc, $query);
// Aftermath.
echo '<p>Your new account has been successfully created. You\'re now ready to log in. After this you should implement basic character-details on your users profile to begin the game.</p>';
mysqli_close($dbc);
exit();
} }
else {
// An account already exists for this email, so display an error message
echo '<p class="error">An account already exists for this e-mail.</p>';
$email = "";
}
}

Your if statement will never be executed. You need to check the number of rows returned. This is what you want:
Note: I originally used $stmt->rowCount(), but the OP said that didn't work for him. But I'm pretty sure the cause of that error was coming from somewhere else.
if (!($stmt = $pdo->prepare("SELECT * FROM table WHERE email = ?"))) {
//error
}
if (!$stmt->execute(array("$email"))) {
//error
}
//The $row3 var you had was useless. Deleted that.
$count = 0;
while ($row = $stmt->fetch()) {
$count++;
}
//The query returned 0 rows, so you know the email doesn't exist in the DB
if ($count== 0) {
$query = "INSERT INTO table (username, email, password, join_date) VALUES ('$username', '$email', SHA('$password1'), NOW())";
if (!mysqli_query($dbc, $query)) {
//error
}
$query = "SELECT * FROM table WHERE username = '$username'";
if (!($data2 = mysqli_query($dbc, $query))) {
//error
}
while ($row = mysqli_fetch_array($data2)) {
$recipent = '' . $row['user_id'] . '';
$query = "INSERT INTO messages (recipent, MsgTit, MsgR, MsgA, sender, time, readb, reada, MsgCon) VALUES ('$recipent', '$MsgTit', '$MsgR', '$MsgA', '$sender', NOW(), '$readb', '$reada', '$MsgCon')";
if (!mysqli_query($dbc, $query)) {
//error
}
// Aftermath.
echo '<p>Your new account has been successfully created. You\'re now ready to log in. After this you should implement basic character-details on your users profile to begin the game.</p>';
mysqli_close($dbc);
exit();
}
}
//The query did not return 0 rows, so it does exist in the DB
else {
// An account already exists for this email, so display an error message
echo '<p class="error">An account already exists for this e-mail.</p>';
$email = "";
}
And you should totally convert the rest of those queries to use PDO.

+1 to answer from #Geoff_Montee, but here are a few more tips:
Make sure you check for errors after every prepare() or execute(). Report the error (but don't expose your SQL to the user), and fail gracefully.
Note that even though you checked for existence of a row matching $email, such a row could be created in the brief moment of time since your check and before you INSERT. This is a race condition. Even if you SELECT for a row matching $email, you should also use a UNIQUE constraint in the database, and catch errors when you execute the INSERT in case the UNIQUE constraint blocks the insert due to conflict.
SELECT email instead of SELECT *. If you have an index on email, then the query runs more efficiently because it can just check the index for the given value, instead of having to read all the columns of the table when you don't need them. This optimization is called an index-only query.
Likewise use SELECT user_id instead of SELECT *. Use SELECT * only when you really need to fetch all the columns.
Bcrypt is more secure than SHA for hashing passwords.

Related

Inserting data into Mysql with PHP while loop

I'm trying to check an email against my database, and if it doesn't already exist, add it to the database.
$query = "SELECT * FROM users";
$inputQuery = "INSERT INTO users (`email`,
`password`) VALUES ('$emailInput',
'$passInput')";
$emailInput = ($_POST['email']);
$passInput = ($_POST['password']);
if ($result = mysqli_query($link, $query)) {
while ($row = mysqli_fetch_array($result)) {
if ($row['email'] == $emailInput) {
echo "We already have that email!";
} else {
mysqli_query($link, $inputQuery);
echo "Hopefully that's been added to the database!";
}
}
};
It can detect an existing email, it's just the adding bit...
Currently this seems to add a new empty row for each existing row (doubling the size).
I'm trying to understand why it doesn't add the information, and how to escape the loop somehow.
Also for good measure, everyone seems to reuse $query, but this seems odd to me. Is it good practice to individually name queries as I have here?
Please let me know if there's anything else I should add.
I am not going to talk about the standards but straight, simple answer to your question.
Approach - 1:
INSERT INTO users (`email`,`password`) SELECT '$emailInput', '$passInput' from DUAL WHERE NOT EXISTS (select * from users where `email` = '$emailInput');
Approach - 2:
- Create a unique key on email column
- use INSERT IGNORE option.
user3783243 comments are worth noting
Try this :
$emailInput = mysqli_real_escape_string($link, $_POST['email']);
$passInput = mysqli_real_escape_string($link, $_POST['password']);
$qry3=mysqli_query($link,"select * from users where `email`='".$emailInput."'");
$num=mysqli_num_rows($qry3);
if($num==1) {
echo "Email-Id already exists";
} else {
$inputQuery = mysqli_query($link,"INSERT INTO users (`email`, `password`) VALUES ('".$emailInput."', '".$passInput."')");
if ($inputQuery) {
echo "Hopefully that's been added to the database!";
}
}
Your code seems to be a bit over-engineered because why not to pass you $_POST['email'] to select query where clause
"SELECT * FROM users where email = $emailInput" and then check if it is there already.
Also, keep in mind that this is an example only, and you should always check and sanitize user input.
From another hand you can do it with MySQL only using INSERT ... ON DUPLICATE KEY UPDATE Syntax. https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html
That requires to add unique key for email column.

Ensure username and email address are unique

I am trying to verify whether or not a username and email address exist in my database and have tried to do a if, elseif, else statement to no avail.
I want to first run a check to see if the username is fine - obviously if not, an echo statement will appear. If the username doesn't exist, run an elseif statement to see if the email address is unique - again if not, another echo statement will appear. For the final statement, if all other conditions return false, I want to run the below code so that the user's input is submitted to the database.
I initially tried to declare two variables with a statement to check if the username=$username and email_address=$email_address then check to see if the number of rows returned from a mysqli_query is more than 1 for the username. I entered an elseif statement with the same but for email address but then I had an else statement with the below code in {} brackets.
I have deleted the original code because too many errors were thrown up, and was probably too convoluted and messy when a more elegant way to do what I was exists.
Any help would be appreciated.
if(isset($_POST['submit']))
{
$sql = "INSERT INTO users (first_name, last_name, username, email_address, password, gender, city, country, verification_code, verified, sign_up_date) VALUES (
'$first_name',
'$last_name',
'$username',
'$email_address',
'$password',
'$gender',
'$city',
'$country',
'$verification_code',
'1',
'$sign_up_date')";
$result = mysqli_query($conn,$sql);
header("Location:confirmation.php");
}
What you want is an integrity check on the data. You should do this check inside the database. The simplest way is with unique constraints/indexes:
create unique index unq_users_username on users(username);
create unique index unq_users_email on users(email);
If you attempt to insert or update a row so it violates these constraints, then your data modification step will fail with an error.
You need to create an index for them.
Use The following command to create the index:
CREATE UNIQUE INDEX index_name ON table_name (column_name)
Check This Link for more info: https://www.w3schools.com/sql/sql_create_index.asp
You could write a function to check your database first for example:
$errors = []; // you can add errors to this array.
if (isset($_POST['submit']))
{
// first do your validation here against empty values and invalid email
$sql = "SELECT * from users where email='$email' and username='$username'";
$result = mysqli_query($conn, $sql);
if (mysqli_num_rows($result) > 0) {
$errors[] = "Username and email has been taken.";
}
if (!empty($errors))
{
// loop through your errors and echo them
} else {
// insert your values into the database
}
}

Prevent duplicate data being entered into mysql database

I'm trying to make my email subscription service reject emails that already exist within my database so users don't subscribe the same email twice. this is what I have but its not working, any ideas?
<?php
if(!isset($_POST['submit']))
exit();
$vars = array('email');
$verified = TRUE;
foreach($vars as $v) {
if(!isset($_POST[$v]) || empty($_POST[$v])) {
$verified = FALSE;
}
}
if(!$verified) {
echo "<p style='color:white; margin-top:25px;'>*Email required*</p>";
exit();
}
$email = $_POST['email'];
if($_POST['submit']) echo "<p style='color:white; margin-top:25px;'>*Check your inbox* </p>";
// Create connection
$con=mysqli_connect("mysql.host","user","password","dbname");
// Check connection
if (mysqli_connect_errno($con))
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$sql="INSERT INTO emails (email) VALUES ('$_POST[email]')";
if (!mysqli_query($con,$sql))
{
die('Error: ' . mysqli_error($con));
}
$query = mysql_query("SELECT * FROM emails WHERE email='$email'",($con));
if(mysql_num_rows($query) != 1)
{
echo "email already exists";
// redirect back to form and populate with
// data that has already been entered by the user
}
mysqli_close($con);
?>
The easiest way to let MySQL reject the duplicate e-mail address is to make the field unique (http://www.w3schools.com/sql/sql_unique.asp)
ALTER TABLE emails ADD UNIQUE (email)
However, MySQL will not return a warning
Use mysqli_num_rows($query) instead of mysql_num_rows($query)
$query = mysqli_query($con, "SELECT * FROM emails WHERE email='".$email."'");
if(mysqli_num_rows($query) > 0){
echo "email already exists";
}else{
$sql="INSERT INTO emails (email) VALUES ('".$_POST[email]."')";
if (!mysqli_query($con,$sql))
{
die('Error: ' . mysqli_error($con));
}
}
Firstly, you're mixing MySQLi_ with MySQL_ so stick with MySQLi_ and modify the rest of your code accordingly.
This is the logic I use in my scripts, using ? instead of '$email'
$query = $con->query("SELECT * FROM emails WHERE email=?");
// $query = $con->query("SELECT email FROM emails WHERE email=?");
// you may need to use that one --^ if checking a particular column
$numrows=mysqli_num_rows($query);
if($numrows > 0){
die("Email already exists in the database, please try again.");
}
You can use this method, binding parameters. Assuming your column is named email
$query = "SELECT email FROM emails WHERE email=?";
if ($stmt = $con->prepare($query)){
$stmt->bind_param("s", $email);
if($stmt->execute()){
$stmt->store_result();
$email_check= "";
$stmt->bind_result($email_check);
$stmt->fetch();
if ($stmt->num_rows == 1){
echo "That Email already exists.";
exit;
}
}
}
Beside mixing mysql and mysli
Use > not !=
if(mysqli_num_rows($query) > 1)
But this approach means you already have duplicates.
Maybe this will help after you put an unique index on the email column.
As noted in the other answers, you mixed mysqli and mysql functions.
for exemple in both these lines you use mysql instead of mysqli functions.
$query = mysql_query("SELECT * FROM emails WHERE email='$email'",($con));
if(mysql_num_rows($query) != 1)
I also think your code is easily SQL Injectable.
You are using $_POST["email"] in your insert query, without sanitizing it.
Have a look to at least the sql injection wikipedia page
My answer would be as follows,
First, create a UNIQUE KEY of the email column, and then:
INSERT INTO `table` VALUES (/*etc*/) ON DUPLICATE KEY UPDATE /*set a column equal to itself*/
This allows you to attempt inserting into the database, and you can choose whether or not the query throws an error. If you want it to throw an error, then simply do not use ON DUPLICATE KEY, and then catch the SQLException that is thrown from the query and tell the user that the email already exists.
Add a unique constraint to the email column.
Test for error returned on insert or update. I believe the code may be influenced if it is a primary key, foreign key, unique constraint on an index.
With PHP you can use
if( mysql_errno() == X) {
// Duplicate VALUE
} else {
// fail
}
You can test it yourself with a duplicate email or here are the mysql_errNo return values
For non PHP, to determine correct error code test it yourself with a duplicate email or look at the following.
MySQL Errors

Problem with syntax error

Hi guys am fighting with a syntax error of my sql, saying exactly:
"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax"
Even though the code is working and doing what I wanted I still get the syntax error info!
and here is the code:
$person_id =mysql_query("SELECT person_id FROM person WHERE firstname='$array[0]' AND lastname='$array[1]' AND city='$array[2]' ")
or die(mysql_error());
if (mysql_num_rows($person_id) )
{
print 'user is already in table';
}
else
{
mysql_query ("INSERT INTO person VALUES (NULL, '$array[0]' ,'$array[1]' , '$array[2]' ")
or die(mysql_error());
$person_id = mysql_insert_id();
}
$address_id =mysql_query("SELECT address_id FROM address WHERE street='$array[3]' AND city='$array[4]' AND region='$array[5]'")
or die(mysql_error());
if (mysql_num_rows($address_id) )
{
print ' already in table';
}
else
{
mysql_query ("INSERT INTO address VALUES (NULL, '$array[3]', '$array[4]', '$array[5]'")
or die(mysql_error());
$address_id = mysql_insert_id();
}
mysql_query ("INSERT INTO person_address VALUES($person_id, $address_id)")
or die(mysql_error());
Thanks for any suggestions
It's probably because you haven't escaped your values...
Try:
$query = "SELECT age FROM person WHERE name='".mysql_real_escape_string($array[0])."' AND lastname='".mysql_real_escape_string($array[1])."' AND city='".mysql_real_escape_string($array[2])."'";
And read up on SQL injection.
EDIT
I think your problem is that you are trying to pass mysql result resources directly into a string, without fetching the actual values first.
Try this:
// Create an array of escaped values to use with DB queries
$escapedArray = array();
foreach ($array as $k => $v) $escapedArray[$k] = mysql_real_escape_string($v);
// See if the person already exists in the database, INSERT if not
$query = "SELECT person_id FROM person WHERE firstname='$escapedArray[0]' AND lastname='$escapedArray[1]' AND city='$escapedArray[2]' LIMIT 1";
$person = mysql_query($query) or die(mysql_error());
if ( mysql_num_rows($person) ) {
print 'user is already in table';
$person = mysql_fetch_assoc($person);
$person_id = $person['person_id'];
} else {
$query = "INSERT INTO person VALUES (NULL, '$escapedArray[0]', '$escapedArray[1]', '$escapedArray[2]')";
mysql_query($query) or die(mysql_error());
$person_id = mysql_insert_id();
}
// See if the address already exists in the database, INSERT if not
$query = "SELECT address_id FROM address WHERE street='$escapedArray[3]' AND city='$escapedArray[4]' AND region='$escapedArray[5]'";
$address = mysql_query($query) or die(mysql_error());
if (mysql_num_rows($address) ) {
print 'address already in table';
$address = mysql_fetch_assoc($address);
$address_id = $person['address_id'];
} else {
$query = "INSERT INTO address VALUES (NULL, '$escapedArray[3]', '$escapedArray[4]', '$escapedArray[5]')";
mysql_query ($query) or die(mysql_error());
$address_id = mysql_insert_id();
}
// INSERT a record linking person and address
mysql_query ("INSERT INTO person_address VALUES($person_id, $address_id)") or die(mysql_error());
ANOTHER EDIT
Firstly, I have modified the code above - added a couple of comments, corrected a couple of small errors where the wrong variable was referenced and re-spaced it to make it more readable.
Secondly...
You are getting that additional error because you are trying to insert a new row into your person_address table, which doesn't seem to have a sensibly configured primary key. The easy work around to the problem you currently have is to run a SELECT against this table to see if you have already got a record for that user, then if you have you can do an UPDATE instead of the INSERT to alter the existing record.
However, if I understand what your doing here correctly, you don't actually need the person_address table, you just need to add another integer column to the person table to hold the ID of the corresponding row in the address table. Doing this would make many of your future queries potentially much simpler and more efficient as it will be much easier to SELECT data from both tables at once (you could do it with your current structure but it would be much more confusing and inefficient).
The following code example could be used if you add another integer column on the end of your person, and call that column address_id. You will notice it's very similar to the above, but there are two key differences:
We do the address stuff first, since we will keep track of the relation in the person record
We do an UPDATE only if we find a person, otherwise we just INSERT a new person as before
// Create an array of escaped values to use with DB queries
$escapedArray = array();
foreach ($array as $k => $v) $escapedArray[$k] = mysql_real_escape_string($v);
// See if the address already exists in the database, INSERT if not
$query = "SELECT address_id FROM address WHERE street='$escapedArray[3]' AND city='$escapedArray[4]' AND region='$escapedArray[5]'";
$address = mysql_query($query) or die(mysql_error());
if (mysql_num_rows($address) ) {
print 'address already in table';
$address = mysql_fetch_assoc($address);
$address_id = $person['address_id'];
} else {
$query = "INSERT INTO address VALUES (NULL, '$escapedArray[3]', '$escapedArray[4]', '$escapedArray[5]')";
mysql_query ($query) or die(mysql_error());
$address_id = mysql_insert_id();
}
// See if the person already exists in the database, UPDATE if he does, INSERT if not
$query = "SELECT person_id FROM person WHERE firstname='$escapedArray[0]' AND lastname='$escapedArray[1]' AND city='$escapedArray[2]' LIMIT 1";
$person = mysql_query($query) or die(mysql_error());
if ( mysql_num_rows($person) ) {
print 'user is already in table';
$person = mysql_fetch_assoc($person);
$person_id = $person['person_id'];
$query = "UPDATE person SET address_id = '$address_id' WHERE person_id = '$person_id'";
mysql_query($query) or die(mysql_error());
} else {
$query = "INSERT INTO person VALUES (NULL, '$escapedArray[0]', '$escapedArray[1]', '$escapedArray[2]', '$address_id')";
mysql_query($query) or die(mysql_error());
}
If we structure the database in this way, it allows us to do this:
SELECT person.*, address.* FROM person, address WHERE person.address_id = address.address_id AND [some other set of conditions]
Which will return the person record, and the address record, in the same result set, all nicely matched up for you by the database.
YET ANOTHER EDIT
You need to add an auto-increment primary key to the person_address table, and perform a SELECT on it to make sure you are not adding duplicate records.
You should replace the final INSERT statement with the following code segment. This code assumes that you have a primary key in the person_address table called relation_id. It also assumes that the id field names in this table are named in the same way as they are in the other two tables.
// See if a relation record already exists for this user
// If it does, UPDATE it if the address is different
// If it doesn't, INSERT an new relation record
$query = "SELECT relation_id, address_id FROM person_address WHERE person_id = '$person_id' LIMIT 1";
$relation = mysql_query($query);
if ( mysql_num_rows($relation) ) {
$relation = mysql_fetch_assoc($relation);
if ($relation['address_id'] == $address_id) {
print 'The record is identical to an existing record and was not changed';
} else {
$relation_id = $relation['relation_id'];
$query = "UPDATE person_address SET address_id = '$address_id' WHERE relation_id = '$relation_id'";
mysql_query($query) or die(mysql_error());
}
} else {
$query = "INSERT INTO person_address VALUES(NULL, '$person_id', '$address_id')";
mysql_query($query) or die(mysql_error());
}
EVEN MORE EDITING
Try this to replace the code from above:
// See if a relation record already exists for this user
// If it doesn't, INSERT an new relation record
$query = "SELECT person_id FROM person_address WHERE person_id = '$person_id' AND address_id = '$address_id' LIMIT 1";
$relation = mysql_query($query);
if ( !mysql_num_rows($relation) ) {
$query = "INSERT INTO person_address VALUES('$person_id', '$address_id')";
mysql_query($query) or die(mysql_error());
}
You cannot use array values like that inside of quotes - instead you could, for example, separate the values from the query using dots.
$query = "SELECT age FROM person WHERE name='".$array[0]."' AND lastname='".$array[1]."' AND city='".$array[2]."'";
the second and fourth query do not have an ending ')' at the end of the values

Is is possible to do this with only one sql?

I want have an insert query, but before inserting I check whether the username and email are used by someone else. If used, I want to cancel insert query and echo a message to say whether username or email is in use.
Here my code:
$sql = "SELECT 1 FROM user WHERE username='".$_POST['username']."'";
if(!$result = mysql_query($sql))
die(mysql_error());
while($row = mysql_fetch_array($result))
die('This username is already exists');
$sql = "SELECT 2 FROM user WHERE email='".$_POST['email']."'";
if(!$result = mysql_query($sql))
die(mysql_error());
while($row = mysql_fetch_array($result))
die('This email address is already exists');
$sql = "insert into user (username,email,password,tel,type) values ('".$_POST['username']."','".$_POST['email']."','".$_POST['password']."','".$_POST['telnumber']."','member')";
if(!mysql_query($sql))
die(mysql_error());
I want these three sql statements in one. It can be either using cases or something else that you suggest. So,
Is it possible to zip this code into one sql query?
As a result what I need is
sql = "sql_query"
if(!$result = mysql_query($sql))
die(mysql_error());
while($row = mysql_fetch_array($result)){
if($row['result']==1)
die('This username is already exists');
else if($row['result']==2)
die('This email is already exists');
}
die('you have succesfully registered');
thanks for any advice.
While I suggest you follow #cularis' answer, you may be interested in the following alternative:
Give email and username the UNIQUE constraint, by creating a unique index for both of these.
run your INSERT query, and if this fails... (due to duplicate keys)
run the suggested combined SELECT, to determine which field existed (username or email)
You can combine the first two queries like this:
$sql = "SELECT * FROM user WHERE username='".$_POST['username']."' OR email='".$_POST['email']."'";
Have look at mysql_real_escape string to sanatize your input.
Assuming you don't care about a more specific error case you could probably just do the following:
$sql = "SELECT * FROM user WHERE username='".$_POST['username']."' OR email='".$_POST['email']."'";
if(!$result = mysql_query($sql))
die(mysql_error());
while($row = mysql_fetch_array($result))
die('The username or email address is already being used');
$sql = "insert into user (username,email,password,tel,type) values ('".$_POST['username']."','".$_POST['email']."','".$_POST['password']."','".$_POST['telnumber']."','member')";
if(!mysql_query($sql))
die(mysql_error());
This isn't the best of designs if you're looking for, as I said, specific error cases. So if you are okay with just telling the person there is an error that one or both are in use then that should work.
I am not sure as I am very rusty in PHP/MySQL but I assume that if such cases of both exist then multiple rows may be returned and I forget exactly how mysql_fetch_array works but I assume it's an array of all results valid for the query so you should be set. As long as the array exists, you know there was a hit in the db.

Categories