Làm thế nào để có được cơ thể của một POST trong php?


273

Tôi gửi POST dưới dạng trang php như sau:

{a:1}

Đây là phần thân của yêu cầu (một yêu cầu POST).
Trong php, tôi phải làm gì để trích xuất giá trị đó?

var_dump($_POST); 

không phải là giải pháp, không hoạt động.


23
Đây là một câu hỏi hữu ích cho những người muốn tạo API RESTful. Hầu hết không biết làm thế nào để truy cập dữ liệu đầu vào thô được gửi đến tập lệnh của họ vì nó không có sẵn thông qua siêu lớp $_POST. Điều này cũng đúng (đặc biệt) trong trường hợp yêu cầu PUT, vì PHP không có siêu lớp tương ứng.
ndlowrey


1
Điều đáng chú ý là tên $ _POST gây hiểu nhầm, vì không có bất kỳ loại dữ liệu nào từ yêu cầu POST sẽ có ở đó, nhưng chỉ khi loại nội dung là application / x-www-form-urlencoding hoặc
multiart

Câu trả lời:


549

Để truy cập phần thân thực thể của yêu cầu POST hoặc PUT (hoặc bất kỳ phương thức HTTP nào khác):

$entityBody = file_get_contents('php://input');

Ngoài ra, STDINhằng số là một luồng đã mở php://input, vì vậy bạn có thể thay thế:

$entityBody = stream_get_contents(STDIN);

Từ mục nhập thủ công PHP trên tài liệu luồng I / O :

php: // input là luồng chỉ đọc cho phép bạn đọc dữ liệu thô từ thân yêu cầu. Trong trường hợp yêu cầu POST, tốt hơn là sử dụng đầu vào php: // thay vì $HTTP_RAW_POST_DATAkhông phụ thuộc vào các lệnh php.ini đặc biệt. Hơn nữa, đối với những trường hợp $HTTP_RAW_POST_DATAkhông được điền theo mặc định, đây là một giải pháp thay thế ít bộ nhớ hơn để kích hoạt always_population_raw_post_data. php: // đầu vào không khả dụng với enctype = "Multipart / form-data".

Cụ thể, bạn sẽ muốn lưu ý rằng php://inputluồng, bất kể bạn truy cập nó như thế nào trong web SAPI, đều không thể tìm kiếm được . Điều này có nghĩa là nó chỉ có thể được đọc một lần. Nếu bạn đang làm việc trong một môi trường nơi các thực thể HTTP lớn được tải lên thường xuyên, bạn có thể muốn duy trì đầu vào ở dạng luồng của nó (thay vì đệm nó như ví dụ đầu tiên ở trên).

Để duy trì tài nguyên luồng, một cái gì đó như thế này có thể hữu ích:

<?php

function detectRequestBody() {
    $rawInput = fopen('php://input', 'r');
    $tempStream = fopen('php://temp', 'r+');
    stream_copy_to_stream($rawInput, $tempStream);
    rewind($tempStream);

    return $tempStream;
}

php://tempcho phép bạn quản lý mức tiêu thụ bộ nhớ vì nó sẽ chuyển sang lưu trữ hệ thống tập tin một cách trong suốt sau khi một lượng dữ liệu nhất định được lưu trữ (2M theo mặc định). Kích thước này có thể được thao tác trong tệp php.ini hoặc bằng cách nối thêm /maxmemory:NN, trong đó NNlượng dữ liệu tối đa cần giữ trong bộ nhớ trước khi sử dụng tệp tạm thời, tính bằng byte.

Tất nhiên, trừ khi bạn có một lý do thực sự tốt để tìm kiếm trên luồng đầu vào, bạn không nên cần chức năng này trong một ứng dụng web. Đọc phần thân thực thể yêu cầu HTTP một lần thường là đủ - đừng để khách hàng chờ đợi cả ngày trong khi ứng dụng của bạn tìm ra việc cần làm.

Lưu ý rằng php: // input không khả dụng cho các yêu cầu chỉ định Content-Type: multipart/form-datatiêu đề ( enctype="multipart/form-data"ở dạng HTML). Kết quả này từ PHP đã phân tích dữ liệu biểu mẫu vào $_POSTsuperglobal.


17
Xin lưu ý rằng afaics, luồng STDIN không khả dụng trên các hệ thống chạy PHP bằng CGI, tức là thông qua mod_fcgid hoặc mod_fastcgi, v.v.
scy

nhưng, tôi đang chuyển biến (dưới dạng dữ liệu biểu mẫu) với yêu cầu, làm cách nào tôi có thể truy cập giá trị được chỉ định, tôi đang chuyển Grant_type = password & username = user & password = pass dưới dạng thân dữ liệu với yêu cầu, làm cách nào tôi nhận được Grant_type từ "$ entityBody "
Anvar

