Bagaimana cara mendapatkan tubuh POST di php?

273

Saya mengirimkan sebagai POST ke halaman php berikut ini:

{a:1}

Ini adalah badan permintaan (permintaan POST).
Dalam php, apa yang harus saya lakukan untuk mengekstraksi nilai itu?

var_dump($_POST); 

bukan solusinya, tidak bekerja.

Itay Moav -Malimovka
sumber
23
Ini adalah pertanyaan yang bermanfaat bagi orang yang ingin membuat API RESTful. Sebagian besar tidak tahu cara mengakses data input mentah yang dikirim ke skrip mereka karena tidak tersedia melalui $_POSTsuperglobal. Ini juga (terutama) benar dalam kasus permintaan PUT, karena PHP tidak memiliki superglobal yang sesuai.
rdlowrey
4
Kemungkinan duplikat dari Cara mendapatkan konten permintaan (isi) di PHP?
YakovL
1
Perlu dicatat bahwa nama $ _POST menyesatkan, karena tidak semua jenis data dari permintaan POST akan ada di sana, tetapi hanya ketika jenis kontennya adalah aplikasi / x-www-form-urlencoded atau multipart / form-data
Petruza

Jawaban:

549

Untuk mengakses badan entitas dari permintaan POST atau PUT (atau metode HTTP lainnya):

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

Selain itu, STDINkonstanta adalah aliran yang sudah terbuka php://input, sehingga Anda dapat melakukannya sebagai alternatif:

$entityBody = stream_get_contents(STDIN);

Dari entri manual PHP pada I / O streams docs :

php: // input adalah aliran hanya baca yang memungkinkan Anda membaca data mentah dari badan permintaan. Dalam hal permintaan POST, lebih baik menggunakan php: // input daripada $HTTP_RAW_POST_DATAtidak tergantung pada arahan khusus php.ini. Selain itu, untuk kasus-kasus di mana $HTTP_RAW_POST_DATAtidak diisi secara default, itu berpotensi alternatif yang kurang intensif memori untuk mengaktifkan always_populate_raw_post_data. php: // input tidak tersedia dengan enctype = "multipart / form-data".

Khususnya Anda ingin mencatat bahwa php://inputaliran, terlepas dari bagaimana Anda mengaksesnya di web SAPI, tidak dapat dicari . Ini berarti hanya dapat dibaca sekali. Jika Anda bekerja di lingkungan tempat entitas entitas HTTP besar diunggah secara rutin, Anda mungkin ingin mempertahankan input dalam bentuk alirannya (alih-alih buffering seperti contoh pertama di atas).

Untuk menjaga sumber daya aliran, sesuatu seperti ini dapat membantu:

<?php

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

    return $tempStream;
}

php://tempmemungkinkan Anda untuk mengelola konsumsi memori karena akan secara transparan beralih ke penyimpanan sistem file setelah sejumlah data disimpan (secara default 2M). Ukuran ini dapat dimanipulasi dalam file php.ini atau dengan menambahkan /maxmemory:NN, di mana NNjumlah maksimum data yang disimpan dalam memori sebelum menggunakan file sementara, dalam byte.

Tentu saja, kecuali Anda memiliki alasan yang sangat bagus untuk mencari di aliran input, Anda seharusnya tidak memerlukan fungsi ini dalam aplikasi web. Membaca badan entitas HTTP permintaan biasanya sudah cukup - jangan biarkan klien menunggu sepanjang hari sementara aplikasi Anda menentukan apa yang harus dilakukan.

Perhatikan bahwa php: // input tidak tersedia untuk permintaan yang menentukan Content-Type: multipart/form-dataheader ( enctype="multipart/form-data"dalam bentuk HTML). Ini hasil dari PHP sudah mem-parsing formulir data ke $_POSTsuperglobal.

rdlowrey
sumber
17
Harap dicatat bahwa afaics, aliran STDIN tidak tersedia pada sistem yang menjalankan PHP menggunakan CGI, yaitu via mod_fcgid atau mod_fastcgi dll.
scy
tapi, saya meneruskan variabel (sebagai formulir-data) dengan permintaan, bagaimana saya bisa mengakses nilai yang ditentukan, saya melewati grant_type = kata sandi & nama pengguna = pengguna & kata sandi = lulus sebagai bentuk-data badan dengan permintaan, bagaimana saya akan mendapatkan hibah_type dari "$ entitasBody "
Anvar Pk
menurut pengujian saya, ini php://inputjuga kosong untuk application/x-www-form-urlencodedtipe konten (selain multipart/form-data)
YakovL
6
Untuk memperluas tanggapan @ scy: STDIN tidak tersedia, tetapi php://inputada. Jadi, sementara pada konfigurasi (Cepat) CGI stream_get_contents(STDIN)tidak akan berfungsi, file_get_contents("php://input")akan.
Sinus Mackowaty
16

