Stop next index from increasing upon integrity violation - php

I've got the following method in my UserDAO class:
public function insert(Array $params)
{
$sql = 'INSERT INTO users (firstname, lastname, email, password, register_date) ';
$sql .= 'VALUES(:firstname, :lastname, :email, :password, FROM_UNIXTIME(:register_date))';
$sth = $this->pdo->prepare($sql);
$sth->bindValue(':firstname', $params['firstname'], \PDO::PARAM_STR);
$sth->bindValue(':lastname', $params['lastname'], \PDO::PARAM_STR);
$sth->bindValue(':email', $params['email'], \PDO::PARAM_STR);
$sth->bindValue(':password', $params['password'], \PDO::PARAM_STR);
$sth->bindValue(':register_date', $params['registerDate'], \PDO::PARAM_STR);
return $sth->execute();
}
I've got a UNIQUE constraint on my email column, so whenever I'm inserting a new record with a duplicate email, it will throw an exception. That works fine, but I noticed that it still increments the next primary key id number while nothing was inserted, so it actually gets skipped over.
How can I stop it from increasing in a case like that, so that I still get a consecutive increase of the index number? (Like 1, 2, 3, 4 instead of 1, 3, 5, 7, etc).

While it is not really an issue having a non-consecutive id column in a table, if you are concerned about the limit of the ids datatype you have a two realistic options.
Firstly simply SELECT check for the email's existence before the INSERT.
Or use something similar to this:
INSERT INTO users (firstname, lastname, email, password, register_date)
SELECT :firstname, :lastname, :email, :password, FROM_UNIXTIME(:register_date)
FROM dual
WHERE NOT EXISTS (SELECT 1 FROM users WHERE email = :email)
You can use the returned row count to check whether a row has been INSERTed.

Check if you've email in your database before send insert query.
//...
$sth = $this->pdo->prepare("SELECT count(*) FROM users WHERE email = ?");
$sth->execute(array($params['email']));
$rows = $sth->fetch(PDO::FETCH_NUM);
if ($rows[0]) {
return $sth->execute();
}
How to get the number of rows grouped by column?

Related

Last inserted ID of a table for another table in the same query?

I have a register, were people can register with their username, their email and a password. If this gets successfully transmitted to the database, this data will be inserted into a table called users. Now, I need the last ID from the just registered user for a second table that is called users_tokens, where I obviously want to save a token for every specific user. I've tried to solve this by using $mysql->insert_id; but that returns 0 in the table and I am also curious if this is a safe method since through my websites data gets inserted all the time.
My PHP Script:
$key = getToken(32);
$token = bin2hex(openssl_random_pseudo_bytes(64));
$stmt = $mysql->prepare("INSERT INTO users (name, email, password, verification_key, register_date) VALUES(?,?,?,?,?)");
$stmt->bind_param("sssss", $_POST["name"], $_POST["email"], md5($_POST["password"]), $key, $posted_on);
$lastid = $mysql->insert_id;
$u_token = $mysql->prepare("INSERT INTO users_tokens (uid, token) VALUES(?,?)");
$u_token->bind_param("ss", $lastid, $token);
Any suggestions?
You just need to execute your statement before retrieving insert_id, something like this
$stmt = $mysql->prepare("INSERT INTO users (name, email, password, verification_key, register_date) VALUES(?,?,?,?,?)");
$stmt->bind_param("sssss", $_POST["name"], $_POST["email"], md5($_POST["password"]), $key, $posted_on);
$stmt->execute(); //You should check for correct execution
$lastid = $mysql->insert_id;

Inserting values with a foreign key relationship into two different tables simultaneously? (MySQL)

So I have 2 tables:
users with columns id (primary, auto_increment), username, password, person_id (foreign key)
people with columns id (primary, auto_increment), first_name, last_name
What I'm trying to do is when registering a new account have a new row inserted into people and then have a new row inserted into users with the people.id as foreign key users.person_id.
Right now I have 2 php functions that get executed right after eachother, firstly one with this query:
insert into people (first_name, last_name) values (:firstname,
:lastname)
Secondly one with this query:
insert into users (username, password, person_id) values (:user,
:pass, LAST_INSERT_ID())
All of this works fine except for the fact that last_insert_id() keeps giving value 0 instead of the id from the previous query. Is it maybe not possible to use last_insert_id() when using 2 separate queries? If so what would be the best way to go about it then?
This is my relevant php code:
//make new person
$newPerson = new PeopleManagement();
$pm = $newPerson->createNewPerson($_POST["firstName"], $_POST["lastName"]);
//make new user
$newUsr = new Authentication();
$ac = $newUsr->registerNewUser($_POST["user"], $_POST["pass"]);
public function registerNewUser ($user, $pass) {
try {
$dbm = new PDO(DBCONFIG::$db_conn, DBCONFIG::$db_user, DBCONFIG::$db_pass);
$dbm->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$dbm->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
hash = password_hash($pass, PASSWORD_DEFAULT);
$sql = "insert into users (username, password, person_id) values (:user, :pass, LAST_INSERT_ID())";
$stmt = $dbm->prepare($sql);
$stmt->execute(array(
':user' => $user,
':pass' => $hash
));
$dbm = null;
} catch(PDOException $ex) {
return "Could not connect to database";
}
}
public function createNewPerson($firstName, $lastName) {
$dbm = new PDO($this->dbConn, $this->dbUser, $this->dbPass);
$sql = "insert into people (first_name, last_name) values (:firstname, :lastname)";
$stmt = $dbm->prepare($sql);
$stmt->execute(array(
':firstname' => $firstName,
':lastname' => $lastName
));
$dbm = null;
}

