Using one ? to contain several variables in PHP MySQLi prepared INSERT statement - php

Trying to get to grips with prepared statements for an INSERT query. This is supposed to add a new user to the database:
$statement = $mysqli->prepare("INSERT INTO users (email,passwordhash) VALUES (?)");
$statement->bind_param('s', "'$email','$passwordhash'");
$statement->execute();
Is it correct to use a single ? and fill it with two values in that way?

The way mysqli doing that you need to bind all the variables separately
$statement = $mysqli->prepare("INSERT INTO users (email,passwordhash) VALUES (?,?)");
$statement->bind_param('ss', $email,$passwordhash);
$statement->execute();
But if you want it your way (say, you have an array ready and want to insert it using one placeholder) you need a helper class which will translate a custom placeholder into correct SQL statement:
$data = array('email'=>$email, 'passwordhash'=>$passwordhash);
$db->query("INSERT INTO users SET ?u");
and it will be shorter than raw mysqli yet will do much more - error handling, profiling and such.
Also keep in mind that when you will have a variable number of fields to insert, mysqli will turned to be a nightmare.

In prepared statements, each ? is used to replace one value.
When executed, your query will be:
INSERT INTO users (email,passwordhash) VALUES ("'email','password'")
That's not what you want. You need to use 2 ?s, one for each value.
$statement = $mysqli->prepare("INSERT INTO users (email,passwordhash) VALUES (?,?)");
// Pass each variable as a separate parameter
$statement->bind_param('ss', $email, $passwordhash);
$statement->execute();

Should be like this.
$statement = $mysqli->prepare("INSERT INTO users (email,passwordhash) VALUES (?,?)");
$statement->bind_param('ss', $email,$passwordhash);
$statement->execute();

Related

How to use PHP prepare with zillions of fields of different types

I am inserting data that has VARCHAR, TIMESTAMP and DECIMAL kinds using prepare.
The data is already in the format needed by mySQL.
My problem is this. Suppose I had only 2 items to insert. I would do like this:
$stmt = $mysqli->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
$stmt->bind_param("si", $_POST['name'], $_POST['age']);
My problem is the bind part. How do I do the bind when I have to insert 40 columns at once?
I can deal with the prepare part by doing this:
$sql = "INSERT INTO customers ($columns) VALUES ($values)";
$stmt = $mysqli->prepare($sql);
But the next line will result in a ridiculous long line, impossible to understand and very easy to go wrong.
$stmt->bind_param("ssssiidisisssiidiisssidiisidi", ....);
I don't see how I could build that in a loop for example.
How do I do that?
You can pass an array to the mysqli_stmt::bind_param() function as variable arguments with the ... syntax, introduced in PHP 5.6.
$params = ['name', 42];
$stmt = $mysqli->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
$stmt->bind_param(str_repeat('s', count($params)), ...$params);
$stmt->execute();
You don't really need to set the data type individually for each column. You can treat them all as 's'.
I know you're asking about mysqli, but I'll just point out that this is easier with PDO:
$params = ['name', 42];
$stmt = $pdo->prepare("INSERT INTO myTable (name, age) VALUES (?, ?)");
$stmt->execute($params);

Transactions with PDO and prep. statements

