PHP ile nasıl POST isteği gönderebilirim?


656

Aslında bittiğinde, arama sorgusu sonra gelen içeriği okumak istiyorum. Sorun, URL'nin yalnızca POSTyöntemleri kabul etmesi ve yöntemle herhangi bir işlem yapmamasıdır GET...

domdocumentVeya ile tüm içeriği okumalıyım file_get_contents(). Metod ile parametre göndermeme POSTve ardından içeriği okumaya izin verecek herhangi bir yöntem var mı PHP?

Yanıtlar:


1260

PHP5 ile CURL'siz yöntem:

$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);

Yöntem ve başlıkların nasıl ekleneceği hakkında daha fazla bilgi için PHP kılavuzuna bakın, örneğin:


64
Başlıklar için bir dizi kullanmaya karar verirseniz, anahtarları veya değerleri '\ r \ n' ile bitirmemeye dikkat edin. stream_context_create () yalnızca ilk '\ r \ n' metnini alır
raptor

11
URL, file_get_contents()yalnızca fopen sarmalayıcıları etkinleştirildiyse dosya adı olarak kullanılabilir . Bkz. Php.net/manual/tr/…
Pino

3
@I lovefile_get_contents()
deadlock

14
CURL kullanmamanın özel bir nedeni var mı?
jvannistelrooy

37
@jvannistelrooy PHP için CURL, PHP'nin file_get_contents()çekirdeğinin bir parçası iken , tüm ortamlarda bulunmayan bir uzantıdır . Ayrıca, gereksiz bir uzantı kullanmak uygulamanızın saldırı yüzeyini genişletebilir. Örneğin, Google php kıvırmak cve
Pocketsand

139

CURL kullanabilirsiniz :

<?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
Bu benim için çalıştı çünkü hiçbir içeriği olmayan bir sayfaya gönderdiğim sayfa file_get_contents sürümü işe yaramadı.
CommentLuv

9
file_get_contents çözümü allow_url_fopen Off (paylaşılan barındırmada olduğu gibi) ile PHP yapılandırmalarında çalışmaz. Bu sürüm kıvırmak kütüphane kullanır ve ben en "evrensel" olduğunu düşünüyorum bu yüzden size oyumu vermek
Dayron Gallardo

81
Bu kod örneğini kopyaladığınız siteyi yapmadınız: davidwalsh.name/curl-post
efreed

4
Çok önemli olmasa da, CURLOPT_POSTFIELDS parametre verilerinin aslında bir dizeye ("urlified") dönüştürülmesi gerekmez. Quote: "Bu parametre ya 'para1 = val1 & para2 = val2 & ...' gibi urlen kodlu bir dize olarak ya da alan adı anahtar ve alan verisi olarak bir dizi olarak verilebilir. Değer bir dizi ise, Content-Type üstbilgi çok parçalı / form-verisine ayarlanır. " Bağlantı: php.net/manual/en/function.curl-setopt.php .
Edward

2
Ayrıca, farklı yazmak için hiçbir suç, ama neden manuel sayfada bir boole ayarlamak için söylediği gibi CURLOPT_POST parametresi burada bir sayı olarak belirtilmiş bilmiyorum. Alıntı: "CURLOPT_POST: Normal bir HTTP POST yapmak için TRUE." Bağlantı: php.net/manual/en/function.curl-setopt.php .
Edward

68

Curl kullanarak veri göndermek için aşağıdaki işlevi kullanıyorum. $ data gönderilecek alanlardan oluşan bir dizidir (http_build_query kullanılarak doğru şekilde kodlanır). Veriler application / x-www-form-urlencoded kullanılarak kodlanır.

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, curl, CURLOPT_POSTFIELDS parametresine iletilen diziyi doğru bir şekilde kodlayacağından http_build_query'nin atlanabileceğinden bahseder, ancak bu durumda verilerin çok bölümlü / form verileri kullanılarak kodlanacağı önerilir.

Bu işlevi, verinin application / x-www-form-urlencoded kullanılarak kodlanmasını bekleyen API'lerle kullanırım. Bu yüzden http_build_query () kullanıyorum.


