2012-08-14 25 views
7

Tôi đang tạo một ứng dụng web nhỏ sẽ thường xuyên nhận được dữ liệu nhập của người dùng. Khi nghiên cứu làm thế nào để đảm bảo đầu vào dữ liệu được làm sạch đầu tiên, và cho rằng nó có vẻ như chuẩn bị báo cáo là con đường để đi.Làm cách nào để bạn liên kết các tham số với truy vấn chưa được chuẩn bị?

Tuy nhiên, tôi đã tìm thấy this SO question tuy nhiên, vì ứng dụng của tôi (ít nhất là theo tôi biết) sẽ không thực hiện nhiều truy vấn cho mỗi yêu cầu trang, có vẻ như tất cả những gì tôi thực sự cần là tham số trong truy vấn.

Tôi đã xem qua hướng dẫn sử dụng PHP trên PDO và mysqli, nhưng tôi không thể tìm thấy bất kỳ ví dụ nào về các giá trị được ràng buộc với truy vấn thông thường. Tất cả các ví dụ tôi đã tìm thấy có một $stmt->prepare một nơi nào đó trước khi ràng buộc.

Có hay không tuyên bố là "chuẩn bị" một cái gì đó được xác định bởi sự hỗ trợ của cơ sở dữ liệu và câu lệnh chuẩn bị sẽ luôn nằm trong mã? Hoặc có cách nào để ràng buộc các tham số trực tiếp vào một số $dbh->query(...)?

Để giải thích lý do tại sao tôi đang tìm để xem nếu nó có thể không sử dụng chuẩn bị, là do tuyên bố này từ câu hỏi SO tôi liên kết trước đó trong bài:

Khi không sử dụng chuẩn bị phát biểu? Khi bạn sẽ chỉ chạy câu lệnh một lần trước khi kết nối db biến mất.

Khi không sử dụng các tham số truy vấn bị ràng buộc (thực sự điều mà hầu hết mọi người sử dụng câu lệnh chuẩn bị để nhận)?

và điều này

Cá nhân tôi sẽ không bận tâm. Các câu lệnh giả được chuẩn bị có thể hữu ích cho các biến an toàn trích dẫn mà họ cho là có thể cung cấp.

+0

Bạn có thể giải thích * tại sao * bạn muốn bỏ qua 'preparation()'? – Tomalak

+0

Tại sao mọi người downvote mà không đưa ra một lý do? Đó là một câu hỏi khác trên trang web này đã khiến tôi tin rằng có sự khác biệt giữa hai người ngay từ đầu. – sicks

Trả lời

4

Làm cách nào để bạn liên kết các tham số với truy vấn chưa được chuẩn bị?

Bạn không. Chuỗi SQL có tham số (tức là dấu hỏi ở những vị trí cụ thể) cần được phân tích cú pháp (tức là đã chuẩn bị) trước khi các dấu hỏi đó có thể được coi là điểm chèn cho giá trị tham số.

Vì vậy, bạn luôn cần gọi prepare() trước khi bạn có thể gọi bind().


Một tham số tuyên bố là một chuỗi chứa SQL và giữ chỗ đánh dấu (đối với nhãn hiệu ví dụ câu hỏi, nhưng cơ sở dữ liệu khác nhau sử dụng placeholders khác nhau):

$sql = "SELECT user_id FROM user WHERE user_name = ?" 

Bây giờ giả sử có một giá trị bạn muốn chèn tại vị trí này:

$_POST["username"] 

Chuẩn bị tuyên bố, nói chung, cung cấp cho câu hỏi đánh dấu ý nghĩa đặc biệt của chúng "một giá trị có thể được chèn vào đây".Nói cách khác, nó tạo ra các thông số từ trình giữ chỗ.

$stmt->prepare($sql) 

Ràng buộc một giá trị cho một tham số đặt tham số cho một giá trị cụ thể.

$stmt->bind_param("s", $_POST["username"]) 

Bây giờ truy vấn có thể được thực thi mà không có chuỗi SQL và giá trị do người dùng cung cấp thực sự tiếp xúc với nhau. Đây là bit quan trọng: Giá trị tham số và SQL được gửi đến máy chủ riêng biệt. Họ không bao giờ chạm vào nhau.

$stmt->execute(); 

Những lợi thế là:

  • Bạn có thể ràng buộc một giá trị mới cho các tham số và thực hiện truy vấn một lần nữa mà không cần phải lặp lại tất cả của nó (hữu dụng trong một vòng lặp).
  • SQL injection là không thể, không có vấn đề gì giá trị $_POST["username"] chứa.
+0

Vì vậy, không có sự khác biệt giữa các câu lệnh đã chuẩn bị và tham số truy vấn bị ràng buộc? (về những gì tôi viết mã) – sicks

+0

@sicks Uhm, điều gì khiến bạn nghĩ vậy? Xem câu trả lời đã sửa đổi. – Tomalak

2

Bạn không. Đây là lý do:

Nếu sử dụng $dbh->query(...) bạn chỉ có thể gọi sql với tham số được nội suy vào chuỗi sql. Bằng cách sử dụng truy vấn như

