PDO Prepared Statements: having trouble binding multiple values to query - php

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.

Related

PDO: Database reports an error: SQLSTATE[HY000]: General error: 2031 [duplicate]

I'm getting this annoying error and although I have an idea of why I'm getting it, I can't for the life of me find a solution to it.
if ($limit) {
$sth->bindValue(':page', $page - 1, PDO::PARAM_INT);
$sth->bindValue(':entries_per_page', $page * $entries_per_page, PDO::PARAM_INT);
}
$sth->execute($criteria);
Query contains placeholders (:placeholder). But to add those LIMIT placeholders, I need to use the manual method (bindValue) because otherwise the engine will turn them into strings.
I'm not getting the Invalid number of parameters error, so all placeholders have been bound correctly (I assume).
Query:
SELECT `articles`.*, `regional_municipalities`.`name` AS `regional_municipality_name`,
`_atc_codes`.`code` AS `atc_code`, `_atc_codes`.`name` AS `substance`
FROM `articles`
LEFT JOIN `_atc_codes`
ON (`_atc_codes`.`id` = `articles`.`atc_code`)
JOIN `regional_municipalities`
ON (`regional_municipalities`.`id` = `articles`.`regional_municipality`)
WHERE TRUE AND `articles`.`strength` = :strength
GROUP BY `articles`.`id`
ORDER BY `articles`.`id`
LIMIT :page, :entries_per_page
All placeholder values reside in $criteria, except for the last two LIMIT, which I manually bind with bindValue().
This same error 2031 can be issued when one bind two values with the same parameter name, like in:
$sth->bindValue(':colour', 'blue');
$sth->bindValue(':colour', 'red');
..so, beware.
You cannot use ->bind* and ->execute($params). Use either or; if you pass parameters to execute(), those will make PDO forget the parameters already bound via ->bind*.
This exception also appears if you try to run a query with placeholders instead of preparing a statment such as
$stmt = $db->query('SELECT * FROM tbl WHERE ID > ?');
instead of
$stmt = $db->prepare('SELECT * FROM tbl WHERE ID > ?');
From the manual:
public bool PDOStatement::execute ([ array $input_parameters ] )
Execute the prepared statement. If the prepared statement included
parameter markers, you must either:
call PDOStatement::bindParam() to bind PHP variables to the parameter markers: bound variables pass their value as input and
receive the output value, if any, of their associated parameter
markers
or pass an array of input-only parameter values
You need to pick a method. You cannot mix both.
It's not exactly an answer, but this error also happens if you try to use a word with a hyphen as placeholders, for example:
$sth->bindValue(':page-1', $page1);
So better use
$sth->bindValue(':page_1', $page1);
This happens if you have mismatching parameters. For example:
$q = $db->prepare("select :a, :b");
$q->execute([":a"=>"a"]);
The exception also happens (at least in MySQL/PDO) when your SQL tries to UPDATE an AUTO_INCREMENT field.

PDO does not insert after quote

I am trying to avoid SQL injection in my page.
// Connect to database server and select database
$connection = new PDO("mysql:dbname=tt8888;host=mysql.tt8888.com", "tt8888", "ttnopassword");
// Quote data to prevent SQL injection
$name = $connection->quote($name);
// Insert now
$connection->query("INSERT INTO Contact (name, eeeee, llll, mmmmm, iiiii) VALUES ('$name','$eeeee','$llll','$mmmmm','$iiiii');");
Without quote(), it inserts just fine. And using print $name;, the quote() part seems work fine. Why is there nothing inserted into database after using quote()?
PDO::quote will put single quotes around your values. So you don't need to do that yourself in your SQL.
Though I'd strongly recommend you switch to using prepare() with named parameters.
Do not use PDO::quote. It is much better to use parameterized queries.
$stmt = $connection->prepare("INSERT INTO Contact (name, e, l, m, i) VALUES (?,
?, ?, ?, ?)");
// This will quote all of the values for you
$stmt->execute(array($name, $eeeee, $llll, $mmmm, $iiiii));
You can also use bind methods (bindParam or bindValue) instead of passing the arguments directly to execute. This will allow you to specify the data types if it's necessary, but it seems like these are all supposed to be strings.

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']

ON DUPLICATE KEY UPDATE not working in PDO

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.

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