Reputation: 190
I have answers
table with fields id
player_id
read_status
I am trying to update read_status
:
$this->Answer->updateAll(
array(
'Answer.' . "'" . $data['field'] . "'" => "'" . trim(base64_decode($data['option'])) . "'"
),
array(
'Answer.id' => trim(base64_decode($data['id']))
)
);
The following fields are dynamic and coming from AJAX Request:
$data['field']
contains read_status
$data['option']
contains base64 encoded yes
$data['id']
contains base64 encoded id
The error I am getting is:
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'Answer.'read_status'' in 'field list'
SQL Query:
UPDATE
`skii`.`answers` AS `Answer`
LEFT JOIN
`skii`.`players` AS `Player` ON (`Answer`.`player_id` = `Player`.`id`)
SET
`Answer`.`'read_status'` = 'yes'
WHERE
`Answer`.`id` = 2
Notice: If you want to customize this error message, create app\View\Errors\pdo_error.ctp
Upvotes: 0
Views: 468
Reputation: 66359
The conditions you're generating are:
WHERE
`Answer`.`id` = 2
There is no reason to use updateAll for that, the primary use cases for updateAll are:
Instead, just call saveField:
$this->Answer->id = $id;
$this->Answer->saveField($field, $val);
or save:
$this->Answer->id = $id;
$this->Answer->save(array($field => $val));
If you choose to continue using the code in the question know that it is dangerous.
Feeding user input directly to updateAll allows for the possibility to inject arbitrary SQL. Ensure the data is the data you expect:
With the updateAll
call there's nothing to prevents someone submitting as $field
:
"read_status = 'yes' AND correct ="
achieving this sql:
SET `Answer`.`read_status` = 'yes' AND correct = 'yes'
It is generally a bad idea to ever put user input in the key of a CakePHP model array (update, conditions, order) as the key is not expected to be potentially malicious by CakePHP and therefore not subject to the same escaping logic applied to values.
Therefore, escape all user input:
$ds = $this->Answer->getDatsource();
$id = (int)trim(base64_decode($data['id']));
$field = $this->Answer->escapeField((base64_decode($data['field']));
$val = $ds->value(trim(base64_decode($data['option']))), $field);
With the above logic and attempting the same injection as shown in the first example the result would be:
SET `Answer`.``read_status` = 'yes' AND correct =` = 'yes';
Which would simply fail rather than permit users to arbitrarily manipulate the database.
Note that the base64 encoding, if it's been added as a "security" measure, does nothing.
Upvotes: 3
Reputation: 418
Try this :-
$this->Answer->updateAll(
array(
'Answer.' . $data['field'] => "'" . trim(base64_decode($data['option'])) . "'"
),
array(
'Answer.id' => trim(base64_decode($data['id']))
)
);
Upvotes: 0
Reputation: 6066
It seems the proble is that you are escaping the field name with single quotes:
`Answer`.`'read_status'` = 'yes'
should be
`Answer`.`read_status` = 'yes'
The following change should fix that:
$this->Answer->updateAll(
array('Answer.' . $data['field'] => trim(base64_decode($data['option']))),
array('Answer.id' => trim(base64_decode($data['id'])))
);
Upvotes: 0