This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Prevent Duplicate SQL entries
I'm just looking for a simple way to tell me if a record already exists, and if it does, not to insert it into the table. The below code inserts regardless if it exists or not... and I just cannot figure out why.
<?php
$FirstName = $_POST["FirstName"];
$LastName = $_POST["LastName"];
$conn = sqlsrv_connect( $hostname, $connectionInfo)
$dup = sqlsrv_query($conn, "SELECT * FROM contact WHERE (FirstName='$FirstName') AND (LastName='$LastName')");
if(sqlsrv_num_rows($dup) > 0)
{
echo "Already Exists";
}
else
{
$query = "INSERT INTO contact (FirstName, LastName) VALUES ('$FirstName', '$LastName')";
sqlsrv_query( $conn, $query );
}
EDIT:
Ultimately, changing sqlsrv_num_rows($dup) > 0 to sqlsrv_has_rows($dup) fixed the problem. Below is my updated code:
$params = array($_POST['FirstName'], $_POST['LastName']);
$conn = sqlsrv_connect( $hostname, $connectionInfo)
$sql = "SELECT * FROM contact WHERE FirstName = ? AND LastName = ?";
$dup = sqlsrv_query($conn, $sql, $params);
if(sqlsrv_has_rows($dup))
{
echo "Already Exists";
}
else
{
$query = "INSERT INTO contact (FirstName, LastName) VALUES (?, ?)";
sqlsrv_query( $conn, $query, $params );
}
First, you need to identify your primary key. This is usually some sort of ID field. I'd probably recommend against using the pairing of FirstName LastName because there are many, many instances of people with the same first name and last name. "Kevin Kline" is the name of both an actor and a SQL Server MVP (and there are probably many, many more).
If you want to just blindly insert FirstName LastName into a table, then a RDBMS-agnostic query would be more like
INSERT INTO contact (FirstName, LastName) VALUES ($FirstName, $LastName) WHERE NOT EXISTS
(SELECT 1 FROM contact where FirstName = $FirstName and LastName = $LastName);
(disclaimer: I know I didn't format it according to what you had in your post, that is due to the following)
HOWEVER:
Your code is also vulnerable to SQL injection attacks. Please read up on the PHP method sqlsrv_query paying special attention to the "params" argument.
Additionally, going back to the "Kevin Kline" example, this will only insert the first "Kevin Kline." I suppose this is fine if you're adding "Kevin Kline" as a dimension in a star schema that will be associated with other dimensions like Profession in a fact table. However, if that's not your application domain, then I'd highly recommend that you determine what you're going to use as your table keys so that you can accurately track the appropriate data.
Related
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.
I am having some problems with a script, I am basically inputting data into a MySQL table. This data will be inserted in the table as 1 row.
Upon a row of data being entered into the table I want the current/specific row currently being entered to have the column 'account_type' to be updated from its default value 'member' to 'client'.
It's a long story why I need to do it this way but I do not want to simply just enter the value 'client' it must be updated from 'member' to client.
The script I have (which is the bit at the bottom) is currently doing just this but it is affecting all rows in the table, is there a way I can add a where clause to the update to say only affect the current row being entered and do not update all other rows in the table?
<?php ob_start();
// CONNECT TO THE DATABASE
require('../../includes/_config/connection.php');
// LOAD FUNCTIONS
require('../../includes/functions.php');
$username = $_POST['username'];
$password = $_POST['password'];
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$email = $_POST['email'];
$number = $_POST['number'];
$dob = $_POST['dob'];
$accounttype = $_POST['accounttype'];
$query="INSERT INTO ptb_registrations (
username,
password,
firstname,
lastname,
email,
number,
dob,
accounttype,
date_created )
VALUES(
'".$username."',
'".$password."',
'".$firstname."',
'".$lastname."',
'".$email."',
'".$number."',
'".$dob."',
'".$accounttype."',
now()
)";
mysql_query($query) or die();
$query="INSERT INTO ptb_users (
first_name,
last_name,
email,
password )
VALUES(
'".$firstname."',
'".$lastname."',
'".$email."',
MD5('".$password."')
)";
mysql_query($query) or dieerr();
$result = mysql_query("UPDATE ptb_users SET ptb_users.user_id = ptb_users.id,
ptb_users.account_type = 'Client'");
Please, don't use mysql_* functions in new code. They are no longer maintained and are officially deprecated. See the red box? Learn about prepared statements instead, and use PDO, or MySQLi - this article will help you decide which. If you choose PDO, here is a good tutorial.
You can use the MySQL function LAST_INSERT_ID() to do this.
The old ext/MySQL extension exposes this functionality through mysql_insert_id(), but you can also access it directly, and more cleanly, and safely, in a query.
So you can do something like this:
$result = mysql_query("
UPDATE ptb_users
SET ptb_users.user_id = ptb_users.id,
ptb_users.account_type = 'Client'
WHERE id = LAST_INSERT_ID()
");
I know you say "it's a long story..." But what you are doing makes little-to-no sense. I can only imagine you are doing this because of a trigger - and that demonstrates quite nicely why triggers are generally a bad idea ;-)
Please try and re-think your design if at all possible.
Get the inserted ID after your first query then use it in the update (assuming you have a primary key with auto-increment).
Try With WHERE Condition on unique coloumn
mysql_query("UPDATE ptb_users SET ptb_users.user_id = ptb_users.id,
ptb_users.account_type = 'Client'" WHERE ptb_user.email='$email');
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.
I have this code to select all the fields from the 'jobseeker' table and with it it's supposed to update the 'user' table by setting the userType to 'admin' where the userID = $userID (this userID is of a user in my database). The statement is then supposed to INSERT these values form the 'jobseeker' table into the 'admin' table and then delete that user from the 'jobseeker table. The sql tables are fine and my statements are changing the userType to admin and taking the user from the 'jobseeker' table...however, when I go into the database (via phpmyadmin) the admin has been added by none of the details have. Please can anyone shed any light onto this to why the $userData is not passing the user's details from 'jobseeker' table and inserting them into 'admin' table?
Here is the code:
<?php
include ('../database_conn.php');
$userID = $_GET['userID'];
$query = "SELECT * FROM jobseeker WHERE userID = '$userID'";
$result = mysql_query($query);
$userData = mysql_fetch_array ($result, MYSQL_ASSOC);
$forename = $userData ['forename'];
$surname = $userData ['surname'];
$salt = $userData ['salt'];
$password = $userData ['password'];
$profilePicture = $userData ['profilePicture'];
$sQuery = "UPDATE user SET userType = 'admin' WHERE userID = '$userID'";
$rQuery = "INSERT INTO admin (userID, forename, surname, salt, password, profilePicture) VALUES ('$userID', '$forename', '$surname', '$salt', '$password', '$profilePicture')";
$pQuery = "DELETE FROM jobseeker WHERE userID = '$userID'";
mysql_query($sQuery) or die (mysql_error());
$queryresult = mysql_query($sQuery) or die(mysql_error());
mysql_query($rQuery) or die (mysql_error());
$queryresult = mysql_query($rQuery) or die(mysql_error());
mysql_query($pQuery) or die (mysql_error());
$queryresult = mysql_query($pQuery) or die(mysql_error());
mysql_close($conn);
header ('location: http://www.numyspace.co.uk/~unn_v002018/webCaseProject/index.php');
?>
Firstly, never use SELECT * in some code: it will bite you (or whoever has to maintain this application) if the table structure changes (never say never).
You could consider using an INSERT that takes its values from a SELECT directly:
"INSERT INTO admin(userID, forename, ..., `password`, ...)
SELECT userID, forename, ..., `password`, ...
FROM jobseeker WHERE userID = ..."
You don't have to go via PHP to do this.
(Apologies for using an example above that relied on mysql_real_escape_string in an earlier version of this answer. Using mysql_real_escape_string is not a good idea, although it's probably marginally better than putting the parameter directly into the query string.)
I'm not sure which MySQL engine you're using, but your should consider doing those statements within a single transaction too (you would need InnoDB instead of MyISAM).
In addition, I would suggest using mysqli and prepared statements to be able to bind parameters: this is a much cleaner way not to have to escape the input values (so as to avoid SQL injection attacks).
EDIT 2:
(You might want to turn off the magic quotes if they're on.)
$userID = $_GET['userID'];
// Put the right connection parameters
$mysqli = new mysqli("localhost", "user", "password", "db");
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
// Use InnoDB for your MySQL DB for this, not MyISAM.
$mysqli->autocommit(FALSE);
$query = "INSERT INTO admin(`userID`, `forename`, `surname`, `salt`, `password`, `profilePicture`)"
." SELECT `userID`, `forename`, `surname`, `salt`, `password`, `profilePicture` "
." FROM jobseeker WHERE userID=?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param('i', (int) $userID);
$stmt->execute();
$stmt->close();
} else {
die($mysqli->error);
}
$query = "UPDATE user SET userType = 'admin' WHERE userID=?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param('i', (int) $userID);
$stmt->execute();
$stmt->close();
} else {
die($mysqli->error);
}
$query = "DELETE FROM jobseeker WHERE userID=?";
if ($stmt = $mysqli->prepare($query)) {
$stmt->bind_param('i', (int) $userID);
$stmt->execute();
$stmt->close();
} else {
die($mysqli->error);
}
$mysqli->commit();
$mysqli->close();
EDIT 3: I hadn't realised your userID was an int (but that's probably what it is since you've said it's auto-incremented in a comment): cast it to an int and/or don't use it as a string (i.e. with quotes) in WHERE userID = '$userID' (but again, don't ever insert your variable directly in a query, whether read from the DB or a request parameter).
There's nothing obviously wrong with your code (apart from it being insecure with using non-escaped values directly from $_GET).
I'd suggest you try the following in order to debug:
var_dump $userData to check that the values are as you expect
var_dump $rQuery and copy and paste it into phpMyAdmin to see if your query is not as you expect
If you don't find your problem then please post back your findings along with the structure of the tables you're dealing with
So here is the deal. I have looked around everywhere, and all other techniques relate to refreshing the browser, and methods to prevent the php page from resubmitting the post data. I am new to this (obviously :p) But anyways, my questions I believe is simple. I just want a method, possibly an if else statement that would check the post data entries, and if there is a match already in my table, than do not execute the query. I am not worried about querying all of the results of the table, as I only suspect this table will ever have 50-60 entries.
Here is the php page that handles the form submission:
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$email = $_POST['email'];
$city = $_POST['city'];
$state = $_POST['state'];
$submitDate = date("Y-m-d");
mysql_connect ("localhost", "abc", "123") or die ('Error: ' . mysql_error());
mysql_select_db ("members");
$query = "INSERT INTO persons (ID, firstName, lastName, email, city, state, submitDate)VALUES (
'NULL',
'".$firstName."',
'".$lastName."',
'".$email."',
'".$city."',
'".$state."',
'".$submitDate."'
)";
mysql_query($query) or die ('Error Updating database');
echo "Database Updated With: " .$firstName ." " .$lastName ." " .$email ." " .$city ." " .$state;
mysql_close($con);
Sorry, cant ever seem to get my php to format correctly with those code braces. Anyways. just to re-iterate, looking for a way to maybe based on the first and last name. if those already exist, then do not allow the submission of the data. I have tried a few if then statements but i do not think I am getting the concept down of comparing the result to my query. I hope this all makes sense!!!
I would suggest adding a UNIQUE index on the columns you want to have unique.
You can just use INSERT IGNORE INTO ... and let MySQL handle it.
$query = "INSERT IGNORE INTO persons (ID, firstName, lastName, email, city, state, submitDate) VALUES (
'NULL',
'".$firstName."',
'".$lastName."',
'".$email."',
'".$city."',
'".$state."',
'".$submitDate."'
)";
Is your problem only that refreshing the page resends the POST data? The pretty much standard way to prevent that is to redirect the browser after having processed the form data, like so:
header('Location: ' . $_SERVER['PHP_SELF']);
Keep in mind, changing headers has to be done before any output is sent to the browser, so this should be above your doctype, and be sure there is no white space before either.
One way of doing this is to make sure your table has appropriate primary keys set (firstname and lastname at least), and then just trying the insert and seeing whether it fails on duplicate. You can check the error message using the mysql_error() function for this purpose.
You can do a select on the database with those two fields to check if a row already exists, but if this is something that needs to be unique there should also be a unique index on those two columns in your MySQL table.
I had this issue as well. Basically what I did is before the insert, do a select on the criteria that would qualify as a duplicate and check for it to return; if it does not we are ok to enter.
$query = "SELECT COUNT(id) AS mycount FROM persons WHERE firstName = '".$firstnName."' AND lastName = '".$lastName."'";
$result = mysql_query($query);
$row = mysql_fetch_array($result);
if($row['mycount'] == 0) {
//Do insert
}