2013-07-24 56 views
8

Tôi hiện có một mẫu tìm kiếm nhỏ chỉ có hai phần tử: một kiểu nhập văn bản có tên là search và hộp "chọn" có tên param. Tùy chọn được chọn trong hộp đó nên được sử dụng làm tham số để chọn cột bảng nào trong DB của tôi sẽ được tìm nạp.Làm thế nào tôi có thể chuyển một biến đến một mệnh đề WHERE bằng cách sử dụng mysqli?

Sử dụng mysql_ chức năng, một cái gì đó như thế này có thể được thực hiện:

$param = $_POST['param' ]; 
$search = $_POST['search']; 

$query = 'SELECT * FROM table WHERE $param LIKE "%$search%"'; 

Nhưng tôi không thể có được nó để làm việc với các cú pháp mysqli_. Tôi cố gắng để sử dụng chuẩn bị phát biểu, nhưng tốt nhất mà tôi đã làm cho đến nay là thế này:

$param = $_POST['param' ]; 
$search = $_POST['search']; 

if($param == 'first_name') 
{ 
    if($prep = $link->prepare('SELECT * FROM table 
           WHERE first_name 
           LIKE CONCAT("%", ?, "%")')) 
    { 
     $prep->bind_param('s', $search); 
     $prep->execute(); 
     $prep->bind_result($first_name, $last_name); 

     while($prep->fetch()) 
      echo $first_name . ' ' . $last_name; 

     $prep->close(); 
    } 
    else 
     echo 'Error while preparing statement.'; 
} 
else if($param == 'last_name') 
{ 
    ... 
} 

Nhưng chỉ sử dụng một loạt các else if s vẻ như rất nhiều lặp đi lặp lại và không hiệu quả, đặc biệt nếu tôi có rất nhiều cột để xử lý.

Điều đầu tiên tôi đã thử là ràng buộc tham số - ... WHERE ? LIKE ...$prep->bind_param('ss', $param, $search) -, nhưng nó không hoạt động (và tôi vẫn không biết tại sao).

Có cách nào để làm điều đó một cách thông minh hơn không?

+0

+1 để định dạng tốt câu hỏi của bạn –

+0

.... WHERE ". $ Param." LIKE ....nói chung những gì tôi làm với câu lệnh sql – Adsy2010

+1

Bạn không thể sử dụng trình giữ chỗ cho tên cột theo như tôi biết, đó là lý do tại sao nó không hoạt động. –

Trả lời

3

Nếu bạn đang sử dụng mã SQL tương tự cho mỗi param, chỉ cần tạo một hash của params thể: (CGI param name => table column name)

$params = array(
    'first_name' => 'first_name', 
    'last_name' => 'last_name', 
); 

Đó là tốt hơn nhiều từ một điểm bảo mật của xem như bạn được bảo vệ từ SQL injection.

Sau đó lấy tên cột từ băm và đặt nó vào truy vấn - và bạn sẽ thoát khỏi if-s:

$name = $params[$param]; 
$sql = "SELECT * FROM table 
WHERE 
$name LIKE ?"; 

if($prep = $link->prepare($sql)) 
{ 
    $prep->bind_param('s', "%$search%"); 
    ... 

Như @Akam nói, không cần phải CONCAT ("% ",?,"% ") trong truy vấn - tốt hơn là ràng buộc giá trị với phần trăm ngay phía trước.

+1

không cần phải concat trong truy vấn, thay vào đó: 'bind_param ('s',"% $ search% ")' –

+1

@Akam Trả lời được cải thiện – user4035

+0

Hiệu quả và rõ ràng. Cảm ơn bạn! – Renato

2

Theo ví dụ này trong cuốn hướng dẫn PHP

http://www.php.net/manual/en/mysqli-stmt.bind-param.php#108790

Bạn dường như là tốt nhất để thêm '%' vào biến chuỗi bạn đang ràng buộc - chứ không phải là trong truy vấn ví dụ trong ví dụ của bạn:

if($prep = $link->prepare('SELECT * FROM table 
          WHERE first_name 
          LIKE ?')) 
{ 
    $search='%'.$search.'%'; 
    $prep->bind_param('s', $search); 
    $prep->execute(); 
    $prep->bind_result($first_name, $last_name); 

    while($prep->fetch()) 
     echo $first_name . ' ' . $last_name; 

    $prep->close(); 
} 

Chưa thử nghiệm nhưng có vẻ như là giải pháp hợp lý.

+0

Điều đó sẽ không giải quyết được vấn đề của anh ta khi sử dụng tên trường động, nhưng nó sẽ sửa chữa ví dụ của anh ta trong giải pháp của anh ta. –

+0

Xin lỗi, bạn nói đúng, tôi đã bỏ lỡ điểm. Tôi chỉ đơn giản là thay thế chuỗi param $ vào chuỗi truy vấn thay vì tên cột. Tuy nhiên, tôi sẽ áp dụng một số lọc nghiêm trọng về nội dung, ví dụ: $ unsafe_col_name = "/ [^ a-zA-Z0-9 \\\ _] /"; $ param = preg_replace ("$ unsafe_col_name", "", $ param); –

1

Bạn không thể sử dụng trình giữ chỗ cho tên cột, vì vậy bạn sẽ phải nối các tên cột bình thường. Tuy nhiên, thay vì chỉ thoát nó với mysqli, bởi vì bạn có một bộ hạn chế về cột tôi muốn đề nghị một danh sách cách tiếp cận trong khi:

$allowed_params = array('first_name', 'last_name', etc); 

$param = $_POST['param' ]; 
$search = $_POST['search']; 


if(!in_array($param, $allowed_params)) 
    die("Uh oh, the request seems to have an invalid param!"); 

if($prep = $link->prepare('SELECT * FROM table 
          WHERE ' . $param . ' 
          LIKE ?')) 
{ 
    $prep->bind_param('s', '%' . $search . '%'); 
    $prep->execute(); 
    $prep->bind_result($first_name, $last_name); 

    while($prep->fetch()) 
     echo $first_name . ' ' . $last_name; 

    $prep->close(); 
} 
else 
    echo 'Error while preparing statement.'; 

Cũng lưu ý việc loại bỏ các tuyên bố concat, và thay vào đó concatenating trong PHP. Điều này rất quan trọng đối với các câu lệnh đã chuẩn bị khi nó đến máy chủ nó không thực sự kết hợp chúng (do đó bảo vệ các câu lệnh đã chuẩn bị), vì vậy nó sẽ không hoạt động đúng trừ khi các ký tự đại diện được gửi với chuỗi $search.