mengembalikan nilai dalam array

 $data = json_decode(file_get_contents('php://input'), true);
umesh bhanderi
sumber
Dalam skenario ini, Anda sekarang harus mengulang melalui $dataarray asosiatif untuk memeriksa apakah setiap nilai dikodekan sesuai keinginan Anda. Cara "stream-to-datatype" dalam melihat sesuatu mungkin sederhana, tetapi mungkin tidak seefisien berurusan dengan pengkodean dalam "bentuk aliran" menggunakan filter aliran. Jika Anda tidak menangani masalah penyandian dan hanya membersihkan dan memvalidasi, Anda kehilangan satu langkah.
Anthony Rutledge
13

Kemungkinan alasan untuk kosong $_POSTadalah bahwa permintaannya bukan POST, atau tidak POSTlagi ... Itu mungkin sudah dimulai sebagai pos, tetapi menemui 301atau 302mengarahkan ulang ke suatu tempat, yang dialihkan ke GET!

Periksa $_SERVER['REQUEST_METHOD']untuk memeriksa apakah ini masalahnya.

Lihat https://stackoverflow.com/a/19422232/109787 untuk diskusi yang baik tentang mengapa hal ini tidak boleh terjadi tetapi masih terjadi.

Legolas
sumber
1
Pertanyaan ini diajukan dalam konteks pengembangan platform api REST.
Itay Moav -Malimovka
Saya tidak yakin apa yang Anda maksud? Api REST mungkin juga menemukan pengalihan di jalurnya, itulah masalah yang saya miliki.
Legolas
Maksud saya ketika saya mengajukan pertanyaan, saya tidak mencoba menyelesaikan bug, tetapi mencoba mencari tahu bagaimana mengembangkannya.
Itay Moav -Malimovka
3
petunjuk ini menyelamatkan hari saya. server penerima telah dikonfigurasi ulang untuk mengarahkan ulang ke https whoch memecahkan beberapa klien API.
DesertEagle
Sebenarnya permintaan saya adalah POSTtetapi setelah memeriksanya ternyata memang benar GET. Setelah saya menambahkan /di akhir URL saya, itu mulai menunjukkan POST. Aneh!
zackygaurav
4

Periksa $HTTP_RAW_POST_DATAvariabelnya

linepogl
sumber
7
Metode yang disukai untuk mengakses data POST mentah adalah php://input. $HTTP_RAW_POST_DATAtidak tersedia dengan enctype="multipart/form-data".
nullability
38
Fitur ini DIHAPUSKAN dalam PHP 5.6.0, dan DIHAPUS pada PHP 7.0.0.
Charles
3

Jika Anda telah menginstal ekstensi HTTP PECL, Anda dapat menggunakan http_get_request_body()fungsi ini untuk mendapatkan data tubuh sebagai string.

shivanshu patel
sumber
fungsi tidak ada.
Rick
2

Jika Anda menginstal ekstensi pecl / http , Anda juga dapat menggunakan ini:

$request = new http\Env\Request();
$request->getBody();
spinkus
sumber
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());
Hatzegopteryx
sumber
Yang sedikit hilang dari logika ini adalah pengujian nilai yang ditemukan di header Tipe Konten. Ini tidak berarti bahwa hanya karena $ _POST kosong yang JSON harus telah disampaikan, atau bahwa jika json_last_error() == JSON_ERROR_NONEadalah false, bahwa array kosong harus dikembalikan. Bagaimana jika seseorang telah mengirimkan XML atau YAML? Tambahkan tes untuk Tipe-Konten dan pergi dari sana.
Anthony Rutledge
Selain itu, metode permintaan HTTP dapat menjadi faktor dalam menentukan apakah Anda ingin menerima data input. Lihat $_SERVERsuperglobal untuk mengetahui nilai berguna.
Anthony Rutledge