Bagaimana cara mengirim permintaan POST dengan PHP?


655

Sebenarnya saya ingin membaca konten yang muncul setelah permintaan pencarian, ketika selesai. Masalahnya adalah bahwa URL hanya menerima POSTmetode, dan tidak mengambil tindakan apa pun dengan GETmetode ...

Saya harus membaca semua konten dengan bantuan domdocumentatau file_get_contents(). Apakah ada metode yang akan membiarkan saya mengirim parameter dengan POSTmetode dan kemudian membaca isinya PHP?

Jawaban:


1259

Metode CURL-less dengan PHP5:

$url = 'http://server.com/path';
$data = array('key1' => 'value1', 'key2' => 'value2');

// use key 'http' even if you send the request to https://...
$options = array(
    'http' => array(
        'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        'method'  => 'POST',
        'content' => http_build_query($data)
    )
);
$context  = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }

var_dump($result);

Lihat manual PHP untuk informasi lebih lanjut tentang metode dan cara menambahkan header, misalnya:


64
Perlu dicatat bahwa jika Anda memutuskan untuk menggunakan array untuk header, JANGAN akhiri kunci atau nilai dengan '\ r \ n'. stream_context_create () hanya akan membawa teks ke yang pertama '\ r \ n'
raptor

11
URL dapat digunakan sebagai nama file file_get_contents()hanya jika pembungkus fopen telah diaktifkan. Lihat php.net/manual/en/…
Pino

3
@I lovefile_get_contents()
deadlock

14
Apakah ada alasan khusus untuk tidak menggunakan CURL?
jvannistelrooy

37
@jvannistelrooy CURL untuk PHP adalah ekstensi yang mungkin tidak ada di semua lingkungan sedangkan file_get_contents()merupakan bagian dari inti PHP. Selain itu, menggunakan ekstensi yang tidak perlu dapat memperluas permukaan serangan aplikasi Anda. Misalnya Google php curl cve
Pocketsand

139

Anda bisa menggunakan CURL :

<?php
//The url you wish to send the POST request to
$url = $file_name;

//The data you want to send via POST
$fields = [
    '__VIEWSTATE '      => $state,
    '__EVENTVALIDATION' => $valid,
    'btnSubmit'         => 'Submit'
];

//url-ify the data for the POST
$fields_string = http_build_query($fields);

//open connection
$ch = curl_init();

//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);

//So that curl_exec returns the contents of the cURL; rather than echoing it
curl_setopt($ch,CURLOPT_RETURNTRANSFER, true); 

//execute post
$result = curl_exec($ch);
echo $result;
?>

3
ini berfungsi untuk saya karena halaman yang saya kirim ke halaman tidak memiliki konten sehingga versi file_get_contents tidak berfungsi.
CommentLuv

9
solusi file_get_contents tidak berfungsi pada konfigurasi PHP dengan allow_url_fopen Off (seperti pada shared hosting). Versi ini menggunakan pustaka ikal dan menurut saya paling "universal", jadi saya berikan suara Anda
Dayron Gallardo

81
Anda tidak menemukan situs tempat Anda menyalin contoh kode ini dari: davidwalsh.name/curl-post
efreed

4
Meskipun tidak terlalu penting, data parameter CURLOPT_POSTFIELDS sebenarnya tidak perlu dikonversi ke string ("urlified"). Kutipan: "Parameter ini dapat dilewatkan sebagai string urlencoded seperti 'para1 = val1 & para2 = val2 & ...' atau sebagai array dengan nama bidang sebagai kunci dan data bidang sebagai nilai. Jika nilainya array, Tipe-Konten header akan diatur ke multipart / form-data. " Tautan: php.net/manual/en/function.curl-setopt.php .
Edward

2
Juga, tidak ada pelanggaran untuk menulisnya secara berbeda, tetapi saya tidak tahu mengapa parameter CURLOPT_POST ditentukan sebagai angka di sini seperti yang dikatakan untuk mengaturnya menjadi boolean pada halaman manual. Kutipan: "CURLOPT_POST: BENAR untuk melakukan POST HTTP biasa." Tautan: php.net/manual/en/function.curl-setopt.php .
Edward

68

Saya menggunakan fungsi berikut untuk mengirim data menggunakan curl. $ data adalah array bidang untuk dikirim (akan dikodekan dengan benar menggunakan http_build_query). Data dikodekan menggunakan aplikasi / x-www-form-urlencoded.