Dizinin CURLOPT_POSTFIELDS öğesine iletilmesi, verilerin istenilemeyen çok parçalı / form verileri kullanılarak kodlanmasına neden olur.
Dima L.

Kullanıcı file_get_contents istedi, bu yüzden default_stream_context değiştirmek için bir çözüme ihtiyacı var
Radon8472

Açıklığa kavuşturmak için: Sanırım @DimaL. silinmiş bir yoruma yanıt veriyor; diziyi bir dizeye http_build_querydönüştürerek $dataçıktıyı çoklu bölüm / form verileri olarak önler.
ToolmakerSteve

@ Radon8472 - içindekilerle ... CURLOPT_RETURNTRANSFER, truesonuçlanır $response.
ToolmakerSteve

Dediğim gibi, soru şuydu file_get_contentsve çözümünüzün birçok insanın sahip olmadığı CURL'a ihtiyacı var. bu nedenle çözümünüz çalışıyor olabilir, ancak bunun yerel yerleşik dosya / akış işlevleriyle nasıl yapılacağı sorusunu yanıtlamıyor.
Radon8472

42

Tamamen birim olarak test edilmiş ve en son kodlama uygulamalarını kullanan açık kaynaklı paket kılavuzunu kullanmanızı öneririm .

Guzzle Kurulumu

Proje klasörünüzdeki komut satırına gidin ve aşağıdaki komutu yazın (paket yöneticisi bestecisinin zaten yüklü olduğu varsayılarak ). Composer'ı nasıl kuracağınız konusunda yardıma ihtiyacınız varsa, buraya bir göz atmalısınız .

php composer.phar require guzzlehttp/guzzle

POST isteği göndermek için Guzzle'ı kullanma

Guzzle kullanımı, hafif bir nesne yönelimli API kullandığından çok basittir:

// 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
Bunun zaten gönderilen yerel PHP çözümü ve cURL çözümüne göre ne gibi avantajları olduğunu bilmek yararlı olacaktır.
artfulrobot

9
@artfulrobot: Yerel PHP çözümünün birçok sorunu vardır (örn. https, sertifika doğrulaması vb. ile bağlantı), bu yüzden hemen hemen her PHP geliştiricisi cURL kullanır. Ve neden bu durumda cURL kullanmıyorsunuz? Çok basit: Guzzle, tüm bu "düşük seviyeli cURL taşıma problemlerini" ortadan kaldıran basit, kolay, hafif bir arayüze sahiptir. Modern PHP geliştiren hemen hemen herkes Composer'ı kullanıyor, bu yüzden Guzzle kullanmak gerçekten çok basit.
Andreas

2
Teşekkürler, guzzle'ın popüler olduğunu biliyorum, ancak bestecinin kedere neden olduğu kullanım durumları vardır (örneğin, zaten guzzle veya diğer bağımlılıkların (farklı bir versiyonunu) kullanabilen daha büyük yazılım projeleri için eklentiler geliştirmek), bu yüzden bu bilgiyi yapmak iyi hangi çözümün en sağlam olacağına karar verme
artfulrobot

26

Bu şekilde gidiyorsanız başka bir CURL yöntemi var.

PHP kıvırmak uzantısının çalışma şeklini setopt () çağrıları ile birleştirerek başınızı döndürdüğünüzde bu oldukça basittir. Bu örnekte, göndermeye hazırlandığım XML'yi içeren bir değişken $ xml var - bunun içeriğini örneğin test yöntemine göndereceğim.

$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

Önce bağlantıyı başlattık, sonra setopt () kullanarak bazı seçenekler ayarladık. Bunlar PHP'ye bir gönderi isteği yaptığımızı ve verilerle birlikte bazı veriler gönderdiğimizi söyler. CURLOPT_RETURNTRANSFER bayrağı curl'e çıktıyı çıktısını almak yerine curl_exec'in dönüş değeri olarak vermesini söyler. Sonra aramayı yaparız ve bağlantıyı kapatırız - sonuç $ yanıtındadır.


1
3 curl_setopt () çağrısında, ilk arg olmalıdır $chdeğil $curl, doğru mu?
jcomeau_ictx

