Menu

$_GET và $_POST trong PHP: đọc query string và dữ liệu form

$_GET chứa query string của URL (?page=2 cho bạn $_GET['page']) còn $_POST chứa các trường của form gửi bằng method="post". Tìm hiểu cách đọc cả hai an toàn, tạo liên kết bằng http_build_query, kiểm tra $_SERVER['REQUEST_METHOD'] và chọn giữa GET với POST.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

$_GET là một mảng chứa query string của URL, nên article.php?id=42&lang=en cho bạn $_GET['id'] === '42' và $_GET['lang'] === 'en'. $_POST là một mảng chứa các trường của form gửi bằng method="post". Hãy đọc cả hai kèm giá trị mặc định, $_GET['id'] ?? null, vì khóa sẽ không tồn tại mỗi khi thiếu tham số.

Chạy khối code, rồi bấm vào các liên kết: mỗi lần bấm, script chạy lại với $_GET được lấy từ query string của liên kết.

$_GET['lang'] là bất cứ thứ gì URL ghi, không chỉ ba liên kết bạn đã in ra. Ai cũng có thể gõ ?lang=<script> vào thanh địa chỉ, đó là lý do khối code tra giá trị trong $languages thay vì in thẳng nó ra, và escape ở chỗ duy nhất có in dữ liệu từ request.

Đọc một số từ query string

Mọi giá trị trong $_GET đều là chuỗi. Với số trang, hãy kiểm tra và chuyển kiểu trong một bước bằng filter_var() và dùng giá trị mặc định khi giá trị bị thiếu, không phải số hoặc nằm ngoài khoảng. Bấm qua các trang, rồi thử các liên kết Page 999 và Page abc.

filter_var() trả về số nguyên 3 với "3" và trả về tùy chọn default với mọi chuỗi khác, nên $page luôn là một số nguyên dùng được. Trang filter_var liệt kê các bộ kiểm tra khác.

Đọc dữ liệu form với $_POST

Form có method="post" gửi các trường trong phần thân request, và PHP đặt chúng vào $_POST theo name của từng ô nhập. $_SERVER['REQUEST_METHOD'] cho bạn biết request hiện tại là lần truy cập đầu (GET) hay là lần submit (POST). Điền form rồi nhấn Send để xem cả hai.

Ô văn bản để trống vẫn được gửi đi, dưới dạng "", nên sau khi submit $_POST['title'] vẫn tồn tại dù người truy cập không gõ gì. Trên máy chủ, REQUEST_METHOD luôn có giá trị; ?? 'GET' chỉ giúp script không báo lỗi khi bạn chạy tệp bằng php trên dòng lệnh. Mẫu đầy đủ để kiểm tra và hiển thị lại form có ở trang form.

Form tìm kiếm với method="get"

Dùng GET cho form mà kết quả nên là một URL chia sẻ được, như ô tìm kiếm. Trình duyệt biến các trường thành query string (?q=sort&level=beginner) và script đọc chúng từ $_GET, y hệt một liên kết. Hãy tìm array hoặc string.

Tạo liên kết với http_build_query

Tự viết "?q=$q&page=2" sẽ hỏng ngay khi $q chứa khoảng trắng, & hoặc #. http_build_query() mã hóa mọi giá trị giúp bạn, và kết quả đi qua htmlspecialchars() khi được đặt vào href, vì trong HTML & nên là &amp;.

parse_str() với hai đối số chính là cách PHP tạo $_GET từ một query string, nên rất tiện khi kiểm thử. Luôn truyền đối số thứ hai; dạng một đối số cũ vốn tạo ra biến đã bị bỏ trong PHP 8.

$_REQUEST và lý do nên tránh

$_REQUEST là $_GET và $_POST gộp thành một mảng. Các tệp php.ini đi kèm PHP đặt request_order = "GP", nên khi cả hai có cùng một khóa, POST thắng; không có thiết lập đó, cookie cũng bị gộp vào:

<?php
// POST /save.php?id=1 with a form field id=2
echo $_GET['id'];      // "1"
echo $_POST['id'];     // "2"
echo $_REQUEST['id'];  // "2"

Trông thì tiện, nhưng nó che giấu nguồn gốc của giá trị. Một đoạn xử lý xóa bản ghi dựa trên $_REQUEST['id'] có thể bị kích hoạt bởi một liên kết đơn giản, đúng thứ mà các thao tác chỉ dùng POST muốn ngăn chặn. Hãy đọc $_GET hoặc $_POST theo đúng tên.

GET hay POST: nên dùng cái nào

GETPOST
Dữ liệu đi qua đâuTrong URL: ?q=php&page=2Trong phần thân request
Đọc bằng$_GET$_POST
Bookmark, chia sẻ, nút quay lạiCóKhông (trình duyệt hỏi có gửi lại không)
Độ dàiGiới hạn bởi URL (vài nghìn ký tự là an toàn)Giới hạn bởi post_max_size (mặc định 8M)
Tải tệp lênKhôngCó, với enctype="multipart/form-data" (đọc $_FILES)
Dùng choTìm kiếm, bộ lọc, sắp xếp, phân trangĐăng nhập, đăng ký, lưu, xóa, thanh toán

Quy tắc quan trọng nhất: một request GET không được thay đổi bất cứ thứ gì. Trình duyệt tải trước liên kết, crawler đi theo liên kết, và mọi người chia sẻ liên kết, nên một liên kết ?delete=5 sớm muộn cũng sẽ bị một thứ không hề có ý định xóa đi theo. Bản thân không phương thức nào được mã hóa: HTTPS bảo vệ cả hai, còn POST chỉ giữ dữ liệu khỏi URL, lịch sử trình duyệt và log của máy chủ.

Câu hỏi thường gặp

Làm sao lấy một tham số từ URL trong PHP?

Đọc nó từ $_GET kèm giá trị mặc định: với page.php?id=42, $id = $_GET['id'] ?? null; cho bạn chuỗi "42". Mọi giá trị đều là chuỗi (hoặc mảng với id[]=), nên hãy chuyển kiểu và kiểm tra, ví dụ bằng filter_var($id, FILTER_VALIDATE_INT).

$_GET và $_POST khác nhau thế nào?

$_GET đến từ query string của URL, nên nhìn thấy được, lưu bookmark được và bị giới hạn độ dài; hãy dùng nó cho tìm kiếm, bộ lọc và phân trang. $_POST đến từ phần thân request của form gửi bằng method="post"; hãy dùng nó cho mọi thứ làm thay đổi dữ liệu, như lưu, mua hàng hay đăng nhập.

Làm sao kiểm tra một tham số GET có tồn tại trong PHP?

Dùng isset($_GET['q']), trả về false khi khóa không có hoặc là null. Để coi cả giá trị rỗng (?q=) là không có, hãy so sánh giá trị đã trim: trim($_GET['q'] ?? '') !== ''.

Có nên dùng $_REQUEST trong PHP không?

Thường là không. $_REQUEST gộp $_GET và $_POST (và tùy theo request_order, cả cookie), nên bạn không biết giá trị đến từ đâu, và một liên kết có thể cung cấp giá trị mà bạn tưởng đến từ form. Hãy đọc rõ ràng $_GET hoặc $_POST.

Làm sao biết một request là GET hay POST trong PHP?

So sánh $_SERVER['REQUEST_METHOD']: if ($_SERVER['REQUEST_METHOD'] === 'POST') { ... }. Cách này đáng tin cậy hơn isset($_POST['submit']), vốn thất bại khi nút không có name hoặc khi form được gửi bằng JavaScript hay một script khác không có trường đó.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu