I am using the prepared statement for CRUD in PHP. My code snippet :
$SQL="INSERT INTO Dress(DressID, Description, Size, Price, EntryDate, CategoryID, ColorID)
VALUES (?, ?, ?, ?, ?, ?, ?)
ON DUPLICATE KEY UPDATE Description=?, Size=?, Price=?, EntryDate=?, CategoryID=?, ColorID=?";
$stmt=$connection->prepare($SQL);
$stmt->bind_param("ssssss", $ColorID, $Color, $Color);
Then, I have to repeat the variables binding in bind_param function, like bind_param("sssssssss", $var1, $var2, $var1, $var2, $var3..).
Is there any way to shorten this binding?
You can pass the parameters to the ->execute() method, like this:
$stmt->execute([123, 'red', 'green', ... ]);
If you keep the parameters in an array, instead of assigning them to variables, then binding them to the prepared statement can become rather trivial.
Related
Say I have this query:
$query = "INSERT INTO table(one, two, date) VALUES (1, 2, CURDATE())";
When rewritten for a prepared statement would it look like this?:
$query = "INSERT INTO table(one, two, date) VALUES (?, ?, CURDATE())";
OR
$query = "INSERT INTO table(one, two, date) VALUES (?, ?, ?)";
And on bind_param, leave out the MySQL function or include it?:
...
$stmt->bind_param('ii', 1, 2);
OR
$stmt->bind_param('iis', 1, 2, 'CURDATE()');
Iff you would bind function calls, that would mean any user input could be interpreted as a function. E.g.:
$stmt->bind_param('iis', 1, 2, 'CURDATE()');
$date = 'CURDATE()';
$stmt->bind_param('iis', 1, 2, $date);
$stmt->bind_param('iis', 1, 2, $someUserValue);
Which would be inherently insecure and the same as simple insecure string interpolation.
No, any bound parameter is some sort of primitive value, e.g. a string or integer or such. Never any structural part or code, which includes function calls. Remember, bind_param('s', 'CURDATE()') is equivalent to VALUES(..., 'CURDATE()'), not VALUES(..., CURDATE()).
I have a class in php that needs to send data from a form to a database. The query is split up in 2 queries bcs half the data needs to be send to an other table in the same database.
Now the problem: When I confirm the form then only the data of the sec query have been send to the database but not the data of the first query.
this is what I have:
(database connection) ...
if (something is empty)
{
Give error.
}
else {
$query = $this->db->prepare("INSERT INTO Table1(coloumn1, coloumn2, coloumn3, coloumn4, coloumn5, coloumn6, coloumn7, coloumn8) VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
$query->bindParam(1, $Val1);
$query->bindParam(2, $Val2);
$query->bindParam(3, $Val3);
$query->bindParam(4, $Val4);
$query->bindParam(5, $Val5);
$query->bindParam(6, $Val6);
$query->bindParam(7, $Val7);
$query->bindParam(8, $Val8);
$query->execute();
$query = $this->db->prepare("INSERT INTO Table2(coloumn1, coloumn2, coloumn3, coloumn4, coloumn5) VALUES(?, ?, ?, ?, ?)");
$query->bindParam(1, $Val1);
$query->bindParam(2, $Val9);
$query->bindParam(3, $Val10);
$query->bindParam(4, $Val11);
$query->bindParam(5, $Val12);
$query->execute();
}
What I have done:
checked database connection
checked table name
some error checks
trying to make a different function for the sec query (but then he
doesn't send anything anymore)
delete the sec query (but it still wont send the first query)
and ofc googling
I think i am doing something wrong with my first query but I don't know what.
Found it misspelled a column name (yes i did check it 2 times but still didn't saw it).
bind_param isn't supposed to be used the way you were using it for mysqli:
mysqli_stmt_bind_param documentation
The first parameters is a hint to PHP about what type of variable you are dealing with (i=>integer, s=> string, etc.)
You basically have to give ALL parameters in one line, using VARIABLES (you can't use constants).
--- SIDE NOTE: ADVANCED ---
If your code doesn't know how many parameters to pass at compile time, you might need to use:
call_user_func_array(array($query,'bind_param'), $all_prm );
where $all_prm is a an array of references to the values, first element being the types.
I believe you used the bind_param method in the wrong way. As stated in http://php.net/manual/en/mysqli-stmt.bind-param.php:
bool mysqli_stmt::bind_param ( string $types , mixed &$var1 [, mixed &$... ] )
So, assuming all your variables are integers, you could bind them in the following way:
$query->bind_param('iiiiiiii', $Val1, $Val2, $Val3, $Val4, $Val5, $Val6, $Val7, $Val8);
Here are the type specification chars:
'i': corresponding variable has type integer
'd': corresponding variable has type double
's': corresponding variable has type string
'b': corresponding variable is a blob and will be sent in packets
Therefore the solution I propose you is:
$query = $this->db->prepare("INSERT INTO Table1(coloumn1, coloumn2, coloumn3, coloumn4, coloumn5, coloumn6, coloumn7, coloumn8) VALUES(?, ?, ?, ?, ?, ?, ?, ?)");
$query->bind_param('iiiiiiii', $Val1, $Val2, $Val3, $Val4, $Val5, $Val6, $Val7, $Val8);
$query->execute();
$query = $this->db->prepare("INSERT INTO Table2(coloumn1, coloumn2, coloumn3, coloumn4, coloumn5) VALUES(?, ?, ?, ?, ?)");
$query->bind_param('iiiii', $Val1, $Val9, $Val10, $Val11, $Val12);
$query->execute();
From this code I received an error.
//Prepare insert statement.
if($InsertEventQuery = $mysqli->prepare("INSERT into events(eventname, eventdesc, eventmonth, eventdate, eventyear, eventstart, eventend) VALUES ('$EventName','$EventDesc','$EventMonth','$EventDate','$EventYear','$EventStart','$EventEnd')"))
{
//Bind parameters of insert statement.
$InsertEventQuery->bind_param('ssiiiii', $EventName, $EventDesc, $EventMonth, $EventDate, $EventYear, $EventStart, $EventEnd);
This is the error:
Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement in[...]
I looked into it because the error appears to be incorrect and found:
PHP Warning: mysqli_stmt::bind_param(): Number of variables doesn't match number of parameters in prepared statement
You do not need to bind parameters in this case. Placeholders are used for the values in an INSERT statement, or in a WHERE clause. (Note that placeholders are not allowed for identifiers, such as the column names in your statement.)
This confused me and I am now wondering in interest of security, when is it necessary to bind parameters and when is it necessary to use placeholders.
Binding parameters is a good idea in any INSERT statement as it will prevent SQL injection, and will also sanitize your strings for free.
I usually get it working using question mark in prepare statement like this:
//Prepare insert statement.
if ($InsertEventQuery = $mysqli->prepare("INSERT into events(eventname, eventdesc, eventmonth, eventdate, eventyear, eventstart, eventend) VALUES (?, ?, ?, ?, ?, ?, ?)"))
{
//Bind parameters of insert statement.
$InsertEventQuery->bind_param('ssiiiii', $EventName, $EventDesc, $EventMonth, $EventDate, $EventYear, $EventStart, $EventEnd);
I have a form with many optional fields. I am using PHP and PDO to collect the data from the forms and store it in a DB.
Since some optional fields may be empty, I only want to store inputs that actually have value. I can easily identify the inputs that have value, but without using a whole lot of IF statements, I can't seem to find a way to ONLY insert a value into the DB if it exists.
My current PDO looks something like this:
$data = array($var1, $var2, $var3, $var4, $var5, $var6);
$STH = $DBH->("INSERT INTO users (first, last, addr, city, email, phone) values (?, ?, ?, ?, ?, ?)";
$STH->execute($data);
Is there a way to only update a column if a value in the array exists?
Example: if $var3 and $var4 are empty, nothing is stored in the DB for "addr" and "city"?
For any other noobs out there, turns out inserting null values into a database is acceptable as long as you have your mysql rows up to allow null. You may also want to give them a default value of null.
See this post:
MySQL, better to insert NULL or empty string?
Thanks to everyone for the help.
Ideally, you'd set up the table to not allow null values for those fields. Otherwise, on the PHP side you could just check if the values have been set and are not null:
if (isset($var1, $var2, $var3, $var4, $var5, $var6)) {
$data = array($var1, $var2, $var3, $var4, $var5, $var6);
$STH = $DBH->("INSERT INTO users (first, last, addr, city, email, phone) values (?, ?, ?, ?, ?, ?)";
$STH->execute($data);
}
Unless you want to still insert? In which case just initialize the values to an empty string or whatever:
$data = array($var1?:"", $var2?:"", $var3?:"", $var4?:"", $var5?:"", $var6?:"");
I'm getting obsessed. I'm working for the first time with prepared statement and I am sure I have read somewhere that you could prepare a statement like:
$stmt = $db->prepare("INSERT INTO {$table} (:var1, :var2) VALUES (:val1, :val2)");
$stmt->bind_param(':var1', $var1);
$stmt->bind_param(':var2', $var2);
$stmt->bind_param(':val1', $val1);
$stmt->bind_param(':val2', $val2);
$stmt->execute();
Or something like that. I remember that I have read that you could call the vars with a specific name with ':' as prefix. But I really can't find an example of that. I read the php manual and I couldn't find any sample of this thing.
Is it right or have I dreamed it?
Faq
If you are wondering why I can't use simply the '?' method:
$stmt = $db->prepare("INSERT INTO {$table} (?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?)");
this gets hard to write.
You can't do :var1,:var2,:varX in both the column names list and the VALUES list for one thing. Secondly, PDO accepts named parameter binding.
See PHP Data Objects and examples in PDO::prepare.