2012-12-30 31 views
5

Xét Tôi đang xây dựng một hình thức và gửi dữ liệu đến PHP, một truy vấn chèn điển hình cho tôi đi như thế này:cách tối ưu để tạo ra các truy vấn SQL chèn dài với PDO

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

này có vẻ tốt đẹp cho một nhỏ truy vấn, và nó là sự hiểu biết của tôi rằng điều này giúp tôi an toàn từ thích SQL injection và whatnot.

Nhưng nếu tôi cần làm việc với một hình thức khá lớn thì sao? Một cái gì đó như ...

$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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; 

Tôi nghĩ rằng nó sẽ trở nên tẻ nhạt đếm tất cả các dấu hỏi này. Có cách nào tốt hơn để làm điều này với PDO?

+0

Hãy xem xét một [ORM] (http://stackoverflow.com/questions/1346457/some-orm-using-pdo) thay vì xây dựng monstrosities như vậy bằng tay . – DCoder

Trả lời

6

tôi sẽ làm một cái gì đó như thế này:

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

Nói cách khác, việc sử dụng tên thông số, và họ đã được tự động tạo ra dựa trên các mảng $fields. Mặc dù các thông số được đặt tên không hoàn toàn cần thiết; họ làm giúp mọi thứ trở nên dễ dàng hơn, bởi vì thứ tự các phần tử được chuyển đến, ví dụ: PDOStatement::execute() không còn là vấn đề nữa.

Điều này giả định rằng số lượng phần tử và khóa của chúng trong $_POST, khớp chính xác với số trường và tên của chúng trong $sql.

+3

+1 nhưng tôi khuyên bạn nên hạn chế các giá trị tham số: '$ stmt-> execute (array_intersect_key ($ _ POST, array_flip ($ fields)))'. –

+0

Kết hợp với đầu vào của Bill, điều này có vẻ tốt. Máy chủ thử nghiệm của tôi hiện không chạy PHP 5.3, tôi có thể lấy ví dụ bằng cách sử dụng create_function không? (Các phiên bản PHP dưới 5.3 không hỗ trợ các chức năng ẩn danh), tôi đã thử thực hiện điều này một cách riêng của mình, nhưng người mới làm quen PHP của tôi đang làm suy yếu tôi! –

+0

@BillKarwin Cảm ơn Bill, tôi đã thêm đề xuất của bạn. –

1

Sử dụng phương pháp bindParam, đó là cách riêng biệt (n | r) để thực hiện những gì bạn mong đợi. Điều này dễ hiểu hơn so với các dấu chấm hỏi. Vì vậy, mã sẽ được duy trì nhiều hơn.

Ví dụ từ official php doc:

Ví dụ # 1 Thực hiện một tuyên bố chuẩn bị với placeholders tên

<?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(); 
?> 

hy vọng điều này giúp.

2

Bạn có thể tạo SQL của bạn tự động:

$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(); 
Các vấn đề liên quan