theo thử nghiệm của tôi, điều này php://inputcũng trống đối với loại application/x-www-form-urlencodednội dung (bên cạnh đó multipart/form-data)
YakovL

6
Để mở rộng phản hồi của @ scy: STDIN không có sẵn, nhưng php://inputlà. Vì vậy, trong khi các cấu hình CGI (Nhanh) stream_get_contents(STDIN)sẽ không hoạt động, file_get_contents("php://input")sẽ.
Sinus Mackowaty

16

trả về giá trị trong mảng

 $data = json_decode(file_get_contents('php://input'), true);

Trong kịch bản này, bây giờ bạn phải lặp qua $datamảng kết hợp để kiểm tra xem mỗi giá trị được mã hóa theo cách bạn muốn. Cách nhìn "stream-to-datatype" có thể đơn giản, nhưng nó có thể không hiệu quả như xử lý mã hóa trong "dạng luồng" bằng bộ lọc luồng. Nếu bạn không xử lý các vấn đề mã hóa và chỉ đơn giản là vệ sinh và xác nhận, bạn đang thiếu một bước.
Anthony Rutledge

13

Một lý do có thể cho một sản phẩm nào $_POSTđó là yêu cầu không còn POSThoặc không POSTcòn nữa ... Nó có thể đã bắt đầu như một bài đăng, nhưng gặp phải 301hoặc 302chuyển hướng ở đâu đó, được chuyển sang GET!

Kiểm tra $_SERVER['REQUEST_METHOD']để kiểm tra nếu đây là trường hợp.

Xem https://stackoverflow.com/a/19422232/109787 để biết một cuộc thảo luận tốt về lý do tại sao điều này không nên xảy ra nhưng vẫn còn.


1
Câu hỏi này đã được hỏi trong bối cảnh phát triển nền tảng api REST.
Itay Moav -Malimovka

Tôi không chắc ý của bạn là gì? Một api REST cũng có thể tìm thấy các chuyển hướng trong đường dẫn của nó, đó là vấn đề tôi gặp phải.
Legolas

Ý tôi là khi tôi đặt câu hỏi, tôi không cố gắng giải quyết một lỗi, mà là cố gắng tìm ra cách phát triển nó.
Itay Moav -Malimovka 17/03/2016

3
gợi ý này đã cứu ngày của tôi. máy chủ nhận đã được cấu hình lại để chuyển hướng đến https whoch đã phá vỡ một số ứng dụng khách API.
DesertEagle

Trên thực tế yêu cầu của tôi là POSTnhưng sau khi kiểm tra nó đã cho thấy rằng nó là GET. Khi tôi đã thêm một /ở cuối URL, nó bắt đầu hiển thị POST. Kỳ dị!
zackygaurav

4

7
Phương pháp ưa thích để truy cập dữ liệu POST thô là php://input. $HTTP_RAW_POST_DATAkhông có sẵn với enctype="multipart/form-data".
nullability

38
Tính năng này đã được ĐỔI trong PHP 5.6.0 và được KHAI THÁC kể từ phiên bản PHP 7.0.0.
Charles


2

Nếu bạn đã cài đặt tiện ích mở rộng pecl / http , bạn cũng có thể sử dụng tiện ích này:

$request = new http\Env\Request();
$request->getBody();

2
function getPost()
{
    if(!empty($_POST))
    {
        // when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request
        // NOTE: if this is the case and $_POST is empty, check the variables_order in php.ini! - it must contain the letter P
        return $_POST;
    }

    // when using application/json as the HTTP Content-Type in the request 
    $post = json_decode(file_get_contents('php://input'), true);
    if(json_last_error() == JSON_ERROR_NONE)
    {
        return $post;
    }

    return [];
}

print_r(getPost());

Cái logic này còn thiếu là một bài kiểm tra giá trị được tìm thấy trong tiêu đề Kiểu nội dung. Nó không tuân theo điều đó chỉ vì $ _POST trống mà JSON phải được gửi hoặc nếu json_last_error() == JSON_ERROR_NONEfalse, thì một mảng trống sẽ được trả về. Nếu ai đó đã gửi XML hoặc YAML thì sao? Thêm một bài kiểm tra cho Kiểu nội dung và đi từ đó.
Anthony Rutledge

Ngoài ra, phương thức yêu cầu HTTP có thể là yếu tố quyết định nếu bạn muốn chấp nhận dữ liệu đầu vào. Xem $_SERVERsuperglobal cho các giá trị hữu ích để kiểm tra.
Anthony Rutledge

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.