2012-12-30 8 views
5

bedenkt, dass ich bin ein Formular Aufbau und die Daten in PHP zu veröffentlichen, eine typische INSERT-Abfrage für mich so geht:optimal langen Einsatz von SQL-Abfragen mit PDO erstellen

$sql = "INSERT INTO news 
      (title, body) 
      VALUES (?, ?)"; 
$stmt = $db->prepare($sql); 
$stmt->execute(array($_POST["title"], $_POST["body"])); 
$stmt->closeCursor(); 

Das sieht gut aus für eine kleine Abfrage, und es ist mein Verständnis, dass dies hält mich vor SQL Injection und was nicht.

Aber was, wenn ich mit einer ziemlich großen Form arbeiten muss? So etwas wie ...

$sql = "INSERT INTO ficha_item 
    (titulo, tipo_produto, quantidade_peso, unidade_de_venda, 
    unidades_por_caixa, caixas_piso, pisos_palete, tipo_de_palete, 
    unidades_palete, caixas_palete, uni_diametro, uni_largura, 
    uni_profundidade, uni_altura, uni_peso_bruto_unidade, caixa_largura, 
    caixa_profundidade, caixa_altura, altura_palete, volume_unidade, 
    peso_caixa, peso_palete) 
    VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 

Ich denke, es wird langweilig, alle diese Fragezeichen zu zählen. Gibt es eine sauberere Möglichkeit, dies mit PDO zu tun?

+0

Betrachten wir ein [ORM] (http://stackoverflow.com/questions/1346457/some-orm-using-pdo) anstelle solche Ungeheuerlichkeiten des Gebäudes manuell . – DCoder

Antwort

6

Ich würde so etwas tun:

$fields = array(
    'titulo', 
    'tipo_produto', 
    'quantidade_peso', 
    'unidade_de_venda', 
    'unidades_por_caixa', 
    'caixas_piso', 
    'pisos_palete', 
    'tipo_de_palete', 
    'unidades_palete', 
    'caixas_palete', 
    'uni_diametro', 
    'uni_largura', 
    'uni_profundidade', 
    'uni_altura', 
    'uni_peso_bruto_unidade', 
    'caixa_largura', 
    'caixa_profundidade', 
    'caixa_altura', 
    'altura_palete', 
    'volume_unidade', 
    'peso_caixa', 
    'peso_palete' 
); 
$sql = 'INSERT INTO ficha_item (%s) VALUES (%s)'; 
// make a list of field names: titulo, tipo_produto /*, etc. */ 
$fieldsClause = implode(', ', $fields); 
// make a list of named parameters: :titulo, :tipo_produto /*, etc. */ 
$valuesClause = implode(', ', array_map(function($value) { return ':' . $value; }, $fields)); 
// or, with create_function 
$valuesClause = implode(', ', array_map(create_function('$value', 'return ":" . $value;'), $fields)); 
$sql = sprintf($sql, $fieldsClause, $valuesClause); 

// $sql is now something similar to (formatted for display): 
// INSERT INTO ficha_item 
//  (titulo, tipo_produto /*, etc. */) 
// VALUES 
//  (:titulo, :tipo_produto /*, etc. */) 

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

// if the keys in $_POST match with $fields, you can now simply pass $_POST here 
$stmt->execute($_POST); 
// or, as per Bill Karwin's sound suggestion, with the intersection of $_POST 
$stmt->execute(array_intersect_key($_POST, array_flip($fields))) 

Mit anderen Worten: Parametern Verwendung genannt, und sie dynamisch auf das $fields Array basiert erzeugt werden. Obwohl benannte Parameter nicht unbedingt notwendig sind; Sie tun helfen, die Dinge einfacher zu machen, weil die Reihenfolge der Elemente, die beispielsweise an PDOStatement::execute() weitergegeben werden, jetzt keine Rolle mehr spielt.

Dies setzt jedoch voraus, dass die Anzahl der Elemente und ihre Schlüssel in $_POST genau mit der Anzahl der Felder und deren Namen in $sql übereinstimmt.

+3

+1, aber ich würde empfehlen, die Parameterwerte einzuschränken: '$ stmt-> execute (array_intersect_key ($ _ POST, array_flip ($ fields)))'. –

+0

In Kombination mit Bills Eingabe sieht das gut aus. Mein Testserver läuft nicht mit PHP 5.3, könnte ich ein Beispiel mit create_function bekommen? (PHP-Versionen unter 5.3 unterstützen keine anonymen Funktionen.) Ich habe versucht, dies selbst zu implementieren, aber mein PHP-Neuling beeinträchtigt mich! –

+0

@BillKarwin Danke Bill, ich habe deinen Vorschlag hinzugefügt. –

1

Mit der bindParam-Methode ist es die clea (n | r) est-Methode, um das zu tun, was Sie erwarten. Dies ist verständlicher als mit Fragezeichen. So wird der Code wartungsfreundlicher.

Beispiel aus dem official php doc:

Beispiel # 1 Führen Sie eine vorbereitete Anweisung mit dem Namen Platzhalter

<?php 
/* Execute a prepared statement by   binding PHP variables */ 
$calories = 150; 
$colour = 'red'; 
$sth = $dbh->prepare('SELECT name, colour, calories 
FROM fruit 
WHERE calories < :calories AND colour = :colour'); 
$sth->bindParam(':calories', $calories, PDO::PARAM_INT); 
$sth->bindParam(':colour', $colour, PDO::PARAM_STR, 12); 
$sth->execute(); 
?> 

Hoffnung, das hilft.

2

Sie können Ihre SQL dynamisch erstellen:

$allowed_fields = array(
    'titulo', 
    'tipo_produto', 
    'quantidade_peso', 
    'unidade_de_venda', 
    'unidades_por_caixa', 
    'caixas_piso', 
    'pisos_palete', 
    'tipo_de_palete', 
    'unidades_palete', 
    'caixas_palete', 
    'uni_diametro', 
    'uni_largura', 
    'uni_profundidade', 
    'uni_altura', 
    'uni_peso_bruto_unidade', 
    'caixa_largura', 
    'caixa_profundidade', 
    'caixa_altura', 
    'altura_palete', 
    'volume_unidade', 
    'peso_caixa', 
    'peso_palete' 
); 

$columns = ""; 
$values = ""; 
$values_arr = array(); 
foreach ($_POST as $key=>$value) 
{ 
    if (!in_array($key, $allowed_fields)) continue; 
    $columns .= "$key, "; 
    $values .= "?, "; 
    $values_arr[] = $value; 
} 
// now remove trailing ", " from $columns and $values 
$columns = rtrim($columns, ", "); 
$values = rtrim($values, ", "); 
// finish them 
$sql = "INSERT INTO ficha_item($columns) VALUES($values)"; 
$stmt = $db->prepare($sql); 
$stmt->execute($values_arr); 
$stmt->closeCursor(); 
Verwandte Themen