function httpPost($url, $data)
{
    $curl = curl_init($url);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($curl);
    curl_close($curl);
    return $response;
}

@Edward menyebutkan bahwa http_build_query dapat dihilangkan karena curl akan mengkodekan array yang diteruskan dengan benar ke parameter CURLOPT_POSTFIELDS, tetapi disarankan bahwa dalam kasus ini data akan dikodekan menggunakan data multi-formulir / data.

Saya menggunakan fungsi ini dengan API yang mengharapkan data dikodekan menggunakan aplikasi / x-www-form-urlencoded. Itu sebabnya saya menggunakan http_build_query ().


Melewati array ke CURLOPT_POSTFIELDS menyebabkan data dikodekan menggunakan multipart / formulir-data yang mungkin tidak diinginkan.
Dima L.

Pengguna memang meminta file_get_contents, sehingga ia membutuhkan solusi untuk mengubah default_stream_context
Radon8472

Untuk memperjelas: Saya pikir @DimaL. menanggapi komentar yang telah dihapus; http_build_querymengubah $dataarray menjadi string, menghindari output sebagai multipart / form-data.
ToolmakerSteve

@ Radon8472 - ... CURLOPT_RETURNTRANSFER, truemenghasilkan konten yang $responsemengandung
ToolmakerSteve

@ToolmakerSteve seperti yang saya katakan, pertanyaannya adalah file_get_contentsdan solusi Anda membutuhkan CURL yang tidak dimiliki banyak orang. jadi solusi Anda mungkin bekerja, tetapi tidak menjawab pertanyaan bagaimana melakukan ini dengan fungsi file bawaan / stream bawaan.
Radon8472

42

Saya sarankan Anda untuk menggunakan guzzle paket open-source yang sepenuhnya unit diuji dan menggunakan praktik coding terbaru.

Menginstal Guzzle

Pergi ke baris perintah di folder proyek Anda dan ketik perintah berikut (dengan asumsi Anda sudah menginstal komposer manajer paket ). Jika Anda memerlukan bantuan cara menginstal Komposer, Anda harus melihatnya di sini .

php composer.phar require guzzlehttp/guzzle

Menggunakan Guzzle untuk mengirim permintaan POST

Penggunaan Guzzle sangat mudah karena menggunakan API berorientasi objek ringan:

// Initialize Guzzle client
$client = new GuzzleHttp\Client();

// Create a POST request
$response = $client->request(
    'POST',
    'http://example.org/',
    [
        'form_params' => [
            'key1' => 'value1',
            'key2' => 'value2'
        ]
    ]
);

// Parse the response object, e.g. read the headers, body, etc.
$headers = $response->getHeaders();
$body = $response->getBody();

// Output headers and body for debugging purposes
var_dump($headers, $body);

7
Akan bermanfaat untuk mengetahui keuntungan apa yang dimilikinya dari solusi PHP asli yang sudah diposting, dan juga cURL.
artfulrobot

9
@artfulrobot: Solusi PHP asli memiliki banyak masalah (mis. menghubungkan dengan https, verifikasi sertifikat, dll. pp), itulah sebabnya hampir setiap pengembang PHP menggunakan cURL. Dan mengapa tidak menggunakan CURL dalam hal ini? Sederhana: Guzzle memiliki antarmuka yang lurus ke depan, mudah, ringan yang memisahkan semua "masalah penanganan CURL tingkat rendah". Hampir semua orang yang mengembangkan PHP modern menggunakan Komposer, jadi menggunakan Guzzle sangat sederhana.
Andreas

2
Terima kasih, saya tahu guzzle populer, namun ada kasus penggunaan ketika komposer menyebabkan kesedihan (misalnya mengembangkan plugin untuk proyek perangkat lunak yang lebih besar yang mungkin sudah menggunakan (versi berbeda) dari guzzle atau dependensi lainnya), jadi ada baiknya mengetahui info ini untuk membuat keputusan tentang solusi mana yang paling kuat
artfulrobot

26

Ada metode CURL lain jika Anda menuju ke sana.

Ini sangat mudah setelah Anda mengetahui bagaimana ekstensi PHP curl bekerja, menggabungkan berbagai flag dengan panggilan setopt (). Dalam contoh ini saya punya variabel $ xml yang berisi XML yang telah saya siapkan untuk kirim - saya akan memposting konten itu ke metode pengujian contoh.

$url = 'http://api.example.com/services/xmlrpc/';
$ch = curl_init($url);

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);
//process $response