$dbh->query("INS INTO MY_TABLE_OF_NAMES ('$name');"); 

10 hoặc hơn năm trước, đây là cách mà hầu hết sql đã được thực hiện. Đây là cách tiến thẳng nhất để gọi cơ sở dữ liệu, sử dụng giao diện SQL được thực hiện bởi RDMS, mà không cần một giao diện mức thấp đặc biệt. Nhưng mọi người phát hiện ra rằng điều này là nguy hiểm vì một cái gì đó gọi là tiêm sql.

http://en.wikipedia.org/wiki/Sql_injection

Ví dụ đơn giản nhất và phổ biến nhất đi một cái gì đó như thế này. Giả sử bạn đã có một cuộc gọi sql trong trang web của bạn mà có thể chạy:

INS INTO MY_TABLE_OF_NAMES VALUE ('$name'); 

Nhưng rồi ai đó sẽ đến với trang web của bạn và nhập có tên là bob'); DROP TABLE MY_TABLE_OF_NAMES;

đột nhiên tuyên bố sql suy của bạn trở nên

INS INTO MY_TABLE_OF_NAMES VALUE ('bob'); DROP TABLE MY_TABLE_OF_NAMES;); 

sau đó sẽ chèn bob vào cơ sở dữ liệu của bạn, xóa tất cả tên của bạn và ném một lỗi cho dấu trang ); khi trang web của bạn chạy nó.

Vì vậy, các phát biểu đã chuẩn bị được phát minh. Thay vì nội suy chuỗi trực tiếp vào chuỗi của bạn, nó sẽ sử dụng các ký tự ? để biểu thị giá trị động và một hàm bind được sử dụng để chèn chuỗi an toàn. Bằng cách này, đầu vào nhân cách sẽ không bao giờ được hiểu là mã SQL bởi cơ sở dữ liệu của bạn và trang web của bạn không thể bị lừa làm những việc mà nó không muốn làm. Lệnh chuẩn bị mất một chuỗi sql mất một chút sql và bán biên dịch vào một langauge cơ sở dữ liệu cấp thấp hơn để lại không gian mở các chuỗi động bất cứ nơi nào một ? được sử dụng. Bind sau đó lấy một trong những không gian mở đó và điền vào nó một đoạn dữ liệu, được mã hóa để thoát ascii, để nó không thể được hiểu sai dưới dạng mã SQL. Sau khi tất cả các số này đã được điền, sql đã sẵn sàng để được gửi tới RDMS để chạy.

Vì vậy, để trả lời câu hỏi của bạn, bạn sẽ không bao giờ ràng buộc tham số vào truy vấn đơn giản. Nếu bạn muốn biến động trong một truy vấn đơn giản, bạn sẽ chỉ nội suy chúng thành chuỗi SQL. Nhưng điều này là nguy hiểm. Các câu lệnh chuẩn bị cho phép bạn biên dịch trước một câu lệnh sql sau đó an toàn ràng buộc các tham số động vào nó để tạo ra SQL động an toàn. Ràng buộc để sql hoàn toàn là một cấu trúc của báo cáo chuẩn bị.

+0

+1 cho câu cuối cùng của bạn. Đây là khá nhiều xác nhận tôi đang tìm kiếm. Ước gì tôi có thể đặt hai câu trả lời đúng – sicks

0

Để sử dụng các thông số bị ràng buộc, bạn phải sử dụng các câu lệnh đã chuẩn bị. Đây chỉ là cách mọi thứ hiện đang được thực hiện trong pdo và mysqli. Tôi không chắc liệu các sản phẩm cơ sở dữ liệu có hỗ trợ một số loại giao thức truyền thông trong đó parametrized sql (sql text sử dụng placeholders) được gửi cùng với các giá trị tham số mà không cần phải thực hiện cuộc gọi chuẩn bị rõ ràng, nhưng pdo và mysqli không hiển thị chức năng này nếu nó có sẵn. Nó chắc chắn sẽ là một tính năng chào mừng cho các ứng dụng web.

Với pdo, vâng, có hay không câu lệnh sql thực sự được chuẩn bị khi bạn gọi $dbh->prepare($sql) phụ thuộc vào hỗ trợ cơ sở dữ liệu. pdo sẽ mô phỏng các câu lệnh đã chuẩn bị khi cơ sở dữ liệu không hỗ trợ chúng, hoặc nó có thể mô phỏng chúng nếu cấu hình của nó được thực hiện. Trong thực tế, pdo mô phỏng các câu lệnh chuẩn bị cho trình điều khiển mysql theo mặc định, và đã làm như vậy theo mặc định trong một thời gian rất dài. Nó mô phỏng chúng bằng cách tạo sql động, trích dẫn các giá trị, giống như bạn muốn. Trong trường hợp này, sql (với các giá trị cuối cùng được nhúng vào văn bản) được gửi đến cơ sở dữ liệu khi bạn gọi $stmt->execute(). Có, tiêm sql có thể ở đây trong các tình huống nhất định.

Các vấn đề liên quan