JSON verilerini POST yapmak için aynı kodu kullanabilir misiniz? Ancak $ xml yerine $ json deyin ($ json muhtemelen bir JSON dizesidir?)
Neal Davis

24

Herhangi bir şansla uygulamanızı geliştirmek için Wordpress kullanıyorsanız (aslında çok basit şeyler için yetkilendirme, bilgi sayfaları vb. Almak için uygun bir yoldur), aşağıdaki snippet'i kullanabilirsiniz:

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

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

Web sunucusunda neler bulunduğuna bağlı olarak gerçek HTTP isteğinde bulunmanın farklı yollarını kullanır. Daha fazla ayrıntı için HTTP API belgelerine bakın .

Wordpress motorunu başlatmak için özel bir tema veya eklenti geliştirmek istemiyorsanız, wordpress kökündeki yalıtılmış bir PHP dosyasında aşağıdakileri yapabilirsiniz:

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

// ... your code

Herhangi bir temayı göstermeyecek veya herhangi bir HTML çıktısı vermeyecek, Wordpress API'lerini hackleyeceksiniz!


22

Fred Tanrikut'un kıvrılma temelli cevabı hakkında bazı düşünceler eklemek istiyorum. Birçoğunun yukarıdaki cevaplarda zaten yazıldığını biliyorum, ancak hepsini içeren bir cevap göstermek iyi bir fikir.

İşte yanıt gövdesi hakkında, curl tabanlı HTTP-GET / POST / PUT / DELETE istekleri yapmak için yazdığım sınıf:

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;
    }
}

İyileştirmeler

  • Sorgu dizesini istek dizisinden çıkarmak için http_build_query kullanma. (Dizinin kendisini de kullanabilirsiniz, bu nedenle bkz: http://php.net/manual/en/function.curl-setopt.php )
  • Yankılanmak yerine yanıtı döndürmek. Btw satır kaldırarak dönen önleyebilirsiniz curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); . Bundan sonra dönüş değeri bir boole (true = istek başarılıydı, aksi takdirde bir hata oluştu) ve yanıt yankılanıyor. Görmek: Http://php.net/en/manual/function.curl-exec.php
  • Oturum kapatmayı ve curl_close kullanarak curl- handler'ın silinmesini temizleyin . Görmek: Http://php.net/manual/en/function.curl-close.php
  • Curl_setopt için boole değerlerini kullanmaHerhangi bir sayı kullanmak yerine işlevi kullanmak. (Sıfır değerine eşit olmayan herhangi bir sayının da doğru olarak kabul edildiğini biliyorum, ancak true kullanımı daha okunabilir bir kod oluşturur, ancak bu sadece benim görüşüm)
  • HTTP-PUT / DELETE aramaları yapabilme (RESTful hizmet testi için yararlıdır)

Kullanım örneği

ALMAK

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

İLETİ

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

KOYMAK

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

SİL

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

Test yapmak

Bu basit sınıfı kullanarak bazı harika servis testleri de yapabilirsiniz.

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}]');
    }
}

Benim için "Yakalanmayan Hata: Tanımlanmamış yöntem çağrısı HTTPRequester :: HTTPost ()" yazıyor . Sınıfınızı .php dosyama yapıştırdım. Yapmam gereken başka bir şey var mı?
LinusGeffarth

1
Lütfen kodunuzu gönderebilir misiniz? Kod pasajı olmadan neyin yanlış olduğunu tahmin etmek oldukça zordur.
mwatzer

Söylediğim gibi, seninkini tam benim düz php dosyasına kopyaladım ve bana bu hatayı verdi.
LinusGeffarth

