【问题标题】:Unable to update records in CakePHP无法更新 CakePHP 中的记录
【发布时间】:2014-05-22 08:17:14
【问题描述】:

我有 answers 带有字段 id player_id read_status 的表

我正在尝试更新read_status

$this->Answer->updateAll(
    array(
        'Answer.' . "'" . $data['field'] . "'" => "'" . trim(base64_decode($data['option'])) . "'"
    ),
    array(
        'Answer.id' => trim(base64_decode($data['id']))
    )
);

以下字段是动态的,来自 AJAX 请求:

$data['field'] 包含read_status

$data['option'] 包含 base64 编码的yes

$data['id'] 包含 base64 编码的id

我得到的错误是:

错误:SQLSTATE[42S22]:未找到列:1054“字段列表”中的未知列“Answer.'read_status''
SQL查询:

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

注意:如果要自定义此错误信息,请创建 app\View\Errors\pdo_error.ctp

【问题讨论】:

  • 我敢肯定,当您仔细查看错误消息和查询的 SET 部分时,您将能够自己回答这个问题。
  • @ndm 我现在真的很困惑!混了很久。请帮忙!
  • 去掉双引号

标签: php mysql cakephp


【解决方案1】:

不要那样做

你产生的条件是:

WHERE
    `Answer`.`id` = 2

没有理由为此使用 updateAll,updateAll 的主要用例是:

  • 更新多条记录
  • 非主键更新
  • 以原子方式递增计数器等更新

调用保存

相反,只需调用 saveField:

$this->Answer->id = $id;
$this->Answer->saveField($field, $val);

或保存:

$this->Answer->id = $id;
$this->Answer->save(array($field => $val));

验证您的输入

如果您选择继续使用问题中的代码,请知道这很危险。

将用户输入直接提供给 updateAll 允许注入任意 SQL。确保数据是您期望的数据:

使用updateAll 调用没有什么可以阻止某人以$field 提交:

"read_status = 'yes' AND 正确 ="

实现这个 sql:

SET `Answer`.`read_status` = 'yes' AND correct = 'yes'

永远将用户输入放在 CakePHP 模型数组(更新、条件、顺序)的键中通常是个坏主意,因为预计该键不会被 CakePHP 潜在恶意,因此不受应用于值的相同转义逻辑的约束。

因此,转义所有用户输入:

$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);

使用上述逻辑并尝试与第一个示例中所示相同的注入,结果将是:

SET `Answer`.``read_status` = 'yes' AND correct =` = 'yes';

这只会失败,而不是允许用户任意操作数据库。

请注意,base64 编码如果被添加为“安全”措施,则不会执行任何操作。

【讨论】:

  • 我应该更具体一点,抱歉,我指的当然是字段/值部分或 updateAll。
  • 在更新(第一个参数)中是的,因为它被视为一个 sql 片段。在条件(第二个参数)没有。
【解决方案2】:

看来问题是你用单引号转义了字段名称:

`Answer`.`'read_status'` = 'yes'

应该是

`Answer`.`read_status` = '是'

以下更改应该可以解决此问题:

$this->Answer->updateAll(
    array('Answer.' . $data['field'] => trim(base64_decode($data['option']))),
    array('Answer.id' => trim(base64_decode($data['id'])))
);

【讨论】:

  • 我建议你至少阅读一下我刚刚写的答案(提问者和回答者)。
  • 如果在 updateAll() 案例中不是 int 类型,我认为它不会更新,因为字段的值应该在 '' 中
  • 没错,我只是指出了一个简单的解决方法,而不是建议使用save 或验证输入。同样,您的回答提供了完整的解释,@AD7six
【解决方案3】:

试试这个:-

$this->Answer->updateAll(
array(
    'Answer.' . $data['field']  => "'" . trim(base64_decode($data['option'])) . "'"
),
array(
    'Answer.id' => trim(base64_decode($data['id']))
)
);

【讨论】:

    猜你喜欢
    • 2020-03-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多