Pertama kita menginisialisasi koneksi, lalu kita mengatur beberapa opsi menggunakan setopt (). Ini memberi tahu PHP bahwa kami sedang membuat permintaan posting, dan bahwa kami mengirim beberapa data dengannya, memasok data. Bendera CURLOPT_RETURNTRANSFER memberi tahu curl untuk memberi kami output sebagai nilai balik dari curl_exec daripada mengeluarkannya. Lalu kami melakukan panggilan dan menutup koneksi - hasilnya dalam $ response.


1
dalam panggilan curl_setopt () ke-3, arg pertama $chtidak boleh $curl, benar?
jcomeau_ictx

Bisakah Anda menggunakan kode yang sama ini untuk data POST JSON? Tetapi ganti $ xml dengan say $ json (di mana $ json mungkin adalah string JSON?)
Neal Davis

24

Jika Anda kebetulan menggunakan Wordpress untuk mengembangkan aplikasi Anda (itu sebenarnya cara yang mudah untuk mendapatkan otorisasi, halaman info dll bahkan untuk hal-hal yang sangat sederhana), Anda dapat menggunakan cuplikan berikut:

$response = wp_remote_post( $url, array('body' => $parameters));

if ( is_wp_error( $response ) ) {
    // $response->get_error_message()
} else {
    // $response['body']
}

Ini menggunakan berbagai cara membuat permintaan HTTP yang sebenarnya, tergantung pada apa yang tersedia di server web. Untuk detail lebih lanjut, lihat dokumentasi API HTTP .

Jika Anda tidak ingin mengembangkan tema atau plugin khusus untuk memulai mesin Wordpress, Anda bisa melakukan hal berikut dalam file PHP yang terisolasi di root wordpress:

require_once( dirname(__FILE__) . '/wp-load.php' );

// ... your code

Itu tidak akan menampilkan tema atau menghasilkan HTML apa pun, cukup hapus dengan API Wordpress!


22

Saya ingin menambahkan beberapa pemikiran tentang jawaban berbasis ikal dari Fred Tanrikut. Saya tahu sebagian besar dari mereka sudah ditulis dalam jawaban di atas, tetapi saya pikir itu ide yang baik untuk menunjukkan jawaban yang mencakup semuanya.

Berikut ini adalah kelas yang saya tulis untuk membuat permintaan HTTP-GET / POST / PUT / DELETE berdasarkan curl, mengenai hampir semua tubuh respons:

class HTTPRequester {
    /**
     * @description Make HTTP-GET call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPGet($url, array $params) {
        $query = http_build_query($params); 
        $ch    = curl_init($url.'?'.$query);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-POST call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPost($url, array $params) {
        $query = http_build_query($params);
        $ch    = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, false);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
    /**
     * @description Make HTTP-PUT call
     * @param       $url
     * @param       array $params
     * @return      HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPPut($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
    /**
     * @category Make HTTP-DELETE call
     * @param    $url
     * @param    array $params
     * @return   HTTP-Response body or an empty string if the request fails or is empty
     */
    public static function HTTPDelete($url, array $params) {
        $query = \http_build_query($params);
        $ch    = \curl_init();
        \curl_setopt($ch, \CURLOPT_RETURNTRANSFER, true);
        \curl_setopt($ch, \CURLOPT_HEADER, false);
        \curl_setopt($ch, \CURLOPT_URL, $url);
        \curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
        \curl_setopt($ch, \CURLOPT_POSTFIELDS, $query);
        $response = \curl_exec($ch);
        \curl_close($ch);
        return $response;
    }
}

Perbaikan

  • Menggunakan http_build_query untuk mengeluarkan kueri-string dari array-permintaan. (Anda juga bisa menggunakan array itu sendiri, oleh karena itu lihat: http://php.net/manual/en/function.curl-setopt.php )
  • Mengembalikan respons alih-alih menggemakannya. Btw Anda bisa menghindari pengembalian dengan menghapus baris curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true);. Setelah itu, nilai baliknya adalah boolean (true = permintaan berhasil jika tidak terjadi kesalahan) dan respons diulang. Lihat: http://php.net/en/manual/function.curl-exec.php
  • Bersihkan penutupan sesi dan penghapusan curl-handler dengan menggunakan curl_close . Lihat: http://php.net/manual/en/function.curl-close.php
  • Menggunakan nilai boolean untuk curl_setopt fungsi daripada menggunakan angka apa pun. (Saya tahu bahwa angka apa pun yang tidak sama dengan nol juga dianggap benar, tetapi penggunaan true menghasilkan kode yang lebih mudah dibaca, tapi itu hanya pendapat saya)
  • Kemampuan untuk melakukan panggilan HTTP-PUT / DELETE (berguna untuk pengujian layanan RESTful)

