filter_var($value, FILTER_VALIDATE_EMAIL) trả về giá trị khi đó là một địa chỉ email hợp lệ và false khi không phải. Đổi bộ lọc để kiểm tra các định dạng khác: FILTER_VALIDATE_INT, FILTER_VALIDATE_FLOAT, FILTER_VALIDATE_URL, FILTER_VALIDATE_BOOL, FILTER_VALIDATE_IP. Luôn so sánh kết quả với === false.
Có hai kết quả khiến nhiều người bất ngờ. ada@example bị từ chối vì tên miền không có dấu chấm, còn ' ada@example.com' bị từ chối vì có khoảng trắng ở đầu, nên hãy trim() đầu vào trước khi kiểm tra.
Kiểm tra email từ form
Vẫn phép kiểm tra đó, nhưng đặt sau một form. Chạy code, nhập một địa chỉ rồi nhấn Check; khối code sẽ chạy lại với dữ liệu bạn nhập trong $_POST.
FILTER_VALIDATE_EMAIL chỉ kiểm tra định dạng. nobody@example.com vẫn qua, và một địa chỉ gõ sai tên miền cũng vậy. Ký tự ngoài ASCII bị từ chối: adä@example.com chỉ qua khi có FILTER_FLAG_EMAIL_UNICODE, flag cho phép các ký tự này ở trước @, còn tên miền như exämple.com vẫn bị từ chối dù có flag, trừ khi bạn chuyển nó sang dạng xn-- trước. Cách duy nhất để biết một địa chỉ dùng được là gửi đến đó một liên kết xác nhận.
Kiểm tra số nguyên với min_range và max_range
FILTER_VALIDATE_INT chuyển một chuỗi hợp lệ thành int và từ chối mọi thứ khác. Mảng tùy chọn cho phép thêm khoảng giá trị và giá trị mặc định:
Khoảng trắng ở hai đầu và dấu + ở đầu được chấp nhận, số 0 ở đầu ('042') thì không, và kết quả của '42' là số nguyên 42, không phải chuỗi. Ngoài khoảng cho phép sẽ trả về false; có tùy chọn default thì bạn nhận giá trị mặc định thay cho false, rất tiện cho những thứ như ?page= (xem _POST). Thêm FILTER_FLAG_ALLOW_HEX hoặc FILTER_FLAG_ALLOW_OCTAL để chấp nhận 0x1A hay 0755.
Cái bẫy 0 và false
Chuỗi '0' hợp lệ trả về số nguyên 0, mà 0 là falsy. Một câu if đơn giản sẽ coi đó là thất bại:
Điều này cũng đúng với FILTER_VALIDATE_FLOAT ('0.0') và FILTER_VALIDATE_BOOL, nơi false là một câu trả lời hợp lệ. FILTER_NULL_ON_FAILURE sinh ra chính là để giải quyết chuyện này.
Boolean, số thực, URL và địa chỉ IP
FILTER_VALIDATE_BOOL là tên trong PHP 8; FILTER_VALIDATE_BOOLEAN là cùng một bộ lọc. Nếu không có FILTER_NULL_ON_FAILURE, 'maybe' sẽ trả về false, không phân biệt được với 'off'.
URL hợp lệ chưa chắc là liên kết an toàn
FILTER_VALIDATE_URL kiểm tra chuỗi có hình dạng của một URL hay không, với scheme bất kỳ. Trong đó có cả những scheme bạn không bao giờ muốn thấy trong href:
javascript://comment%0Aalert(1) vượt qua FILTER_VALIDATE_URL, và trình duyệt sẽ chạy nó như JavaScript khi người dùng bấm vào liên kết, vì %0A kết thúc phần //comment. Hãy kiểm tra scheme bằng parse_url() trước khi in URL của người dùng vào trang. Bạn cũng có thể bắt buộc một số phần bằng FILTER_FLAG_PATH_REQUIRED và FILTER_FLAG_QUERY_REQUIRED.
Bộ lọc sanitize
Bộ lọc sanitize xóa bớt ký tự thay vì trả lời có hay không. Chúng hữu ích để chuẩn hóa đầu vào, chứ không giúp in ra an toàn:
Hãy nhìn dòng đầu tiên: Order #12-345 (x2) trở thành 12-3452, một con số chưa từng có trong đầu vào, còn dòng thứ ba là một địa chỉ không ai gõ cả. Nếu bạn sanitize, hãy kiểm tra lại kết quả sau đó. Với mọi thứ bạn in vào HTML, htmlspecialchars() lúc xuất ra mới là công cụ đúng (FILTER_SANITIZE_FULL_SPECIAL_CHARS escape theo cùng cách). FILTER_SANITIZE_STRING đã bị deprecated từ PHP 8.1; xem htmlspecialchars để biết nên dùng gì thay thế.
Kiểm tra cả form với filter_var_array
filter_var_array() áp dụng một bộ lọc cho mỗi khóa và trả về một mảng chứa mọi khóa bạn yêu cầu: giá trị đã lọc, false khi kiểm tra thất bại, hoặc null khi thiếu khóa.
role đã biến mất: các khóa bạn không liệt kê đều bị bỏ, điều này ngăn người truy cập thêm role=admin vào form rồi được lưu lại. country là null vì không được gửi lên. Trên máy chủ web, filter_input_array(INPUT_POST, $rules) làm điều tương tự nhưng đọc thẳng từ request.
Câu hỏi thường gặp
Làm sao kiểm tra địa chỉ email trong PHP?
Dùng filter_var($email, FILTER_VALIDATE_EMAIL), hàm này trả về chuỗi email nếu hợp lệ và false nếu không: if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { /* invalid */ }. Hàm chỉ kiểm tra định dạng; muốn biết địa chỉ có tồn tại hay không, bạn cần gửi email xác nhận.
Làm sao kiểm tra một chuỗi có phải số nguyên trong PHP?
filter_var($s, FILTER_VALIDATE_INT) trả về số nguyên với "42", "-7" và " 42 ", còn với "4.2", "42abc" hay "042" thì trả về false. Hãy so sánh bằng !== false, vì "0" hợp lệ sẽ trả về 0, một giá trị falsy.
Vì sao filter_var trả về false với 0?
Thật ra không phải vậy: filter_var('0', FILTER_VALIDATE_INT) trả về số nguyên 0. Lỗi nằm ở câu kiểm tra if (filter_var(...)), vốn coi 0 như false. Hãy viết if (filter_var($v, FILTER_VALIDATE_INT) !== false).
FILTER_SANITIZE_STRING được thay bằng gì trong PHP 8.1?
Không có thứ gì thay thế trực tiếp; nó bị deprecated vì cái tên hứa hẹn sự an toàn mà nó không mang lại. Hãy kiểm tra đầu vào theo đúng kiểu bạn mong đợi, lưu nguyên như vậy và escape khi in ra bằng htmlspecialchars(). Nếu cần bỏ thẻ HTML, dùng strip_tags().
filter_var và filter_input khác nhau thế nào?
filter_var() lọc bất kỳ giá trị nào bạn truyền vào. filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT) đọc thẳng từ request gốc, nên trả về null khi thiếu tham số và bỏ qua mọi thay đổi mà code của bạn đã làm với $_GET. Cả hai nhận cùng bộ lọc và tùy chọn.