ON DUPLICATE KEY UPDATE not working in PDO - php

INSERT INTO b (id, website...)
VALUES (:id, :website...)
ON DUPLICATE KEY UPDATE
website=:website ...
I have a MYSQL QUERY, I have SET id unique, why
website=:website ...
is not working, when I change to website="whatever" it works. anyone know why?
$job_B->bindValue(':website', $website, PDO::PARAM_STR);

As a general tip, you shouldn't be "duplicating" inserted values when doing an ON DUPLICATE KEY. Mysql provides the VALUES() function for this purpose, e.g.
INSERT INTO foo (bar) VALUES (:baz)
ON DUPLICATE KEY UPDATE bar := :baz
can be better rewritten as
INSERT INTO foo (bar) VALUES (:baz)
ON DUPLICATE KEY UPDATE bar = VALUES(bar)
^^^^^^^^^^^
VALUES() will re-use the value assigned to the specified field in the VALUES (...) section automatically, without requiring binding another variable into the query.

You have run into an unfortunate and misleading behavior of PDO's named parameters in a prepared statement. Despite assigning names, you cannot actually use a parameter more than once, as mentioned in the prepare() documentation:
You must include a unique parameter marker for each value you wish to pass in to the statement when you call PDOStatement::execute(). You cannot use a named parameter marker of the same name twice in a prepared statement. You cannot bind multiple values to a single named parameter in, for example, the IN() clause of an SQL statement.
This means you'll need to bind the parameter twice, with two different names, and consequently two different bindValue() calls:
$stmt = $pdo->prepare("
INSERT INTO b (id, website...)
VALUES (:id, :website_insert...)
ON DUPLICATE KEY UPDATE
website=:website_update ...
");
// Later, bind for each
$job_B->bindValue(':id', ...);
// Same value twice...
$job_B->bindValue(':website_insert', $website, PDO::PARAM_STR);
$job_B->bindValue(':website_update', $website, PDO::PARAM_STR);

The use of VALUES() to refer to the new row and columns is deprecated beginning with MySQL 8.0.20, and is subject to removal in a future version of MySQL.

Related

Using prepared statements with SQLite3 and PHP

I'm trying to add data to a database using SQLite3 in PHP. I got it working without prepared statements but now I'm trying to make it safer. I'm not using PDO.
So far the following code doesn't work. It just inserts the words ":name" and ":email" into the database, instead of what their bound values should be:
$smt = $db->prepare("insert into names (name, email) values (':name', ':email')");
$smt->bindValue(':name', $var_name);
$smt->bindValue(':email', $var_email);
$var_name = ($_POST[post_name]);
$var_email = ($_POST[post_email]);
$smt->execute();
So I thought at first that this was because I have single quotes around :name and :email in the prepared statement. So I took those out. Now when I post the form, it just puts blank entries into the database, it doesn't insert the values of $var_name and $var_email
The statement is executing, it's just not binding the variables properly I don't think. What have I done wrong?
You managed to confuse binding functions.
It is bindParam have to be used if you don't have your variable assigned yet.
While bindValue have to be used with existing value only.
Also, you should turn error reporting ON
You don't need intermediate variables, you must do this:
$smt = $db->prepare("insert into names (name, email) values (':name', ':email')");
$smt->bindValue(':name', $_POST['post_name'], SQLITE3_TEXT);
$smt->bindValue(':email', $_POST['post_email'], SQLITE3_TEXT);
$smt->execute();
As documented in SQLite3Stmt::bindValue() value is binded instantly, not as SQLite3Stmt::bindParam() that gets the value of the variable at execute() time. So the problem is that that variables are empty when the statement is executed.
Remember:
You don't need to add parentheses on variable assignment: $a = ($b); -> $a = $b;
You MUST quote variable key name. Otherwise PHP will try to look for a constant with this name and will throw a warning if it doesn't exists... but will assign a erroneous key value if it exists!! $_POST[post_name] -> $_POST['post_name']

mysql prepared statement "truncate table ?" returns null

in a function to truncate a table I can use
$stmt = $mysqli->prepare("truncate table packed_items");
and $stmt is set to a mysqli_stmt Object, but
if I try
$stmt = $mysqli->prepare("truncate table ?");
then $stmt is set to null and the statment:
$stmt->bind_param("s", $mytable)
will crash with error
Call to a member function bind_param() on a non-object in
I am using parameterized prepared statements to select,insert and update with no problem.
you cannot bind any SQL literal but data one. no keyword, no operator, no identifier.
if you really need to truncate your tables dynamically, knowing no name already (as truncating tables at random is obviously a sign of very bad design), check the table name against white list, format it correctly, and then interpolate in a query string.

Insert All Post Data into MySQL Database

The following topic is close to what I'm trying to ask, but it's outdated considering the mysql functions are deprecated in php now and there are prepared statements for preventing sql injection. insert all $_POST data into mysql using PHP?
Basically, I have a huge number of columns in my database that all need to get filled up when I submit this form. The form matches each column with an input field of the same name (the name attribute on the input field is the same as the column name it belongs in. So $_POST['firstName'] goes in the firstName column, and so on).
Is there a way using mysqli or PDO that I could easily just take all my POST data and automatically insert it into the MySQL table without going through each field by hand? I could code them all out using prepared statements, but there are a ton of columns and I'd like to get them done all at once if possible.
This is the beginning of the long version I don't really want to have to complete.
$stmt = $connection->prepare("INSERT INTO area_retreat
(user,firstName,lastName,...etc)
VALUES
(?,?,?,...etc)
ON DUPLICATE KEY UPDATE
user=VALUES(user),
firstName=VALUES(firstName),
lastName=VALUES(lastName),
...etc
");
$stmt->bind_param("sss",
$username,
$_POST['firstName'],
$_POST['lastName']
);
$stmt->execute();
INSERT INTO area_retreat VALUES (?, ?, ...) -- however, you have to match ALL columns as shown in the database.
If you have an auto increment ID, you will need to provide NULL for that column in the proper column order.
To avoid errors you definitely need to store the list of variables one way or another. It could be as simple as an array:
$fields = array('firstName', etc.);
Then you can loop through your array to generate your sql statement dynamically and using named placeholders instead of question marks, you only need to bind them once. You can also store the values in an array and send that array as a parameter to execute():
// start of query
$values = array();
$query = '...';
foreach ($fields as $field)
{
if (isset($_POST[$field]))
{
// add to query
$query .= "...";
// add value to array so that you can feed the array to `execute`
$values[':' . $field] = $_POST[$field];
}
}
// add end of query
$query .= '...';
$stmt->execute($values);
If you want to use the same variables in an ON DUPLICATE KEY UPDATE section, you can do another loop or build an insert section that you can use twice after looping once.

PDO Prepared Statements: having trouble binding multiple values to query

I am new to PDO and prepared statements and I am having trouble binding multiple values to my query. I have no problem if it is just one while making a SELECT, for example:
SELECT foo FROM table WHERE id=:something // no problem
But multiple, and trying to INSERT I am getting stuck:
Insert INTO mytable (field1, field2) VALUES (:value1, :value2) // No bueno
Have tried a few different ways and read other posts on here but no luck. Below is an example of what I am having trouble with:
$insertSQL = $db->prepare("INSERT INTO voting_poll (ipaddress, choice)
VALUES (':ipaddress', :value)");
$insertSQL->bindParam(':ipaddress', getenv('REMOTE_ADDR'), PDO::PARAM_STR);
$insertSQL->bindParam(':value', $_POST['radio'], PDO::PARAM_STR);
$insertSQL->execute();
I am getting the following error: Invalid parameter number: number of bound variables does not match number of tokens
You don't put quotes around params. Remove the quotes around :ipaddress in your query.
bindParam() must be used with a variable as it binds the parameter to the variable reference. If you want to use a value (for example, the return value from a function like getenv()), use bindValue() instead.

PHP Prepared Statement Fails

I'm passing a prepared sql insert statement (using placeholders ?, ?) into a mysql database. I'm then using ->execute($array) and passing a single array of the values in. It's working great (ie inserts) when there is data entered into every field of the form (the array is complete), however fails completly if just one single element is not completed.
With the older mysql_query, if a value was missing it would simply not insert that value into the database.
How do we deal with this in prepared statements?
Thanks!
They way you deal with it is to properly ensure you have entered all relevant values for your query. mysql_query() can be as lax as it wants because at the end of the day, it only has to support MySQL, but PDO is a generic interface for relational data storage and it does not take the job of making sure you've entered all your data.
I don't see the comparison because mysql_query doesn't take parameters?
The PDO object requires you to bind your elements to the parameters. This is the long-way:
$stmt->bindParam(":namedParam", 1, PDO::PARAM_INT);
This is short-hand, so internally PDO still should do the above with some extra work for itself:
$stmt->execute(array($value1, $value2, $etc));
If your query looks like this:
INSET INTO mytbl VALUES (?, ?, ?, ?, ?)
and your $data array looks like this:
$data = array($val1, $val2, $val3);
Where do you think the two NULL values should be inserted?
1st & 3rd ?'s ? How should PDO know that?
Furthermore, if you do know the answer to that question, you can still handle it in PHP:
function queryMyTable($val1, $val2, $val3, $val4 = null, $val5 = null) {
...
$stmt->execute(array($val1, $val2, $val3, $val4, $val5));
}

Categories