I need to insert to two tables and I tried transactions. It works well:
$nom = "Nrc";
$contrasenya = "somePassword";
$conn->beginTransaction();
$conn->exec("INSERT INTO usuari (nom, contrasenya)
VALUES ('$nom', '$contrasenya')");
$conn->exec("INSERT INTO well (puntuacio, text)
VALUES ('9', 'some text2')");
$conn->commit();
echo "New records created successfully";
Now I want to introduce prep. statements for security. I am not sure how to do that. This is what I tried. It gives me no error, but it does not insert in any table either:
$nom = "Nrc";
$contrasenya = "somePassword";
$conn->beginTransaction();
$stmt = $conn->prepare("INSERT INTO usuari (nom, contrasenya)
VALUES (:nom, :contrasenya)");
$stmt = $conn->prepare("INSERT INTO well (puntuacio, text)
VALUES ('9', 'some text2')");
$stmt->bindParam(':nom', $nom);
$stmt->bindParam(':contrasenya', $contrasenya);
$conn->commit();
echo "New records created successfully";
There are several issues with your code:
You never execute the statement.
You overwrite your statement ($stmt) with the statement using the values directly. So you don't use the correct prepared statement.
You can use the following code to INSERT the values to the tables:
//start the transaction.
$conn->beginTransaction();
//the variables of the first statement.
$nom = 'Nrc';
$contrasenya = 'somePassword';
//prepare the first statement, bind the values and execute.
$stmt = $conn->prepare("INSERT INTO usuari (nom, contrasenya) VALUES (:nom, :contrasenya)");
$stmt->bindParam(':nom', $nom);
$stmt->bindParam(':contrasenya', $contrasenya); //TODO - use hashing here!
//... or solution without variable.
//$stmt->bindValue(':nom', 'Nrc');
//$stmt->bindValue(':contrasenya', 'somePassword');
$stmt->execute();
//the variables of the second statement.
$puntuacio = '9';
$text = 'some text2';
//prepare the second statement, bind the values and execute.
$stmt = $conn->prepare("INSERT INTO well (puntuacio, text) VALUES (:puntuacio, :text)");
$stmt->bindParam(':puntuacio', $puntuacio);
$stmt->bindParam(':text', $text);
//... or solution without variable.
//$stmt->bindValue(':puntuacio', '9');
//$stmt->bindValue(':text', 'some text2');
$stmt->execute();
//commit all changes of the transaction.
$conn->commit();
Note: As already others mentioned, you should also hash your passwords.
From php.net:
Unlike PDOStatement::bindValue(), the variable is bound as a reference and will only be evaluated at the time that PDOStatement::execute() is called.
For password insertion you should use password() function shiped with PHP.
You shouldn't insert direct data directly in prepare statement, as you did for the first one
$stmt = $conn->prepare("INSERT INTO well (puntuacio, text)
VALUES (:number, :some_text)");
$stmt->bindParam(':number', $num);
$stmt->bindParam(':some_text', $text);
You should execute(); your prepared statement in order to execute your query insertion.
Plus as said previously you overwrite your $stmt variable before you can execute your query.

MySQL - Number of variables doesn't match number of parameters in prepared statement

So i have the query below which runs perfectly, but I get the error in the title and I don't understand why. Maybe someone can help.
Query:
$stmt = $mysqli->prepare("INSERT INTO paypal_log (product_name) VALUES ('".$_POST["product_name"]."')");
$stmt->bind_param('s', $product_name);
$stmt->execute();
$stmt->close();
Error:
PHP Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in /home/triponsergiu/public_html/test/includes/paypal.php on line 29
Thank you.
Binding parameters to statements means filling in a parameter in the statement that was left 'blank'. To create a 'blank', replace a value with, for example, a question mark.
$stmt = $mysqli->prepare('INSERT INTO paypal_log (product_name) VALUES (?)');
$stmt->bind_param('s', $product_name);
$stmt->execute();
$stmt->close();
This way, the parameter is automatically escaped (so they can't delete or download your entire database...).
$stmt = $mysqli->prepare("INSERT INTO paypal_log (product_name) VALUES (?)");
$stmt->bind_param('s', $_POST["product_name"]);
Consult the manual on prepared statements.

prepared INSERT statement to get insert_id to use in a second prepared INSERT statement

Im trying to create my own register form but im having issues with prepared statements.
the idea is to create a prepared statement to insert info into the user table, then from that get the insert_id from the generated content to use in another insert statement
here is a version of my register script
<?php
$returnedId = '';
include "includes/dbconnect.php";
$stmt = $db->prepare("INSERT INTO `users`(`Username`, `Email`, `Password`) VALUES (?, ?, ?)");
$stmt->bind_param('sss', $_POST['username'], $_POST['email'], $_POST['password']);
$stmt->execute();
$returnedId = $stmt->insert_id;
$stmt->close();
echo $returnedId;
$allergystmt = $db->prepare("INSERT INTO 'user_allergy' ('user_id', 'allergy_id') VALUES (?, ?)");
$allergystmt->bind_param('ss', $returnedId, $_POST['check_list']);
$allergystmt->execute();
$allergystmt->close();
header('Location: index.php');
?>
the first prepared statement runs correctly and inserts information into the table, after that the $returnId variable is successfully echoed. next in the script is my second prepared statement, when it tries to run im getting the error that says:
Fatal error: Call to a member function bind_param() on a non-object in D:\filepath\register.php on line 17
it seems that my variable isnt being carried into the second prepared statement.
Your second query has syntax errors and failed to prepare. Since you have no error handling for database failures like this, your later code just blunders onwards:
$allergystmt = $db->prepare("INSERT INTO 'user_allergy' ('user_id', 'allergy_id') VALUES (?, ?)");
^--- ^--^--- ^-- etc...
You cannot use ' quotes on table and field names. ' indicate strings. None of those field/table names are reserved words, so there is NO need to quote them at at all:
$allergystmt = $db->prepare("INSERT INTO user_allergy (user_id, allergy_id) VALUES (?, ?)");
if (!$allergystmt) { die($dbh->errorInfo()); }
Note the addition of the errorInfo() output. Never assume a DB operation was successful. Always assume failure, and treat success as a pleasant surprise.

inserting data from a form into your mysql database using php

i used this code
<?php
$conn = new PDO("mysql:host=localhost;dbname=CU4726629",'CU4726629','CU4726629');
$sql="INSERT INTO review (username, movie_name, ratings) VALUES ("$_POST['username']","$_POST['moviename']","$_POST['ratings']")";
header('Location: reviews.php');
?>
but it keeps giving me this error
Parse error: syntax error, unexpected T_VARIABLE in
/home/4726629/public_html/check_login.php on line 5
Take this for an example:
<?php
// insert some data using a prepared statement
$stmt = $dbh->prepare("insert into test (name, value) values (:name, :value)");
// bind php variables to the named placeholders in the query
// they are both strings that will not be more than 64 chars long
$stmt->bindParam(':name', $name, PDO_PARAM_STR, 64);
$stmt->bindParam(':value', $value, PDO_PARAM_STR, 64);
// insert a record
$name = 'Foo';
$value = 'Bar';
$stmt->execute();
// and another
$name = 'Fu';
$value = 'Ba';
$stmt->execute();
// more if you like, but we're done
$stmt = null;
?>
You just wrote a string in your above code:
$sql="INSERT INTO review (username, movie_name, ratings) VALUES ("$_POST['username']","$_POST['moviename']","$_POST['ratings']")";
Above answers are correct, you will need to concat the strings to form a valid sql query. you can echo your $sql variable to check what is to be executed and if is valid sql query or not. you might want to look in to escaping variables you will be using in your sql queries else your app will be vulnerable to sql injections attacks.
look in to
http://php.net/manual/en/pdo.quote.php
http://www.php.net/manual/en/pdo.prepare.php
Also you will need to query you prepared sql statement.
look in to http://www.php.net/manual/en/pdo.query.php
A couple of errors:
1) you have to concat the strings!
like this:
$sql="INSERT INTO review (username, movie_name, ratings)
VALUES (".$_POST['username'].",".$_POST['moviename'].",".$_POST['ratings'].")";
2) you are not using the PDO at all:
after you create the "insert" string you must query the db itself, something like using
$conn->query($sql);
nb: it is pseudocode
3) the main problem is that this approach is wrong.
constructing the queries in this way lead to many security problems.
Eg: what if I put "moviename" as "; drop table review;" ??? It will destroy your db.
So my advice is to use prepared statement:
$sql="INSERT INTO review (username, movie_name, ratings)
VALUES (?,?,?)";
$q = $conn->prepare($sql);
$fill_array = array($_POST['username'], $_POST['moviename'], $_POST['ratings']);
$q->execute($fill_array);
You forgot dots:
$sql="INSERT INTO review (username, movie_name, ratings)
VALUES (".$_POST['username'].",".$_POST['moviename'].",".$_POST['ratings'].")";
and fot the future for now your variables are not escaped so code is not secure
String in a SQL-Statment need ', only integer or float don't need this.
$sql="INSERT INTO review (username, movie_name, ratings) VALUES ('".$_POST['username']."','".$_POST['moviename']."','".$_POST['ratings']."')";

Categories