Reputation: 429
*I saw question about this topic for mysqli or fringe cases for PDO, but didn't find this specific question (which surprised me, but maybe I don't know how to search)
Before trying to use PDO, I used simple, unprotected queries. My prepare function looked like this, simplified:
static function prepareUpdate($table, array $arguments, array $filter) {
$argumentsList = self::associateArguments($arguments);
$filterList = self::associateArguments($filter);
$query = "UPDATE `$table` SET $argumentsList WHERE $filterList;";
return $query;
}
$arguments and $filter are associative arrays: ['name' => 'John', 'occupation' => 'Carpenter']
for $arguments, ['employeeId' => 518]
for filter, for example. Let's say $table is 'workers'. Through some simple functions, it becomes:
argumentsList becomes
`name` = 'John', `occupation` = 'Carpenter'
filterList becomes
`employeeId` = 518
So the final string becomes:
UPDATE `workers` SET `name` = 'John', `occupation` = 'Carpenter' WHERE `employeeId` = 518;
That seemed simple enough for me. Then, I tried to use similar logic in PDO's prepare statements. But I ran into trouble. Maybe because I don't understand the intended philosophy behind it? Or just technicalities.
PDO needs to use the bindValue() method and such after prepare() to be secure against injections, if I understand correctly. And, I have to use placeholders (:name, :occupation, etc).
The question is, how do I do that if I don't know what columns I will be looking for, or even how many?
Most examples I see include a very pre-defined statement: UPDATE tableX SET `name` = :name WHERE `id` = :id - or something along those lines.
So what if I want to use a variable amount of parameters? My understanding is that I can only substitute one :placeholder with one property, not more (hence why the quotes aren't needed), so I can't exactly write something like:
UPDATE :table SET :allParametersHere ;
How would I go about this? I don't have a definite table that I want to use this function on, much less a reasonable list of valid columns to check against. How would I create a wrapper that would work with different argument amounts?
Upvotes: 0
Views: 668
Reputation: 2815
For such problems, the database query builder
solutions would be better.
Returning to the question: you know the number of parameters, so you can create query template.
<?php
$wq = $pq = [];
$allowed_keys = ['name', 'occupation', '...'];
foreach ($arguments AS $key => $value) {
if(in_array($key, $allowed_keys))
$pq[] = "$key = :$key" ;
else throw new Exception('Go away hacker!');
}
foreach ($filter AS $key => $value)
if(in_array($key, $allowed_keys))
$wq[] = "$key = :$key" ;
$q = "UPDATE $table SET ". join(', ', $pq);
if(!empty($wq))
$q .= 'WHERE '. join(' AND ', $wq);
In results you get query pattern like:
UPDATE workers SET name = :name, occupation = :occupation WHERE employeeId = :employeeId;
Such folding is allowed (if you have "secure" keys to these tables)
$allowed_keys
or better $allowed_column_names
Upvotes: 2