0

次のようにデータベースを更新しようとしています。

$fields = array(
    'titulo',
    'tipo_produto',
    'quantidade_peso',
    'unidade_de_venda',
    'unidades_por_caixa',
    'caixas_piso',
    'pisos_palete',
    'tipo_palete',
    'unidades_palete',
    'caixas_palete',
    'uni_diametro',
    'uni_largura',
    'uni_profundidade',
    'uni_altura',
    'caixa_largura',
    'caixa_profundidade',
    'caixa_altura',
    'altura_palete',
    'volume_unidade',
    'volume_caixa',
    'volume_palete',
    'peso_caixa',
    'peso_palete'
);
$sql = 'UPDATE ficha_item SET '.implode(', ', array_map(create_function('$value', 'return "$value=\"" . $_POST["$value"] ."\"";'), $fields)).' WHERE id=?';

$stmt = $db->prepare($sql);

$stmt->execute(array($_POST['item_id']));
$stmt->closeCursor();

これはかなりうまくいくようですが、セキュリティについて疑問に思っています、これはまったく消毒されていますか?

私は別の解決策を試みた後(成功しなかった)、この解決策を思いつきました:

$fields = array(
    'titulo',
    'tipo_produto',
    'quantidade_peso',
    'unidade_de_venda',
    'unidades_por_caixa',
    'caixas_piso',
    'pisos_palete',
    'tipo_palete',
    'unidades_palete',
    'caixas_palete',
    'uni_diametro',
    'uni_largura',
    'uni_profundidade',
    'uni_altura',
    'caixa_largura',
    'caixa_profundidade',
    'caixa_altura',
    'altura_palete',
    'volume_unidade',
    'volume_caixa',
    'volume_palete',
    'peso_caixa',
    'peso_palete'
);
$sql = 'UPDATE ficha_item SET ? WHERE id=?';

$valuesClause = implode(', ', array_map(create_function('$value', 'return "$value=\"" . $_POST["$value"] ."\"";'), $fields));

$stmt = $db->prepare($sql);

$stmt->execute(array($valuesClause, $_POST['item_id']));
$stmt->closeCursor();

エラーはまったくありませんが、データベースは更新されません。私の最初の解決策はまったく消毒されていますか?私の元のアイデアの何が問題になりましたか?PDOが実行時にクエリをサニタイズする方法と関係があると思います...しかし、私はそれをどこに使用するかについての考えがありません。

注:データベースの列名と入力名は同じであるため、$value機能します。ご参考までに、PHPのライブバージョンのため、無名関数は問題外です。

4

3 に答える 3

2

プリペアドステートメントはプリペアドステートメントであり、ステートメントの引数/パラメーターは明らかな理由でSQLとして扱われません。

ステートメントを準備する前に、クエリを準備する必要があります。

PDOのマニュアルを読むことをお勧めします。クエリを保護する方法を明確にするために、この質問も参照する必要があります。

$columns = array();
foreach ($fields as $column)
    $columns[] = "$column = ?";

$sql = "UPDATE table SET " . implode(" AND ", $columns) . " WHERE id = ? ";

// Now you may prepare the statement
于 2013-01-07T11:37:15.523 に答える
1
$fields = array(
    'titulo',
    'tipo_produto',
    'quantidade_peso',
    'unidade_de_venda',
    'unidades_por_caixa',
    'caixas_piso',
    'pisos_palete',
    'tipo_palete',
    'unidades_palete',
    'caixas_palete',
    'uni_diametro',
    'uni_largura',
    'uni_profundidade',
    'uni_altura',
    'caixa_largura',
    'caixa_profundidade',
    'caixa_altura',
    'altura_palete',
    'volume_unidade',
    'volume_caixa',
    'volume_palete',
    'peso_caixa',
    'peso_palete'
);
$sql="UPDATE ficha_item SET ".implode(", ",array_map(function($s){
    return "$s = ?";
},$fields))." WHERE id=?";
print_r($sql);

出力:

UPDATE ficha_item SET titulo = ?, tipo_produto = ?, quantidade_peso = ?, unidade_de_venda = ?, unidades_por_caixa = ?, caixas_piso = ?, pisos_palete = ?, tipo_palete = ?, unidades_palete = ?, caixas_palete = ?, uni_diametro = ?, uni_largura = ?, uni_profundidade = ?, uni_altura = ?, caixa_largura = ?, caixa_profundidade = ?, caixa_altura = ?, altura_palete = ?, volume_unidade = ?, volume_caixa = ?, volume_palete = ?, peso_caixa = ?, peso_palete = ? WHERE id=?

これは、必要なSQLステートメントprepareです。次に、準備されたステートメントを取得します。

$stmt=$db->prepare($sql);
$stmt->execute(array_merge(array_map(function($s){
    return $_POST[$s];
},$fields),array($_POST["item_id"])));

テストするデータベースはありませんが、これは正しいトラックであるはずです。

私はあなたの「スタイル」に従っていることに注意してください。このコードはすべて$_POSTをパラメーターとして扱い、SQLインジェクションを回避していますが、すべて$_POST[$fields[$idx]]が存在することを前提としています。これは、どのユーザーでも簡単に破られる可能性があるため、ここでサニタイズする必要があります。

編集

匿名関数を使用できないように更新したので、必要な配列を手動で作成できます。

$cache=array();
foreach($fields as $field)
    $cache[]="$field = ?";
$sql="UPDATE ficha_item SET ".implode(", ",$cache)." WHERE id=?";

$cache=array();
foreach($fields as $field)
    $cache[]=isset($_POST[$field])?$_POST[$field]:null;
$cache[]=$_POST["item_id"]
/*...*/
$stmt->execute($cache);
于 2013-01-07T11:58:06.570 に答える
1

あなたは良い目標を持ってい
ますあなたのフィールドがあなたのコードでホワイトリストに載っているとき、それは保護のために十分です(実際のところ、ホワイトリストはここで唯一の適切な解決策です)。

したがって、必要なのは、ホワイトリストと$_POST配列から正しいSQLを取得することだけです。
出来上がり-これはまさにこの目的のために書かれた便利な関数です
それであなたのコードは

$sql  = "UPDATE ficha_item SET ".pdoSet($fields,$values)." WHERE id = :id";
$stmt = $db->prepare($sql);
$values["id"] = $_POST['id'];
$stmt->execute($values);

(ユーザー定義)関数は素晴らしいです。なぜ誰もそれらを使用していないのか。

于 2013-01-07T12:06:03.017 に答える