PHP 8 + PDO: Xây dựng bộ lọc tìm kiếm động thế nào để vẫn an toàn SQL?

Đã giải đáp

46 lượt xem · 6 trả lời

Cộng đồng đang cùng tìm lời giải

Câu trả lời được chọn được đưa lên đầu để mọi người dễ tham khảo.

1. 12:26 06/08/2026
Chào mọi người, Mình đang làm trang danh sách có nhiều bộ lọc như trạng thái, tác giả, ngày tạo và sắp xếp. Điều kiện WHERE thay đổi theo các ô người dùng chọn nên mình lo việc ghép câu SQL sẽ gây SQL injection. Mọi người thường tổ chức PDO prepared statement thế nào cho phần điều kiện động, ORDER BY và LIMIT để vừa dễ bảo trì vừa an toàn?
0 Facebook
2. 12:26 06/08/2026
Đáp án được người đặt câu hỏi chọn
Chào bạn Nam, Nguyên tắc quan trọng là: giá trị dữ liệu luôn đi qua placeholder, còn tên cột hoặc chiều sắp xếp không thể bind nên phải lấy từ danh sách cho phép. Bạn nên xây dựng mảng điều kiện WHERE và mảng tham số riêng; chỉ thêm điều kiện khi bộ lọc có giá trị. Với ORDER BY, ánh xạ lựa chọn giao diện sang một whitelist cột hợp lệ; với LIMIT/OFFSET, ép kiểu số nguyên và bind theo PDO::PARAM_INT. Không đưa trực tiếp chuỗi người dùng nhập vào tên cột, toán tử hay ORDER BY. Cuối cùng, hãy ghi test cho các tổ hợp bộ lọc phổ biến và dùng EXPLAIN để chắc rằng câu truy vấn sinh ra vẫn dùng chỉ mục phù hợp.
0
3. 20:36 06/10/2026
Trả lời Nam Lê Chào mọi người, Mình đang làm trang danh sách có nhiều bộ lọc như trạng thái, tác giả, ngày tạo và sắp xếp. Điều kiện WH…
Bạn có thể dùng prepared statement cho các giá trị lọc như status, author và date, truyền tham số vào placeholder để tránh injection. Với ORDER BY và LIMIT, không thể bind trực tiếp, nên tạo danh sách whitelist các cột được phép sắp xếp và chỉ cho phép chúng trong chuỗi. Ví dụ, nếu người dùng chọn sắp xếp theo 'created_at' và 'DESC', bạn concat chuỗi 'ORDER BY created_at DESC' sau khi kiểm tra. Đối với LIMIT, dùng placeholder cho số và bind tham số. Cách này vừa an toàn, vừa dễ bảo trì. Bạn đang áp dụng lọc nào nhất để test?
0
4. 15:29 10/10/2026
Trả lời Nam Lê Chào mọi người, Mình đang làm trang danh sách có nhiều bộ lọc như trạng thái, tác giả, ngày tạo và sắp xếp. Điều kiện WH…
Bạn có thể giữ an toàn bằng cách chỉ sử dụng các tham số cho các giá trị, trong khi vẫn kiểm soát các phần có thể thay đổi của câu lệnh. Tạo một mảng các điều kiện `WHERE` riêng biệt, mỗi điều kiện sử dụng một tên vị trí (`:status`, `:author`, …). Chỉ thêm một điều kiện vào danh sách khi người dùng cung cấp giá trị cho nó, sau đó nối chúng bằng `AND`. Truyền toàn bộ mảng đến `PDO::execute()` – PDO sẽ tự động ánh xạ từng giá trị vào vị trí tương ứng. Đối với `ORDER BY` và `LIMIT`, bạn không bao giờ nên tham số hóa tên cột. Thay vào đó, hãy xác thực trước: định nghĩa một mảng các cột được phép sắp xếp và một danh sách các toán tử sắp xếp được phép (ví dụ: `ASC`, `DESC`). Sử dụng giá trị đã chọn từ mảng đó trong câu lệnh, đảm bảo rằng nó không bao gồm dữ liệu từ người dùng. Cuối cùng, hãy đóng gói logic này trong một hàm nhỏ (hoặc sử dụng một bộ tạo truy vấn đơn giản) để việc bảo trì trở nên dễ dàng hơn. Điều này giúp bạn có được các truy vấn động, có thể tái sử dụng mà vẫn đảm bảo an toàn. Bạn có cần xử lý các giá trị `IN` cho bất kỳ bộ lọc nào không, hoặc có bất kỳ quy tắc đặc biệt nào về ngày tháng không?
0
5. 17:23 13/10/2026
Trả lời Quản Trị Viên Bạn có thể giữ an toàn bằng cách chỉ sử dụng các tham số cho các giá trị, trong khi vẫn kiểm soát các phần có thể thay đ…
Cảm ơn admin đã chia sẻ cách tiếp cận chuẩn chỉnh. Việc tách biệt logic xây dựng câu truy vấn (chuỗi SQL) và truyền tham số (mảng values) thực sự là chìa khóa để tránh injection khi filter phức tạp. Mình thường dùng cách tương tự: build mảng `$whereClauses` và `$params` song song, rồi `implode(' AND ', $whereClauses)`. Một điểm mình thấy hay bị quên là xử lý toán tử `LIKE` – cần nhớ escape ký tự `%` và `_` trong giá trị người dùng nhập *trước khi* bind param, không phải trong SQL. Ngoài ra, với mảng `IN` (ví dụ filter theo nhiều status cùng lúc), cách an toàn nhất là generate động số lượng placeholder `?, ?, ?` tương ứng số phần tử mảng, rồi merge vào `$params`. Admin có thể demo thêm đoạn handle trường hợp `IN` với mảng rỗng (bỏ qua điều kiện) hoặc `BETWEEN` cho range ngày tháng không? Phần validation date format phía PHP trước khi bind cũng là nơi dễ sinh bug lặt vặt.
0
6. 16:22 14/10/2026
Trả lời Lê Châu Cảm ơn admin đã chia sẻ cách tiếp cận chuẩn chỉnh. Việc tách biệt logic xây dựng câu truy vấn (chuỗi SQL) và truyền tham…
Đúng trọng tâm, việc escape `%` và `_` ở tầng PHP trước khi bind mới là "chìa khóa" an toàn cho LIKE, nhiều bạn lầm tưởng PDO lo hết. Về `IN` với mảng rỗng, cách gọn nhẹ nhất là check `empty($arr)` thì không push clause vào `$whereClauses` (hoặc thêm `1=0` nếu bắt buộc có điều kiện). Còn `BETWEEN` ngày tháng, mình thường validate format `Y-m-d` bằng `DateTime::createFromFormat` rồi mới bind 2 tham số `start`/`end`, tránh lỗi lặt vặt do locale hoặc chuỗi rác. Một điểm hay bị bỏ qua: khi filter phức tạp (nhiều nhóm điều kiện OR/AND lồng nhau), các bạn thường xây dựng đệ quy hay dùng thư viện Query Builder nhẹ (như `doctrine/dbal` chỉ phần SQL) để quản lý thứ tự tham số cho đỡ rối?
0
7. 21:53 25/10/2026
Trả lời Quản Trị Viên Bạn có thể giữ an toàn bằng cách chỉ sử dụng các tham số cho các giá trị, trong khi vẫn kiểm soát các phần có thể thay đ…
Với IN, mình thường tạo chuỗi placeholder theo đúng số phần tử, ví dụ dùng array_fill và implode để có ?,?,?, rồi bind từng giá trị bằng execute($params). Lưu ý không dùng lại cùng một named placeholder kiểu :id nhiều lần nếu chưa chắc chế độ emulate prepares; dùng ? hoặc đặt tên riêng sẽ an toàn hơn. Với ID số, vẫn nên ép kiểu int và loại giá trị rỗng trước khi dựng IN. Về ngày tháng, đừng tin định dạng người dùng gử
0
Vui lòng đăng nhập để tham gia trả lời chủ đề này.
Điều hướng nhanh

Bạn muốn khám phá điều gì?

Tìm chủ đề, bài viết hoặc đi thẳng đến một khu vực của cộng đồng.

Esc để đóng Ctrl K để mở lại