Contoh penggunaan

DAPATKAN

$response = HTTPRequester::HTTPGet("http://localhost/service/foobar.php", array("getParam" => "foobar"));

POS

$response = HTTPRequester::HTTPPost("http://localhost/service/foobar.php", array("postParam" => "foobar"));

TARUH

$response = HTTPRequester::HTTPPut("http://localhost/service/foobar.php", array("putParam" => "foobar"));

MENGHAPUS

$response = HTTPRequester::HTTPDelete("http://localhost/service/foobar.php", array("deleteParam" => "foobar"));

Pengujian

Anda juga dapat membuat beberapa tes layanan keren dengan menggunakan kelas sederhana ini.

class HTTPRequesterCase extends TestCase {
    /**
     * @description test static method HTTPGet
     */
    public function testHTTPGet() {
        $requestArr = array("getLicenses" => 1);
        $url        = "http://localhost/project/req/licenseService.php";
        $this->assertEquals(HTTPRequester::HTTPGet($url, $requestArr), '[{"error":false,"val":["NONE","AGPL","GPLv3"]}]');
    }
    /**
     * @description test static method HTTPPost
     */
    public function testHTTPPost() {
        $requestArr = array("addPerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPost($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPPut
     */
    public function testHTTPPut() {
        $requestArr = array("updatePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPPut($url, $requestArr), '[{"error":false}]');
    }
    /**
     * @description test static method HTTPDelete
     */
    public function testHTTPDelete() {
        $requestArr = array("deletePerson" => array("foo", "bar"));
        $url        = "http://localhost/project/req/personService.php";
        $this->assertEquals(HTTPRequester::HTTPDelete($url, $requestArr), '[{"error":false}]');
    }
}

Bagi saya, ia mengatakan "Uncaught Error: Panggil ke metode tak terdefinisi HTTPRequester :: HTTPost ()" . Saya hanya menyisipkan kelas Anda ke file .php saya. Ada lagi yang harus saya lakukan?
LinusGeffarth

1
Bisakah Anda memposting kode Anda? Cukup sulit untuk menebak apa yang salah tanpa cuplikan kode.
mwatzer

Seperti yang saya katakan, saya benar-benar menyalin Anda ke file php polos saya dan itu memberi saya kesalahan ini.
LinusGeffarth

1
Ok sekarang saya melihat masalah, .. itu salah dalam contoh! Anda harus memanggil HTTPRequester :: HTTPPost () alih-alih HTTPRequester :: HTTPost ()
mwatzer

1
Ah. Yang itu mudah dilewatkan. Saya harus membaca komentar Anda seperti 5x sebelum saya melihat P ekstra . Terima kasih!
LinusGeffarth

19

Alternatif lain dari metode curl-less di atas adalah menggunakan fungsi stream asli :

  • stream_context_create():

    Membuat dan mengembalikan konteks aliran dengan opsi apa pun yang disediakan dalam opsi yang telah ditetapkan.

  • stream_get_contents():

    Identik dengan file_get_contents(), kecuali yang stream_get_contents() beroperasi pada sumber daya aliran yang sudah terbuka dan mengembalikan konten yang tersisa dalam string, hingga maxlength byte dan mulai dari offset yang ditentukan .

Fungsi POST dengan ini bisa seperti ini:

<?php

function post_request($url, array $params) {
  $query_content = http_build_query($params);
  $fp = fopen($url, 'r', FALSE, // do not use_include_path
    stream_context_create([
    'http' => [
      'header'  => [ // header array does not need '\r\n'
        'Content-type: application/x-www-form-urlencoded',
        'Content-Length: ' . strlen($query_content)
      ],
      'method'  => 'POST',
      'content' => $query_content
    ]
  ]));
  if ($fp === FALSE) {
    return json_encode(['error' => 'Failed to get contents...']);
  }
  $result = stream_get_contents($fp); // no maxlength/offset
  fclose($fp);
  return $result;
}

1
Metode CURL-less ini berfungsi dengan baik bagi saya untuk memvalidasi reCAPTCHA dari google. Jawaban ini menyatu dengan kode google ini: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero

1
Anda tidak harus menggunakan fclose()jika $fpada false. Karena fclose()mengharapkan sumber daya adalah parameter.
Floris

1
@ Floris Diedit hanya sekarang dan memang dokumen fclose menyebutkan "File pointer harus valid". Terima kasih telah memperhatikan itu!
CPHPython

8

Cara pengiriman GETatau POSTpermintaan yang lebih baik PHPadalah sebagai berikut:

<?php
    $r = new HttpRequest('http://example.com/form.php', HttpRequest::METH_POST);
    $r->setOptions(array('cookies' => array('lang' => 'de')));
    $r->addPostFields(array('user' => 'mike', 'pass' => 's3c|r3t'));

    try {
        echo $r->send()->getBody();
    } catch (HttpException $ex) {
        echo $ex;
    }
?>

Kode diambil dari dokumentasi resmi di sini http://docs.php.net/manual/da/httprequest.send.php


1
@akinuri terima kasih karena telah menyoroti, saya akan membagikan yang baru.
Imran Zahoor

bagaimana melakukannya di PHP 5x?

@YumYumYum silakan checkout jawaban dbau di atas untuk 5x yang menggunakan teknik ini php.net/manual/en/function.stream-context-create.php Atau Anda selalu dapat kembali ke solusi curl standar.
Imran Zahoor

5

Ada satu lagi yang bisa Anda gunakan

<?php
$fields = array(
    'name' => 'mike',
    'pass' => 'se_ret'
);
$files = array(
    array(
        'name' => 'uimg',
        'type' => 'image/jpeg',
        'file' => './profile.jpg',
    )
);

$response = http_post_fields("http://www.example.com/", $fields, $files);
?>

Klik disini untuk detail


2
Ini bergantung pada ekstensi PECL yang sebagian besar tidak akan diinstal. Bahkan tidak yakin itu masih tersedia, karena halaman manual telah dihapus.
miken32

5

Saya mencari masalah yang sama dan menemukan pendekatan yang lebih baik dalam melakukan ini. Jadi begini.

Anda cukup meletakkan baris berikut di halaman redirection (misalkan page1.php).

header("Location: URL", TRUE, 307); // Replace URL with to be redirected URL, e.g. final.php

Saya membutuhkan ini untuk mengarahkan permintaan POST untuk panggilan API REST . Solusi ini dapat mengarahkan ulang dengan memposting data serta nilai header khusus.

Inilah tautan referensi .


1
Ini menjawab bagaimana mengarahkan permintaan halaman bukan Bagaimana cara mengirim permintaan POST dengan PHP? Tentu ini akan meneruskan parameter POST tapi itu sama sekali tidak sama
Wesley Smith

@ DelightedD0D, Maaf saya tidak mendapatkan perbedaan antara redirect a page request with POST paramvs send POST request. Bagi saya tujuan keduanya sama, koreksi saya jika saya salah.
Arindam Nayak

1
Apakah ada metode yang akan membiarkan saya mengirim parameter dengan metode POST dan kemudian membaca isinya melalui PHP? OP ingin skrip php mereka untuk membangun satu set parameter POST dan mengirimkannya ke halaman php lain dan agar skrip mereka menerima output dari halaman tersebut. Solusi ini hanya akan menerima set nilai yang sudah POSTed dan meneruskannya ke halaman lain. Mereka sangat berbeda.
Wesley Smith

5

Di sini hanya menggunakan satu perintah tanpa CURL. Sangat sederhana.

echo file_get_contents('https://www.server.com', false, stream_context_create([
    'http' => [
        'method' => 'POST',
        'header'  => "Content-type: application/x-www-form-urlencoded",
        'content' => http_build_query([
            'key1' => 'Hello world!', 'key2' => 'second value'
        ])
    ]
]));

Bagaimana cara kerja Key2? apa pemisah di antara mereka?
Sayed Muhammad Idrees

@Sayedidrees untuk menambahkan key2 Anda dapat memasukkannya sebagai item array kedua. 'key1' => 'Halo dunia!', 'key2' => 'nilai kedua'
Liga

Ini bekerja sangat baik saat digunakan dengan zapier.
Moxet

3

Coba paket HTTP_Request2 PEAR untuk mengirim permintaan POST dengan mudah. Atau, Anda dapat menggunakan fungsi keriting PHP atau menggunakan konteks aliran PHP .

HTTP_Request2 juga memungkinkan mengejek server , sehingga Anda dapat menguji kode Anda dengan mudah


7
Saya ingin melihat Anda untuk menjelaskannya, jika memungkinkan.
Gui Imamura
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.