PHP MySQLi prepared statement not inserting data into table

I am designing a website with user login and registration with email verification, and when the user registers an account, it will successfully, and correctly, insert the user record into the database in the "users" table.
But when I try to pull the users id that is created when inserted to insert them into a second table for a roster of all members of the site (this is for a gaming clan), it inserts the user id as 0 in the roster table, regardless of what their id is on the "users" table for that user.
heres my code:
if($insert_stmt = $db->prepare("INSERT INTO users (username, password, email, date, actcode) VALUES (?, ?, ?, ?, ?)"))
{
$insert_stmt->bind_param('sssss', $username, $password, $email, $date, $actcode);
$stmt = $db->prepare("SELECT id FROM users WHERE email = ?");
if($stmt)
{
$stmt->bind_param('s', $email);
$stmt->execute();
$stmt->fetch();
$stmt->store_result();
$stmt->bind_result($ui);
}
$stmt = $db->prepare("INSERT INTO roster (userid, joindate) VALUES (?, ?)");
if($stmt)
{
$stmt->bind_param('ss', $ui, $date);
$stmt->execute();
}
if(!$insert_stmt->execute()) {
header('Location: error.php?err=Registration failure: INSERT');
}
}
for security reasons I have left certain variables and sections of the code omitted that do not have any bearing on this section causing me a headache.
I can't figure out why it is not inserting the newly creating "id" from "users" for that user account into the "roster" table under the "userid" column.
Also, just to test something, I also went and set a session variable
$_SESSION['uid'] = $ui;
directly after the line
$stmt->store_result($ui);
and echoed it on my index.php file, and it shows the session variable as 0 as well.
You could simply use this function: mysqli::$insert_id instead of writing your second query.
Replace this line:
$stmt = $db->prepare("SELECT id FROM users WHERE email = ?");
With:
$userid = $db->insert_id;
Let me know if this works.
Still wasn't able to get it to work with the the solutions provided, but decided to just merge everything into the users table, which fixed the issue. As far as checking if it is executing, I am putting in some checks to make sure it goes through. Thanks for the help and advise.

PDO bindValue an empty string in codeigniter

I'm running an insert query to insert user information into the database.
The fields to insert are username and email, and the email field is not mandatory.
The query run fine when the input includes the email, but when I entered nothing in the email, the PDO error always reports the error " Duplicate entry '' for key 'email' " .
$post = $this->input->post();
$sql = "INSERT INTO users (username, email) VALUES (:username, :email)";
$query = $this->db->conn_id->prepare($sql);
$query->bindValue (':username', $post['username'], PDO::PARAM_STR);
if ($email == false){
$query->bindValue(':email', '', PDO::PARAM_STR );
} else {
$query->bindValue(':email', $post['email'], PDO::PARAM_STR );
}
$query->execute();
First, as I mentioned in the comment, you need to set the email column to allow for null values. If you are not requiring an email address, then it is better to store a non-email as null rather than an empty string - but in this case it is necessary because the column is unique.
Then, try this code:
$post = $this->input->post();
if (!$post['email']){
$post['email'] = NULL;
}
$sql = "INSERT INTO users (username, email) VALUES (:username, :email)";
$query = $this->db->conn_id->prepare($sql);
$query->execute(array($post['username'], $post['email']));

Searching a file and storing it in a variable php

I have a text file that goes like this
1 wordsgohere
2 morewordsgohere
3 yougetthepoint
I want to assign one of the strings above to the user_id of that person. So say you are the third person to register, your user_id is 3 and your deposit_id would be 'yougetthepoint'. However when I echo user_id it's always 0 even though there are 2 or three users in the database and when looking at the database the id number increases. It won't put the user in the data base either. If I replace deposit_id with something else it will put the user in the data base. I think it's because new_str never gets defined.
// id of new user
$user_id = $this->db_connection->lastInsertId();
echo $user_id;
// searches text file for address
$lines_array = file("test.txt");
foreach($lines_array as $line) {
echo $line;
if(strpos($line, $user_id) != false) {
list(, $new_str) = explode($user_id, $line);
}
}
// write new users data into database
$query_new_user_insert = $this->db_connection->prepare('INSERT INTO users (deposit_id, user_name, user_password_hash, user_email, user_activation_hash, user_registration_ip, user_registration_datetime) VALUES(:deposit_id, :user_name, :user_password_hash, :user_email, :user_activation_hash, :user_registration_ip, now())');
$query_new_user_insert->bindValue(':deposit_id', $new_str, PDO::PARAM_STR);
$query_new_user_insert->bindValue(':user_name', $user_name, PDO::PARAM_STR);
$query_new_user_insert->bindValue(':user_password_hash', $user_password_hash, PDO::PARAM_STR);
$query_new_user_insert->bindValue(':user_email', $user_email, PDO::PARAM_STR);
$query_new_user_insert->bindValue(':user_activation_hash', $user_activation_hash, PDO::PARAM_STR);
$query_new_user_insert->bindValue(':user_registration_ip', $_SERVER['REMOTE_ADDR'], PDO::PARAM_STR);
$query_new_user_insert->execute();
Any help would be great, thanks.
As some people mention in your comments you should check the order of the statements.
First you insert the row into your database. On execute the Database will generate the ID which u can retrieve afterwards.
Now you want to add the Deposit_id to the generated entry. Just Update the Entry (UPDATE users SET deposit_id=:deposit_id WHERE user_id=:user_id;).
But I think you will get a result, which you don't want.
Is the number in the textfile really the user_id? or just an enumeration? you could just parse it and create an array containing the deposit_ids in the order of the file. Now your can Insert all rows by running one insert per array-entry

Categories