PHP “php: // input” vs $ _POST

243

Saya telah diarahkan untuk menggunakan metode php://inputalih-alih $_POSTketika berinteraksi dengan permintaan Ajax dari JQuery. Apa yang saya tidak mengerti adalah manfaat menggunakan ini vs metode global $_POSTatau $_GET.

Lee
sumber
2
Saya dulu menggunakan "peretasan" untuk menerima panggilan ajax di sisi PHP sebelum menemukan posting ini dan membaca jawabannya yang luar biasa! Untuk orang lain yang memiliki masalah yang sama di masa depan, saya berharap mesin pencari akan membaca komentar saya juga! :)
aderchox

Jawaban:

484

Alasannya adalah bahwa php://inputmengembalikan semua data mentah setelah HTTP-header permintaan, terlepas dari jenis konten.

Superglobal PHP $_POST, hanya seharusnya membungkus data yang baik

  • application/x-www-form-urlencoded (tipe konten standar untuk posting bentuk sederhana) atau
  • multipart/form-data (kebanyakan digunakan untuk unggah file)

Ini karena ini adalah satu-satunya jenis konten yang harus didukung oleh agen pengguna . Jadi server dan PHP biasanya tidak berharap untuk menerima tipe konten lain (yang tidak berarti mereka tidak bisa).

Jadi, jika Anda hanya POST HTML lama yang baik form, permintaan terlihat seperti ini:

POST /page.php HTTP/1.1

key1=value1&key2=value2&key3=value3

Tetapi jika Anda sering bekerja dengan Ajax, probaby ini juga termasuk bertukar data yang lebih kompleks dengan tipe (string, int, bool) dan struktur (array, objek), sehingga dalam banyak kasus JSON adalah pilihan terbaik. Tetapi permintaan dengan payload JSON akan terlihat seperti ini:

POST /page.php HTTP/1.1

{"key1":"value1","key2":"value2","key3":"value3"}

Konten sekarang akan application/json(atau setidaknya tidak ada yang disebutkan di atas), jadi PHP- $_POSTpembungkus tidak tahu bagaimana mengatasinya (belum).

Data masih ada, Anda tidak bisa mengaksesnya melalui pembungkus. Jadi, Anda perlu mengambilnya sendiri dalam format mentah dengan file_get_contents('php://input')( asalkan tidak multipart/form-data-dipode ).

Ini juga cara Anda mengakses data XML atau jenis konten non-standar lainnya.

Quasdunk
sumber
40
+1 untuk "Ini juga bagaimana Anda akan mengakses data-XML atau tipe konten non-standar lainnya"
mandza
@Quasdank Saya mengirim JSON dari aplikasi Android ke server xampp php di cloud ( stackoverflow.com/questions/36558261/... ) tapi saya tidak bisa membuatnya berfungsi ketika saya mencoba file_get_contents ('php: // input'), yang hanya mengembalikan string (0). Ini digunakan untuk bekerja di mesin lokal saya tetapi tidak berfungsi ketika saya menyebarkannya ke cloud. Bisakah kamu membantuku?
The_Martian
1
Perlu dicatat bahwa penggunaan objek XMLHttpRequest dalam permintaan AJAX ke PHP tidak berarti seseorang harus memposting JSON. Ini adalah overhead tambahan, tetapi JavaScript sisi klien Anda dapat dikonversi ke format application / x-www-form-urlencoded. Namun, terjemahan mungkin bukan tipe data murni .
Anthony Rutledge
Perlu untuk mengatakan bahwa batas dua tipe konten yang dikenali sebagian besar bersifat historis. Tidak ada yang menghentikan PHP mengenali yaitu application/jsonsebagai sumber data yang valid untuk $_POSTarray. Dan bahkan ada permintaan khusus untuk dukungan yang dipublikasikan.
AnrDaemon
Hai @quasdunk tolong bantu saya di magento.stackexchange.com/questions/296960/…
Nagaraju K
53

