Tôi đã được hướng dẫn sử dụng phương thức php://input
thay vì $_POST
khi tương tác với các yêu cầu Ajax từ JQuery. Điều tôi không hiểu là lợi ích của việc sử dụng phương pháp này so với phương pháp toàn cầu $_POST
hoặc $_GET
.
Tôi đã được hướng dẫn sử dụng phương thức php://input
thay vì $_POST
khi tương tác với các yêu cầu Ajax từ JQuery. Điều tôi không hiểu là lợi ích của việc sử dụng phương pháp này so với phương pháp toàn cầu $_POST
hoặc $_GET
.
Câu trả lời:
Lý do là php://input
trả về tất cả dữ liệu thô sau các tiêu đề HTTP của yêu cầu, bất kể loại nội dung.
Siêu lớp PHP $_POST
, chỉ được cho là bao bọc dữ liệu
application/x-www-form-urlencoded
(loại nội dung tiêu chuẩn cho bài viết mẫu đơn giản) hoặcmultipart/form-data
(chủ yếu được sử dụng để tải lên tập tin)Điều này là do đây là các loại nội dung duy nhất phải được hỗ trợ bởi các tác nhân người dùng . Vì vậy, máy chủ và PHP theo truyền thống không mong đợi nhận được bất kỳ loại nội dung nào khác (điều đó không có nghĩa là chúng không thể).
Vì vậy, nếu bạn chỉ cần POST một HTML cũ tốt form
, yêu cầu sẽ trông giống như thế này:
POST /page.php HTTP/1.1
key1=value1&key2=value2&key3=value3
Nhưng nếu bạn đang làm việc với Ajax rất nhiều, thì probaby này cũng bao gồm việc trao đổi dữ liệu phức tạp hơn với các kiểu (chuỗi, int, bool) và cấu trúc (mảng, đối tượng), vì vậy, trong hầu hết các trường hợp, JSON là lựa chọn tốt nhất. Nhưng một yêu cầu có tải trọng JSON sẽ trông giống như thế này:
POST /page.php HTTP/1.1
{"key1":"value1","key2":"value2","key3":"value3"}
Nội dung bây giờ sẽ là application/json
(hoặc ít nhất là không có nội dung nào được đề cập ở trên), vì vậy trình biên dịch của PHP $_POST
không biết cách xử lý (chưa).
Dữ liệu vẫn còn đó, bạn không thể truy cập nó thông qua trình bao bọc. Vì vậy, bạn cần phải tự tìm nạp nó ở định dạng thô với file_get_contents('php://input')
( miễn là nó không được multipart/form-data
mã hóa ).
Đây cũng là cách bạn sẽ truy cập dữ liệu XML hoặc bất kỳ loại nội dung không chuẩn nào khác.
application/json
là nguồn dữ liệu hợp lệ cho $_POST
mảng. Và thậm chí còn có các yêu cầu được công bố để hỗ trợ cụ thể.
php://input
có thể cung cấp cho bạn các byte thô của dữ liệu. Điều này hữu ích nếu dữ liệu POST là cấu trúc được mã hóa JSON, thường là trường hợp cho yêu cầu AJAX POST.
Đây là một chức năng để làm việc đó:
/**
* Returns the JSON encoded POST data, if any, as an object.
*
* @return Object|null
*/
private function retrieveJsonPostData()
{
// get the raw POST data
$rawData = file_get_contents("php://input");
// this returns null if not valid json
return json_decode($rawData);
}
Các $_POST
mảng là hữu ích hơn khi bạn đang xử lý dữ liệu quan trọng có giá trị từ một hình thức, được gửi bởi một POST truyền thống. Điều này chỉ hoạt động nếu dữ liệu đã đăng ở định dạng được công nhận, thường application/x-www-form-urlencoded
(xem http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 để biết chi tiết).
true
tham số thứ hai vào json_decode
, nó sẽ trả về một mảng kết hợp.
Nếu dữ liệu bài viết không đúng định dạng, $ _POST sẽ không chứa bất cứ thứ gì. Tuy nhiên, php: // input sẽ có chuỗi không đúng.
Ví dụ, có một số ứng dụng ajax, không tạo thành chuỗi khóa-giá trị bài chính xác để tải lên tệp và chỉ đổ tất cả tệp dưới dạng dữ liệu bài đăng, không có tên biến hoặc bất cứ điều gì. $ _POST sẽ trống, $ _FILES cũng trống và đầu vào php: // sẽ chứa tệp chính xác, được viết dưới dạng chuỗi.
PHP không được thiết kế để cung cấp cho bạn một giao diện giống như REST (GET, POST, PUT, PATCH, DELETE) rõ ràng để xử lý các yêu cầu HTTP .
Tuy nhiên, $_POST
, $_GET
, và $_FILES
superglobals , và các chức năng filter_input_array()
rất hữu ích cho nhu cầu người bình thường của / layman.
Ưu điểm tiềm ẩn số một của $_POST
(và $_GET
) là dữ liệu đầu vào của bạn được mã hóa tự động bởi PHP . Bạn thậm chí không bao giờ nghĩ về việc phải làm điều đó, đặc biệt là đối với các tham số chuỗi truy vấn trong yêu cầu GET tiêu chuẩn.
Điều đó đang được nói, khi bạn nâng cao kiến thức lập trình và muốn sử dụng XmlHttpRequest
đối tượng JavaScript (jQuery cho một số), bạn sẽ thấy giới hạn của sơ đồ này.
$_POST
giới hạn bạn trong việc sử dụng hai loại phương tiện trong Content-Type
tiêu đề HTTP :
application/x-www-form-urlencoded
vàmultipart/form-data
Do đó, nếu bạn muốn gửi các giá trị dữ liệu tới PHP trên máy chủ và để nó hiển thị trong $_POST
superglobal , thì bạn phải urlencode nó ở phía máy khách và gửi dữ liệu đã nói dưới dạng cặp khóa / giá trị - một bước bất tiện cho người mới (đặc biệt là khi cố gắng tìm hiểu xem các phần khác nhau của URL có yêu cầu các hình thức mã hóa url khác nhau: bình thường, thô, v.v.).
Đối với tất cả những người dùng jQuery của bạn, $.ajax()
phương thức này đang chuyển đổi các cặp khóa / giá trị được mã hóa URL của bạn trước khi truyền chúng đến máy chủ. Bạn có thể ghi đè hành vi này bằng cách cài đặt processData: false
. Chỉ cần đọc tài liệu $ .ajax () và đừng quên gửi loại phương tiện chính xác trong tiêu đề Kiểu nội dung.
Thông thường, nếu bạn đang thực hiện một yêu cầu HTTP bình thường, đồng bộ (khi toàn bộ trang vẽ lại) các biểu mẫu HTML, tác nhân người dùng (trình duyệt web) sẽ urlencode dữ liệu biểu mẫu của bạn cho bạn. Nếu bạn muốn làm một yêu cầu HTTP không đồng bộ bằng cách sử dụng XmlHttpRequest
đối tượng, sau đó bạn phải thời trang một chuỗi urlencoded và gửi nó, nếu bạn muốn dữ liệu đó để hiển thị trong $_POST
superglobal .
Chuyển đổi từ một mảng hoặc đối tượng JavaScript thành một chuỗi urlencoding làm phiền nhiều nhà phát triển (ngay cả với các API mới như Dữ liệu biểu mẫu ). Thay vào đó, họ chỉ có thể gửi JSON và sẽ hiệu quả hơn cho mã máy khách để làm như vậy.
Hãy nhớ (nháy mắt, nháy mắt), nhà phát triển web trung bình không học cách sử dụng XmlHttpRequest
trực tiếp đối tượng, hàm toàn cục, hàm chuỗi, hàm mảng và biểu thức chính quy như bạn và tôi ;-). Urlencoding đối với họ là một cơn ác mộng. ;-)
Việc thiếu xử lý XML và JSON trực quan của PHP khiến nhiều người tắt. Bây giờ bạn sẽ nghĩ nó sẽ là một phần của PHP (thở dài).
XML, JSON và YAML đều có các loại phương tiện có thể được đặt vào Content-Type
tiêu đề HTTP .
Hãy xem IANA có bao nhiêu loại phương tiện (trước đây là các loại MIME).
Hãy xem có bao nhiêu tiêu đề HTTP .
Sử dụng php://input
luồng cho phép bạn vượt qua mức độ trừu tượng của việc ngồi / nắm tay em bé mà PHP đã buộc trên thế giới. :-) Với sức mạnh lớn đến trách nhiệm lớn!
Bây giờ, trước khi bạn xử lý các giá trị dữ liệu được truyền qua php://input
, bạn nên / phải làm một vài điều.
À, HÀ! Có, bạn có thể muốn luồng dữ liệu được gửi vào ứng dụng của mình được mã hóa UTF-8, nhưng làm thế nào bạn có thể biết liệu nó có hay không?
php://input
.Bạn sẽ cố gắng xử lý dữ liệu truyền phát mà không biết có bao nhiêu đầu tiên? Đó là một ý tưởng khủng khiếp . Bạn không thể chỉ dựa vào Content-Length
tiêu đề HTTP để được hướng dẫn về kích thước của luồng đầu vào vì nó có thể bị giả mạo.
Bạn sẽ cần một:
Bạn có định chuyển đổi dữ liệu luồng thành UTF-8 mà không biết mã hóa hiện tại của luồng không? Làm sao? Bộ lọc luồng iconv ( ví dụ về bộ lọc luồng iconv ) dường như muốn mã hóa bắt đầu và kết thúc, như thế này.
'convert.iconv.ISO-8859-1/UTF-8'
Vì vậy, nếu bạn có lương tâm, bạn sẽ cần:
( Cập nhật : 'convert.iconv.UTF-8/UTF-8'
sẽ buộc mọi thứ thành UTF-8, nhưng bạn vẫn phải tính đến các ký tự mà thư viện iconv có thể không biết cách dịch. Nói cách khác, bạn phải xác định cách thực hiện hành động nào khi nhân vật không thể dịch : 1) Chèn một ký tự giả, 2) Thất bại / ném và ngoại lệ).
Bạn không thể chỉ dựa hoàn toàn vào Content-Encoding
tiêu đề HTTP , vì điều này có thể chỉ ra điều gì đó như nén như sau. Đây không phải là những gì bạn muốn đưa ra quyết định liên quan đến iconv.
Content-Encoding: gzip
Phần I: Yêu cầu HTTP liên quan
Phần II: Truyền dữ liệu liên quan
Phần III: Kiểu dữ liệu liên quan
(Hãy nhớ rằng, dữ liệu vẫn có thể là một chuỗi được mã hóa URL mà sau đó bạn phải phân tích cú pháp và giải mã URL).
Phần IV: Giá trị dữ liệu liên quan
Lọc dữ liệu đầu vào.
Xác thực dữ liệu đầu vào.
Các $_POST
superglobal, cùng với các thiết lập php.ini cho giới hạn về đầu vào, là đơn giản hơn cho người không có đạo. Tuy nhiên, việc xử lý mã hóa ký tự sẽ trực quan và hiệu quả hơn nhiều khi sử dụng các luồng vì không cần phải lặp qua các siêu lớp (hay nói chung là mảng) để kiểm tra các giá trị đầu vào cho mã hóa phù hợp.
Vì vậy, tôi đã viết một hàm sẽ lấy dữ liệu POST từ luồng đầu vào php: // .
Vì vậy, thách thức ở đây là chuyển sang phương thức yêu cầu PUT, DELETE OR PATCH và vẫn lấy được dữ liệu bài đăng được gửi cùng với yêu cầu đó.
Tôi đang chia sẻ điều này có lẽ cho một người có thử thách tương tự. Các chức năng dưới đây là những gì tôi đã đưa ra và nó hoạt động. Tôi hy vọng nó sẽ giúp!
/**
* @method Post getPostData
* @return array
*
* Convert Content-Disposition to a post data
*/
function getPostData() : array
{
// @var string $input
$input = file_get_contents('php://input');
// continue if $_POST is empty
if (strlen($input) > 0 && count($_POST) == 0 || count($_POST) > 0) :
$postsize = "---".sha1(strlen($input))."---";
preg_match_all('/([-]{2,})([^\s]+)[\n|\s]{0,}/', $input, $match);
// update input
if (count($match) > 0) $input = preg_replace('/([-]{2,})([^\s]+)[\n|\s]{0,}/', '', $input);
// extract the content-disposition
preg_match_all("/(Content-Disposition: form-data; name=)+(.*)/m", $input, $matches);
// let's get the keys
if (count($matches) > 0 && count($matches[0]) > 0)
{
$keys = $matches[2];
foreach ($keys as $index => $key) :
$key = trim($key);
$key = preg_replace('/^["]/','',$key);
$key = preg_replace('/["]$/','',$key);
$key = preg_replace('/[\s]/','',$key);
$keys[$index] = $key;
endforeach;
$input = preg_replace("/(Content-Disposition: form-data; name=)+(.*)/m", $postsize, $input);
$input = preg_replace("/(Content-Length: )+([^\n]+)/im", '', $input);
// now let's get key value
$inputArr = explode($postsize, $input);
// @var array $values
$values = [];
foreach ($inputArr as $index => $val) :
$val = preg_replace('/[\n]/','',$val);
if (preg_match('/[\S]/', $val)) $values[$index] = trim($val);
endforeach;
// now combine the key to the values
$post = [];
// @var array $value
$value = [];
// update value
foreach ($values as $i => $val) $value[] = $val;
// push to post
foreach ($keys as $x => $key) $post[$key] = isset($value[$x]) ? $value[$x] : '';
if (is_array($post)) :
$newPost = [];
foreach ($post as $key => $val) :
if (preg_match('/[\[]/', $key)) :
$k = substr($key, 0, strpos($key, '['));
$child = substr($key, strpos($key, '['));
$child = preg_replace('/[\[|\]]/','', $child);
$newPost[$k][$child] = $val;
else:
$newPost[$key] = $val;
endif;
endforeach;
$_POST = count($newPost) > 0 ? $newPost : $post;
endif;
}
endif;
// return post array
return $_POST;
}
Ví dụ đơn giản về cách sử dụng nó
<?php
if(!isset($_POST) || empty($_POST)) {
?>
<form name="form1" method="post" action="">
<input type="text" name="textfield"><br />
<input type="submit" name="Submit" value="submit">
</form>
<?php
} else {
$example = file_get_contents("php://input");
echo $example; }
?>