I want to insert some data into a table using PDO. I looked for some examples and I found that I need to use the functions prepare, bind and then execute, however I can not figure out in my code what I am doing wrong because it inserted nothing and I have no error in the query or php code.
if($_POST){
$account = $_POST['account'];
$password = $_POST['password'];
$phone = $_POST['phone'];
$email = $_POST['email'];
$stmt = 'INSERT INTO employer(account, password, phone, email) VALUES(:account, :password, :phone, :email)';
$stmt = $conn->prepare($stmt);
$stmt->bindParam(':account', $account, PDO::PARAM_STR,100);
$stmt->bindParam(':password',$password, PDO::PARAM_STR,100);
$stmt->bindParam(':phone', $phone, PDO::PARAM_STR,100);
$stmt->bindParam(':email', $email, PDO::PARAM_STR,100);
if ($stmt->execute(array('account' => $account,
'password' => $password,
'phone' => $phone,
'email' =>$email
)
)
){
echo "success";
}else{
echo "error";
}
}
Error detected by #jeroen I was binding twice. So I can bind "either bind before the execute statement or send an array as a parameter, not both"
$stmt = $pdo->prepare('
INSERT INTO employer
(account, password, phone, mail)
values (:account, :password, :phone, :mail)');
$stmt->execute(
array(':account' => $account,
':password' => md5($password),
':phone' => $phone,
':mail' => $email
)
);
if ($pdo->lastInsertId())
return true;
else
return false;
Related
I have a basic login page that uses this PHP code to upload directly to my database. When I use this code it works fine and it uploads everything to my table:
$fname = $_POST['fname'];
$lname = $_POST['lname'];
$Email = $_POST['Email'];
$username = $_POST['username'];
$password = ($_POST['password']);
$PhoneNumber = ($_POST['PhoneNumber']);
$query = $con-> prepare("
INSERT INTO Users (fName, lName,Email, username, pass_word,PhoneNumber)
VALUES (:fname, :lname, :Email, :username,:password, :PhoneNumber)
");
$success = $query-> execute ([
'fname' => $fname,
'lname' => $lname,
'Email' => $Email,
'username' => $username,
'password' => $password,
'PhoneNumber' => $PhoneNumber
]);
But when i add the hash password function it just doesnt upload anything to the database at all.
$fname = $_POST['fname'];
$lname = $_POST['lname'];
$Email = $_POST['Email'];
$username = $_POST['username'];
$password = ($_POST['password']);
$PhoneNumber = ($_POST['PhoneNumber']);
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
$query = $con-> prepare("
INSERT INTO Users (fName, lName,Email, username, pass_word,PhoneNumber)
VALUES (:fname, :lname, :Email, :username,:password, :PhoneNumber)
");
$success = $query-> execute ([
'fname' => $fname,
'lname' => $lname,
'Email' => $Email,
'username' => $username,
'password' => $hashed_password,
'PhoneNumber' => $PhoneNumber
]);
Update:
I made the changes that were suggested but I am still having the same issue. This is my updated code:
$password = $_POST['password'];
$hashed_password = password_hash($_POST['password'], PASSWORD_BCRYPT, ['cost' => 15]);
$query = $con-> prepare("
INSERT INTO Users (fName, lName,Email, username, pass_word,PhoneNumber)
VALUES (:fname, :lname, :Email, :username,:password, :PhoneNumber)
");
$success = $query-> execute ([
'fname' => $fname,
'lname' => $lname,
'Email' => $Email,
'username' => $username,
'password' => $hashed_password,
'PhoneNumber' => $PhoneNumber
]);
1:
$hashed_password = password_hash($hashed_password, PASSWORD_DEFAULT);
You are hashing an empty string.
You should be hashing the variable containing the password:
$hashed_password = password_hash($_POST['password'], PASSWORD_DEFAULT);
2:
Your SQL query should not contain any variables, this is bad practise and potentially unsafe (for other non-hashed variables).
VALUES (:fname, :lname, :Email, :username,$hashed_password, :PhoneNumber)
But you have $hashed_password as a hardcoded variable. This is incorrect on a syntax level and will cause SQL errors as it's not encased in quotes.
You need to set this value in the ->execute as you do with all the other variables:
$query = $con-> prepare("
INSERT INTO Users (fName, lName,Email, username, pass_word,PhoneNumber)
VALUES (:fname, :lname, :Email, :username, :pwd, :PhoneNumber)
");
$success = $query-> execute ([
'fname' => $fname,
'lname' => $lname,
'Email' => $Email,
'username' => $username,
'pwd' => $hashed_password,
'PhoneNumber' => $PhoneNumber
]);
SECURITY NOTES:
A:
You are not setting a cost value on your PASSWORD_DEFAULT (at time of writing this is BCRYPT) hashing mechanism. It is STRONGLY ENCOURAGED that you set this cost value to as high as possible, rather than the default of 10.
I would suggest setting the cost value to at least 15, and reading the PHP Manual Page, which also sets out how to find the ideal cost value of your server.
$hashed_password = password_hash($password, PASSWORD_BCRYPT, ['cost' => 15]);
B:
I would also highly recommend using one of the ARGON password hashing mechanisms. You will need to recompile PHP with this enabled. I'm sure this will be made easier in coming PHP versions.
C:
I would also highly recommend ensuring your MySQL collations and character sets are UTF8mb4_ prefixed unicode: UTF8mb4_unicode_ci with respect to your password storage column/table (Also ensure your column is long enough*).
* that's what she said!
I'm a newbie with PHP. I am trying to create a log in /register system for a project, so I am using a login system source code I found which has many functions and features like salted passwords. The system itself works fine, but I am trying to add more fields to my MySQL Table. The system had an array for extra columns, but I think it was resulting in bad mysql syntax so I decided to write out the query myself using the variables, but I am not sure how I can give access to the variables to the function. The variables are in the register.php document, here is the code (all of register.php):
if( isset($_POST['submit']) ){
$firstname = $_POST['firstname'];
$lastname = $_POST['lastname'];
$user = $_POST['username'];
$sex = $_POST['sex'];
$country = $_POST['strCountryChoice'];
$email = $_POST['email'];
$pass = $_POST['pass'];
$pass2 = $_POST['pass2'];
$birthdate = $_POST['birthdate'];
$created = date("Y-m-d H:i:s");
//need to add a lot more validation functions.. AKA Check if email exists and username. Password > 5 chars
if( $user=="" || $email=="" || $pass=='' || $pass2=='' || $firstname=='' || $lastname='' || $sex='' || $country='' || $birthdate='' ){
echo "Fields Left Blank","Some Fields were left blank. Please fill up all fields.";
exit;
}
if( !$LS->validEmail($email) ){
echo "E-Mail Is Not Valid", "The E-Mail you gave is not valid";
exit;
}
if( !ctype_alnum($user) ){
echo "Invalid Username", "The Username is not valid. Only ALPHANUMERIC characters are allowed and shouldn't exceed 10 characters.";
exit;
}
if($pass != $pass2){
echo "Passwords Don't Match","The Passwords you entered didn't match";
exit;
}
$createAccount = $LS->register($user, $pass,
array(
"email" => $email,
"name" => $firstname,
"lastname" => $lastname,
"gender" => $sex,
"country" => $country,
"DOB" => $birthdate,
"created" => date("Y-m-d H:i:s") // Just for testing
)
);
if($createAccount === "exists"){
echo "User Exists.";
}elseif($createAccount === true){
echo "Success. Created account.";
}
}
The whole system takes place in another file which has the class. Here is the register function:
public function register( $id, $password, $other = array() ){
if( $this->userExists($id) && (isset($other['email']) && $this->userExists($other['email'])) ){
return "exists";
}else{
$randomSalt = $this->rand_string(20);
$saltedPass = hash('sha256', "{$password}{$this->passwordSalt}{$randomSalt}");
if( count($other) == 0 ){
/* If there is no other fields mentioned, make the default query */
//old query: ("INSERT INTO `{$this->dbtable}` (`username`, `password`, `password_salt`) VALUES(:username, :password, :passwordSalt)");
//new query: ("INSERT INTO `{$this->dbtable}` (`username`, 'email' , `password`, `password_salt` , 'name' , 'lastname' , 'gender' , 'country' , 'DOB') VALUES(:username, :email, :pass, :passwordSalt, :firstname, :lastname, :gender, :country, :DOB)");
$sql = $this->dbh->prepare("INSERT INTO `{$this->dbtable}` (`username`, `password`, `password_salt`) VALUES(:username, :password, :passwordSalt)");
}else{
/* if there are other fields to add value to, make the query and bind values according to it */
//old query: ("INSERT INTO `{$this->dbtable}` (`username`, `password`, `password_salt`, $columns) VALUES(:username, :password, :passwordSalt, :$colVals)");
//new query: ("INSERT INTO `{$this->dbtable}` (`username`, 'email' , `password`, `password_salt` , 'name' , 'lastname' , 'gender' , 'country' , 'DOB') VALUES(:username, :email, :pass, :passwordSalt, :firstname, :lastname, :gender, :country, :DOB)");
$keys = array_keys($other);
$columns = implode(",", $keys);
$colVals = implode(",:", $keys);
//l= $this->dbh->prepare("INSERT INTO `{$this->dbtable}` (`username`, `password`, `password_salt`, $columns) VALUES(:username, :password, :passwordSalt, :$colVals)");
//INSERT INTO MyGuests (firstname, lastname, email)cLUES ('John', 'Doe', 'john#example.com')
$sql = $this->dbh->prepare("INSERT INTO `{$this->dbtable}` (username,email,password,password_salt,name,lastname,created,gender,country,DOB) VALUES ('$username','$email','$pass','$saltedPass','$firstname','$lastname','$created','$gender','$country','$birthdate')");
print($sql);
foreach($other as $key => $value){
$value = htmlspecialchars($value);
$sql->bindValue(":$key", $value);
}
}
/* Bind the default values */
$sql->bindValue(":username", $id);
$sql->bindValue(":password", $saltedPass);
$sql->bindValue(":passwordSalt", $randomSalt);
$sql->execute();
return true;
}
}
So I need to use the variables from register.php in the class file. Can I just include it at the top or do I need to do something specific to the function?
Thanks. I'm focusing on the $sql line after else.
Yes you can include/require register.php file in the class file to use all the variables.
On another note i would like to mention that you should always filter out the POST data before adding it to the query for security concerns.
I have been learning about making an authentication system more secure. One of the problems with my code is that it is vulnerable to a Time of check to time of use bug. Here is my code:
$stmt = $connection->prepare("SELECT username, password, email FROM users WHERE username=:username");
$stmt->execute(array(':username' => $username));
$rows = $stmt->fetch(PDO::FETCH_ASSOC);
if ($rows != null) {
$_SESSION["message"] = "name already exists";
} else {
$stmt = $connection->prepare("INSERT INTO users(company, username, password, first_name, last_name, address, address2, city, state, zip, phone, email) VALUES (:company, :username, :password, :first_name, :last_name, :address, :address2, :city, :state, :zip, :phone, :email)");
$result = $stmt->execute(array(':company' => $company, ':username' => $username, ':password' => $hashed_password, ':first_name' => $firstName, ':last_name' => $lastName, ':address' => $address1, ':address2' => $address2, ':city' => $city, ':state' => $states, ':zip' => $zip, ':phone' => $phone, ':email' => $email));
if ($result) {
// Success
$_SESSION["message"] = "You've successfully registered.";
redirect_to("login.php");
} else {
// Failure
$_SESSION["message"] = "Registration failed.";
}
}
}
} else {
// This is probably a GET request
}
So, it is first seeing if the user exists and if not, then to go ahead and insert the user's information into the database. But this creates a vulnerability for TOCTTOU. To fix this, I made the 'username' column UNIQUE. Is this the only thing I need to do? Is there a way to combine these two statements so it isn't vulnerable to that type of attack?
I've been reading resources on this and it seems making the column UNIQUE or PRIMARY is the best option. But, I don't want to rely on the database. Any suggestions? Thanks!
Here is my fixed code:
At top of file:
ini_set('display_errors', 'On'); error_reporting(E_ALL);
Then:
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$connection->beginTransaction();
try {
$stmt = $connection->prepare('SELECT 1 FROM users WHERE username = :username LIMIT 1');
$stmt->execute([':username' => $username]);
$check = $stmt->fetchColumn();
if ($check) {
$_SESSION["message"] = "name already exists";
} else {
$stmt = $connection->prepare('INSERT INTO users(company, username, password, first_name, last_name, address, address2, city, state, zip, phone, email) VALUES (:company, :username, :password, :first_name, :last_name, :address, :address2, :city, :state, :zip, :phone, :email)');
$stmt->execute(array(':company' => $company, ':username' => $username, ':password' => $hashed_password, ':first_name' => $firstName, ':last_name' => $lastName, ':address' => $address1, ':address2' => $address2, ':city' => $city, ':state' => $states, ':zip' => $zip, ':phone' => $phone, ':email' => $email)); // this should throw an exception if it fails, no need to check the return value
$_SESSION["message"] = "You've successfully registered.";
}
$connection->commit();
redirect_to("login.php");
} catch (PDOException $e) {
$connection->rollBack();
throw $e;
}
I would maintain the unique constraint on your table as that makes sense from a data perspective.
For your PHP code, simply use transactions. For example...
// make sure you have $connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)
$connection->beginTransaction();
try {
$stmt = $connection->prepare('SELECT 1 FROM users WHERE username = :username LIMIT 1');
$stmt->execute([':username' => $username]);
$check = $stmt->fetchColumn();
if ($check) {
$_SESSION["message"] = "name already exists";
} else {
$stmt = $connection->prepare('INSERT INTO ...');
$stmt->execute([...]); // this should throw an exception if it fails, no need to check the return value
$_SESSION["message"] = "You've successfully registered.";
}
$connection->commit();
redirect_to("login.php");
} catch (PDOException $e) {
$connection->rollBack();
throw $e;
}
I can not figure out why it is breaking after passing validation and not submitting to database. Just comes up with blank screen. I have echoed out the new_password and it is encrypting it properly. Am I missing something? or doing something wrong? Any help/advice is appreciated. thanks in advance.
if (isset($_POST['register'])){
//Validation and post variable stuff here but doesn't appear to be any issue with it as I have tested it alot.
}
else if(!$error_msg && !$returned_record && $_POST['register']){
function generateHash($password_1){
if(defined("CRYPT_BLOWFISH") && CRYPT_BLOWFISH){
//echo "WE HAVE CRYPT BLOWFISH";
$salt = '$2y$11$'. substr(md5(uniqid(rand(), true)), 0, 22);
return crypt($password_1, $salt);
}//End If
}//End Function generateHash();
$new_password = generateHash($password_1);
//Build our query
$sql = ("INSERT INTO members (username, email, first_name, last_name, country, password_1) VALUES (?,?,?,?,?,?)");
//Prepare our query
$stmt = $mysqli->prepare($sql) or die("PREPARE DIDNT WORK");;
//Bind the fields and there parameters to our query
$stmt->bind_param('ssssss', $username, $email, $first_name, $last_name, $country, $new_password);
//Execute the query
$stmt->execute();
header('Location: http://someurl.com');
exit();
}
Instead of binding the parameters, try this:
$sql = ("INSERT INTO members (username, email, first_name, last_name, country, password_1) VALUES (:username, :email, $first_name, :last_name, :country, :password_1)");
$stmt = $mysqli->prepare($sql) or die("Failed Execution");;
$stmt->execute(array(
':username' => $username,
':email' => $email,
':first_name' => $fname,
':last_name' => $lname,
':country' $country,
':password_1' $password
));
I think i have figured out. I was trying to implement this code into a wordpress template page with a custom loop. I removed all loop/functions and It worked first try. So something in there was causing the issues. Thanks for trying!
hi i have a table in mysql have six fields
ID, mobileNumber, firstName, lastName, email, password , rollID
ID is autoincrement and i want to insert to it using php
php code
public function run($firstName, $lastName, $mobileNumber, $email, $password, $rePassword) {
if (!$this->db->isExistedMobile($mobileNumber)) {
try {
$query = "INSERT INTO user (firstName, lastName, mobileNumber, email, password, rollID)
VALUES (:firstName, :lastName, :mobileNumber, :email, :password, 'rollID')";
$sth = $this->db->prepare($query);
$sth->execute(array(
':firstName' => $firstName,
':lastName' => $lastName,
':mobileNumber' => $mobileNumber,
':email' => $email,
':password' => $password,
':rollID' => "roma"
));
header("location: " . URL . "index");
} catch (PDOException $e) {
die($e->getMessage());
exit;
}
} else {
include 'controlers/Error.php';
$error = new Error();
$error->index("you enterd a used mobile number");
}
}
i have this exception
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
the function isExistedMobile always return false so don't worry about it , i don't know where is the wrong , is it in the syntax ? or in the rollID cos i make it static ?
thank you for helping :)
The problem (with your original code) was that the parameter array had a trailing comma, which created an additional null element within it.
I'd recommend reverting to that version (with the literal value for rollID) as originally intended, but make sure you remove the trailing comma after $password:
public function run($firstName, $lastName, $mobileNumber, $email, $password, $rePassword) {
if (!$this->db->isExistedMobile($mobileNumber)) {
$query = "INSERT INTO user (firstName, lastName, mobileNumber, email, password, rollID)
VALUES (:firstName, :lastName, :mobileNumber, :email, :password, 'ddd')";
$sth = $this->db->prepare($query);
$sth->execute(array(
':firstName' => $firstName,
':lastName' => $lastName,
':mobileNumber' => $mobileNumber,
':email' => $email,
':password' => $password // , removed from here
));
header("location: " . URL . "index");
} else {
include 'controlers/Error.php';
$error = new Error();
$error->index("you enterd a used mobile number");
}
}