php://inputdapat memberi Anda byte mentah data. Ini berguna jika data POSTed adalah struktur yang dikodekan JSON, yang sering terjadi untuk permintaan POST AJAX.

Inilah fungsi untuk melakukan hal itu:

  /**
   * 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);
  }

The $_POSTarray lebih berguna ketika Anda menangani data kunci-nilai dari bentuk, disampaikan oleh POST tradisional. Ini hanya berfungsi jika data POSTed dalam format yang dikenal, biasanya application/x-www-form-urlencoded(lihat http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4 untuk detailnya).

Rob Agar
sumber
7
Perlu dicatat bahwa jika Anda meneruskan truesebagai parameter kedua json_decode, itu akan mengembalikan array asosiatif.
Vahid Amiri
28

Jika data posting salah format, $ _POST tidak akan berisi apa pun. Namun, input php: // akan memiliki string yang salah bentuk.

Misalnya ada beberapa aplikasi ajax, yang tidak membentuk urutan nilai kunci posting yang benar untuk mengunggah file, dan hanya membuang semua file sebagai data posting, tanpa nama variabel atau apa pun. $ _POST akan kosong, $ _FILES juga kosong, dan php: // input akan berisi file yang tepat, ditulis sebagai string.

Tanpa nama
sumber
22

Pertama, kebenaran dasar tentang PHP.

PHP tidak dirancang untuk secara eksplisit memberi Anda SISA murni (GET, POST, PUT, PATCH, DELETE) seperti antarmuka untuk menangani permintaan HTTP .

Namun, $_POST, $_GET, dan $_FILES superglobals , dan fungsi filter_input_array()yang sangat berguna untuk kebutuhan rata-rata orang / awam.

Keuntungan tersembunyi nomor satu dari $_POST(dan $_GET) adalah bahwa data input Anda di- urecode secara otomatis oleh PHP . Anda bahkan tidak pernah berpikir harus melakukannya, terutama untuk parameter string kueri dalam permintaan GET standar.

Namun, maka Anda belajar lebih banyak ...

Yang sedang berkata, saat Anda maju dalam pengetahuan pemrograman Anda dan ingin menggunakan JavaScript XmlHttpRequest (jQuery untuk beberapa), Anda datang untuk melihat batasan skema ini.

$_POSTmembatasi Anda untuk penggunaan dua jenis media dalam Content-Typetajuk HTTP :

  1. application/x-www-form-urlencoded, dan
  2. multipart/form-data

Dengan demikian, jika Anda ingin mengirim nilai data ke PHP di server, dan menampilkannya di $_POSTsuperglobal , maka Anda harus urlencode di sisi klien dan mengirim data tersebut sebagai pasangan kunci / nilai - langkah yang tidak nyaman untuk pemula (terutama ketika mencoba mencari tahu apakah bagian URL yang berbeda memerlukan bentuk urlencoding yang berbeda: normal, mentah, dll.).

Untuk semua Anda pengguna jQuery, $.ajax()metode ini mengubah JSON Anda ke pasangan kunci / nilai yang disandikan URL sebelum mengirimkannya ke server. Anda dapat mengganti perilaku ini dengan menetapkan processData: false. Baca saja dokumentasi $ .ajax () , dan jangan lupa untuk mengirim jenis media yang benar di header Tipe-Konten.

Pengkodean URL? Apa apaan!!!???

Biasanya, jika Anda melakukan normal, sinkron (ketika seluruh halaman redraws) permintaan HTTP dengan formulir HTML, agen-pengguna (browser web) akan urlencode data formulir Anda untuk Anda. Jika Anda ingin melakukan permintaan HTTP asinkron menggunakan XmlHttpRequestobjek, maka Anda harus membuat string urlencoded dan mengirimkannya, jika Anda ingin data itu muncul di $_POSTsuperglobal .

Seberapa dekat Anda dengan JavaScript? :-)

Konversi dari array JavaScript atau objek ke string urlencoded mengganggu banyak pengembang (bahkan dengan API baru seperti Formulir Data ). Mereka lebih suka mengirim JSON, dan akan lebih efisien bagi kode klien untuk melakukannya.

Ingat (mengedipkan mata, mengedipkan mata), rata-rata pengembang web tidak belajar untuk menggunakan XmlHttpRequest objek secara langsung, fungsi global, fungsi string, fungsi array, dan ekspresi reguler seperti Anda dan saya ;-). Urlencoding untuk mereka adalah mimpi buruk. ;-)

PHP, apa yang menyebabkannya?

Kurangnya PHP XML intuitif dan penanganan JSON mematikan banyak orang. Anda akan berpikir itu akan menjadi bagian dari PHP sekarang (menghela nafas).

Begitu banyak jenis media (tipe MIME di masa lalu)

XML, JSON, dan YAML semuanya memiliki tipe media yang dapat dimasukkan ke dalam Content-Typeheader HTTP .

  • aplikasi / xml
  • application / json
  • application / yaml (walaupun IANA tidak memiliki sebutan resmi terdaftar)

Lihat berapa banyak jenis media (sebelumnya, tipe MIME) yang ditentukan oleh IANA.

Lihat berapa banyak header HTTP ada.

php: // input atau bust

Menggunakan php://input aliran memungkinkan Anda menghindari tingkat abstraksi baby-sitting / hand holding yang dipaksakan PHP di dunia. :-) Dengan kekuatan besar datang tanggung jawab besar!

Sekarang, sebelum Anda berurusan dengan nilai data yang mengalir php://input, Anda harus / harus melakukan beberapa hal.

  1. Tentukan apakah metode HTTP yang benar telah ditunjukkan (DAPATKAN, POST, PUT, PATCH, DELETE, ...)
  2. Menentukan apakah header Jenis Konten HTTP telah dikirimkan.
  3. Tentukan apakah nilai untuk Tipe-Konten adalah tipe media yang diinginkan.
  4. Menentukan apakah data yang dikirim berbentuk XML / JSON / YMAL / dll.
  5. Jika perlu, konversikan data ke tipe data PHP: array atau objek.
  6. Jika salah satu dari pemeriksaan dasar atau konversi ini gagal, berikan pengecualian !

Bagaimana dengan pengkodean karakter?

AH, HA! Ya, Anda mungkin ingin aliran data yang dikirim ke aplikasi Anda dikodekan UTF-8, tetapi bagaimana Anda bisa tahu apakah itu atau tidak?

Dua masalah kritis.

  1. Anda tidak tahu berapa banyak data yang masuk php://input.
  2. Anda tidak tahu pasti penyandian arus data saat ini.

Apakah Anda akan mencoba menangani data streaming tanpa mengetahui berapa banyak yang ada terlebih dahulu? Itu ide yang buruk . Anda tidak dapat bergantung secara eksklusif pada Content-Lengthtajuk HTTP untuk panduan tentang ukuran input yang dialirkan karena dapat dipalsukan.

Anda akan membutuhkan:

  1. Algoritma pendeteksian ukuran streaming.
  2. Batas ukuran aliran yang ditentukan aplikasi (Batas Apache / Nginx / PHP mungkin terlalu luas).

Apakah Anda akan mencoba untuk mengkonversi data stream ke UTF-8 tanpa mengetahui pengkodean arus stream? Bagaimana? Filter stream iconv ( contoh filter iconv stream ) tampaknya menginginkan penyandian awal dan akhir, seperti ini.

'convert.iconv.ISO-8859-1/UTF-8'

Jadi, jika Anda teliti, Anda akan membutuhkan:

  1. Algoritma deteksi aliran encoding.
  2. Algoritma definisi filter aliran dinamis / runtime (karena Anda tidak dapat mengetahui mulai penyandian apriori).

( Perbarui :'convert.iconv.UTF-8/UTF-8' akan memaksakan segalanya untuk UTF-8, tetapi Anda masih harus memperhitungkan karakter yang mungkin tidak diketahui oleh pustaka iconv. Dengan kata lain, Anda harus memahami cara menentukan tindakan apa yang harus diambil ketika karakter tidak dapat diterjemahkan. : 1) Masukkan karakter dummy, 2) Gagal / melempar dan pengecualian).

Anda tidak dapat bergantung secara eksklusif pada Content-Encodingtajuk HTTP , karena ini mungkin menunjukkan sesuatu seperti kompresi seperti berikut ini. Ini bukan yang Anda inginkan untuk membuat keputusan sehubungan dengan ikonv.

Content-Encoding: gzip

Oleh karena itu, langkah-langkah umum mungkin ...

Bagian I: Terkait Permintaan HTTP

  1. Tentukan apakah metode HTTP yang benar telah ditunjukkan (DAPATKAN, POST, PUT, PATCH, DELETE, ...)
  2. Menentukan apakah header Jenis Konten HTTP telah dikirimkan.
  3. Tentukan apakah nilai untuk Tipe-Konten adalah tipe media yang diinginkan.

Bagian II: Stream Data Terkait

  1. Tentukan ukuran aliran input (opsional, tetapi disarankan).
  2. Tentukan penyandian aliran input.
  3. Jika perlu, konversi aliran input ke pengkodean karakter yang diinginkan (UTF-8).
  4. Jika perlu, balikkan kompresi level aplikasi atau enkripsi apa pun, dan kemudian ulangi langkah 4, 5, dan 6.

Bagian III: Jenis Data Terkait

  1. Menentukan apakah data yang dikirim berbentuk XML / JSON / YMAL / dll.

(Ingat, data masih bisa berupa string yang disandikan URL yang harus Anda uraikan dan dekode URL).

  1. Jika perlu, konversikan data ke tipe data PHP: array atau objek.

Bagian IV: Nilai Terkait Data

  1. Memfilter data input.

  2. Validasi input data.

Sekarang kamu lihat?

The $_POSTsuperglobal, bersama dengan pengaturan php.ini untuk batas atas masukan, lebih sederhana bagi orang awam. Namun, berurusan dengan pengkodean karakter jauh lebih intuitif dan efisien ketika menggunakan stream karena tidak perlu mengulang melalui superglobals (atau array, umumnya) untuk memeriksa nilai input untuk pengkodean yang tepat.

Anthony Rutledge
sumber
1
Oh wow! Jawaban ini seharusnya memiliki peringkat yang jauh lebih tinggi. Terima kasih banyak telah membawa cahaya banjir ke kegelapan.
Lox
Dalam analisis akhir, PHP sebaiknya memperbarui standar dasar. Namun, itu adalah kesalahan logis untuk memasangkan metode permintaan HTTP dengan struktur data dengan nama yang sama ($ _GET, $ _POST). Yang penting adalah (1) metode permintaan HTTP yang diinginkan, dan (2) apakah ada data permintaan dengan permintaan itu (Content-Type). Oleh karena itu, seperti halnya dengan Perl, Anda harus melihat bahwa Anda bisa menjadi korban dari pendapat pencipta / pengelola bahasa.
Anthony Rutledge
0

Jadi saya menulis fungsi yang akan mendapatkan data POST dari php: // input stream .

Jadi tantangan di sini adalah beralih ke metode permintaan PUT, DELETE ATAU PATCH, dan masih mendapatkan data pos yang dikirim bersama permintaan itu.

Saya membagikan ini mungkin untuk seseorang dengan tantangan serupa. Fungsi di bawah ini adalah apa yang saya temukan dan berfungsi. Saya harap ini membantu!

    /**
     * @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;
    }
Ifeanyi Amadi
sumber
-5

Contoh sederhana cara menggunakannya

 <?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;  }  
   ?>
Dostonbek Oripjonov
sumber