1
Tamam şimdi sorunu görüyorum, .. örnekte yanlıştı! Bunun yerine HTTPRequester :: HTTPost () ait) HTTPRequester :: HttpPost (çağırmak zorunda
mwatzer

1
Ah. Kaçırması kolay. Ben ekstra P tespit önce 5x gibi yorum okumak zorunda kaldı . Teşekkürler!
LinusGeffarth

19

Yukarıdaki kıvrılmasız yöntemin başka bir alternatifi , yerel akış işlevlerini kullanmaktır:

  • stream_context_create():

    Oluşturur ve verilen herhangi bir seçenek olan bir akış içeriği döner amaç önceden.

  • stream_get_contents():

    Bunun file_get_contents()dışında, stream_get_contents() zaten açık olan bir akış kaynağı üzerinde çalışır ve bir dizede kalan içeriği maksimum bayt değerine kadar ve belirtilen ofsetten başlayarak döndürür .

Bunlarla birlikte bir POST işlevi basitçe şöyle olabilir:

<?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
Bu CURL'siz yöntem, reCAPTCHA'yı Google'dan doğrulamak için benim için iyi çalıştı. Bu yanıt şu google kodu ile yakınsar: github.com/google/recaptcha/blob/master/src/ReCaptcha/…
Xavi Montero

1
Sen kullanımı gerekmez fclose()eğer $fpolduğunu false. Çünkü fclose()kaynak bir parametre bekler.
Floris

1
@Floris Hemen şimdi düzenledi ve aslında fclose docs "Dosya tanıtıcısı geçerli olmalı" ifadesinden bahsediyor. Bunu fark ettiğiniz için teşekkürler!
CPHPython

8

İle daha iyi gönderme GETveya POSTistek yolu PHPaşağıdaki gibidir:

<?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;
    }
?>

Kod, buradaki resmi belgelerden alınmıştır http://docs.php.net/manual/da/httprequest.send.php


1
@akinuri vurguladığınız için teşekkürler, yenisini paylaşacağım.
Imran Zahoor

PHP 5x nasıl yapılır?

@YumYumYum phba-tr/manual/tr/function.stream-context-create.php Bu tekniği kullanan dbau'nun 5x cevabını lütfen yukarıda belirtin .
Imran Zahoor

5

Kullanabileceğiniz bir tane daha var

<?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);
?>

Ayrıntılar için tıklayın


2
Bu, çoğu yüklenmeyecek bir PECL uzantısına dayanır. Manuel sayfalar kaldırıldığı için hala kullanılabilir olduğundan bile emin değilim.
miken32

5

Benzer bir sorun arıyordum ve bunu yapmak için daha iyi bir yaklaşım buldum. İşte gidiyor.

Aşağıdaki satırı yeniden yönlendirme sayfasına koyabilirsiniz (örneğin sayfa1.php).

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

REST API çağrıları için POST isteklerini yeniden yönlendirmek için buna ihtiyacım var . Bu çözüm, özel başlık değerlerinin yanı sıra post verileriyle de yönlendirebilir.

İşte referans linki .


1
Bu cevaplar nasıl bir çağrı talebini yönlendirme değil ben PHP ile bir POST isteği göndermek nasıl? Elbette bu herhangi bir POST parametresini iletecektir, ancak bu aynı şey değildir
Wesley Smith

@ DelightedD0D, Üzgünüm redirect a page request with POST paramvs arasındaki farkı alamadım send POST request. Benim için her ikisinin amacı aynı, eğer yanılıyorsam beni düzeltin.
Arindam Nayak

1
POST yöntemiyle parametreleri göndermeme ve ardından PHP ile içeriği okumama izin verecek herhangi bir yöntem var mı? OP kendi php betiğinin bir dizi POST parametresi oluşturmasını ve bunları başka bir php sayfasına göndermesini ve betiğinin çıktıyı bu sayfadan almasını ister. Bu çözüm, zaten POST edilmiş bir değer kümesini kabul eder ve bunları başka bir sayfaya iletir. Çok farklılar.
Wesley Smith

5

Burada cURL'siz tek bir komut kullanılıyor. Çok basit.

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'
        ])
    ]
]));

Key2 nasıl çalışır? aralarındaki ayırıcı nedir?
Sayed Muhammad Idrees

@Sayedidrees key2 eklemek için ikinci bir dizi öğesi olarak girebilirsiniz. 'key1' => 'Merhaba dünya!', 'key2' => 'ikinci değer'
Liga

Zapier ile kullanırken bu çok iyi çalışıyor.
Moxet

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.