2012-07-17 21 views
8

Tôi đang gặp phải một vấn đề nhỏ. Tôi đang làm việc trên một ứng dụng tại thời điểm đó đòi hỏi việc sử dụng các tên bảng động trong MySQL. Về cơ bản, tôi có một quá trình lựa chọn album từ cơ sở dữ liệu dựa trên một số yếu tố (Thể loại, Độ dài phát, Ngày phát hành, v.v.) - Có một phần của quá trình này cho phép người dùng tạo một nhóm bộ lọc tùy chỉnh ..Bảo vệ an toàn các tên bảng động trong MySQL bằng Codeigniter

Bộ lọc tùy chỉnh trả về số cho người dùng của tất cả các album trong tiêu chí lựa chọn đó. Sau đó, ID của những album đó được lưu trữ trong một bảng có số băm/sê-ri được tạo ngẫu nhiên (ví dụ: albumSelect_20880f9c05d68a)

Tôi đã làm theo cách này bởi vì tôi không muốn lưu trữ danh sách được phân cách bằng dấu phẩy lớn trong một trường ngớ ngẩn) - Và tôi không ưa thích gửi một mảng giá trị đến một trường ẩn trong HTML của tôi vì điều này sẽ chỉ làm tăng thông lượng dữ liệu (Có thể là hàng ngàn hàng cùng một lúc)

Trong CodeIgniter, tôi đang sử dụng Truy vấn Bindings để tạo truy vấn SQL của tôi, như vậy:

select * from artists where artistName = ? AND albumTitle = ? 

Truy vấn sau đó tự động được thoát khi tôi tham số hóa truy vấn

$query = $this->db->query($sql,array("Singer","Album")); 

Bây giờ đến phần khó khăn

Nếu tôi viết truy vấn của tôi để tìm một cái gì đó như thế này:

$sql = "select albumid from albums where albumid in (select albumid from albumSelect_?)"; 
$this->db->query($sql,array('20880f9c05d68a')); 

Các kết quả truy vấn trở thành:

select `albumid` from `albums` where `albumid` in (select `albumid` from `albumSelect_'20880f9c05d68a'`) 

Và khá đúng như vậy, nhưng rõ ràng truy vấn không hợp lệ ..

Edit: More Info

Truy vấn có thể là một phần của một truy vấn lớn hơn, tùy thuộc vào những gì tiêu chí người sử dụng chọn. ví dụ.

$sql = "select albumid from albums where albumid in(select albumid from tags where tag = ?) AND albumid in(select albumid from albumSelect_?)"; 

Tôi chỉ tự hỏi nếu có một cách để làm việc này, HOẶC nếu có ai có thể đề xuất một giải pháp tốt hơn .. Concatenation của tên bảng rõ ràng không là một lựa chọn.

Cảm ơn trước!

Dave

+0

Nếu bạn đã chuẩn hóa dữ liệu của mình, bạn sẽ không cần phải thực hiện việc này * hoặc * lưu trữ danh sách album được phân tách bằng dấu phẩy. Đây được gọi là mối quan hệ "có nhiều người". – Xeoncross

Trả lời

1

Cơ chế thoát chỉ dành cho các chuỗi dữ liệu, không phải cho các tên lược đồ. Nói cách khác, chỉ cho nội dung của bảng, không phải cho cấu trúc của nó. Vì vậy, bạn sẽ phải tự dán chuỗi vào truy vấn hoặc tránh sử dụng bảng theo cách này. ? mẫu truy vấn sẽ không giúp bạn ở đó.

Nếu bạn dán chuỗi vào tên bảng, bạn có thể sử dụng các cơ chế nối chuỗi PHP thông thường. Bạn nên thực hiện thêm chắc chắn mà bạn kiểm tra chuỗi dựa vào cụm từ thông dụng phù hợp nghiêm ngặt, để tránh việc tiêm SQL. Đảm bảo rằng bạn thực sự chỉ dán một chuỗi ngẫu nhiên duy nhất của định dạng mà bạn tạo và không có gì khác. Thay vào đó, bạn có thể có một bảng lớn, chứa tất cả các lựa chọn và sử dụng cột bổ sung để giữ mã nhận dạng của bạn hoặc một số khóa phù hợp khác để xác định một lựa chọn duy nhất. Bằng cách đó, bạn sẽ không phải sửa đổi lược đồ cơ sở dữ liệu trong các hoạt động bình thường. Tôi tin rằng hầu hết các nhà phát triển, tôi bao gồm, thay vì tránh những sửa đổi như vậy bằng mã chương trình. Thiết kế cơ sở dữ liệu tốt hoạt động với một lược đồ cố định.

+0

Xin chào MvG, tôi đã quyết định tạo một bảng cao như bạn đã đề xuất. Làm theo cách này thực sự phù hợp hơn với luồng công việc dự định, và thành thật mà nói, tôi không biết tại sao tôi lại nghĩ cách làm theo cách khác. Cảm ơn bạn đã giúp đỡ! – Dave

0

Nghe có vẻ như tôi muốn bạn sử dụng SQL động. Có thể bạn sẽ phải đi theo con đường của prepared statements. Với họ, bạn có thể gọi PREPARE trên chuỗi và sau đó là EXECUTE. Kết nối bình thường hoạt động tốt.

Điều đó sẽ cho phép bạn tạo SQL của mình dưới dạng chuỗi và thực thi nó. Nếu bạn sử dụng parametrization CodeIgniter kết hợp với thủ tục lưu trữ MySQL, bạn có thể gọi một truy vấn như "CALL selectAlbums(?, ?)" (giả sử selectAlbums là thủ tục được lưu trữ có chứa PREPARE cho truy vấn thực tế), sẽ trả về tập hợp.

Nếu bạn muốn loại bỏ các ' s trong đầu ra, kênh các thông số thông qua CONCAT, mà sẽ tạo ra một chuỗi bình thường.

+0

Báo cáo chuẩn bị không dành cho loại điều này. Họ sử dụng cú pháp câu lệnh bình thường, vì vậy họ sẽ không sử dụng tên bảng động nào dễ dàng hơn. Các câu lệnh được chuẩn bị chỉ là một cách để tăng hiệu suất bằng cách lưu vào bộ nhớ đệm kế hoạch thực hiện cho một câu lệnh đã cho, vì vậy máy chủ đã biết cách tính toán kết quả của một kiểu đã cho. – MvG

+1

Không, đó là chính xác những gì bạn có thể làm với họ. Thậm chí có một ví dụ sử dụng một biến chuỗi cho tên bảng ngay trong tài liệu. Vui lòng đọc nó. Bạn đang nói về các thói quen được lưu trữ. Hoặc, có lẽ, các câu lệnh chuẩn bị của CodeIgniter, là các câu lệnh được chuẩn bị của MySQL API, không phải là cơ chế SQL động được tích hợp trong động cơ. Có một sự khác biệt rất lớn ở đó. – Naltharial

+0

OK, sai lầm của tôi. Tôi đã có C API trong tâm trí, và nghĩ rằng các phía máy chủ chuẩn bị các yếu tố ngôn ngữ tuyên bố sẽ khá nhiều làm như vậy. Chúng xuất hiện để làm nhiều khía cạnh, nhưng việc sử dụng các chuỗi và phía máy chủ 'CONCAT' mở ra các cách mới. Xin lỗi vì tiếng ồn ở đây. Tôi thực sự cần phải đọc các tài liệu cho hai câu nhiều hơn tôi đã làm. – MvG

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