PHPでPOSTリクエストを送信するにはどうすればよいですか?


655

実際、検索クエリの後にあるコンテンツを読み終わったら読みたいと思います。問題は、URLがPOSTメソッドしか受け入れず、GETメソッドでアクションを実行しないことです...

domdocumentまたはの助けを借りて、すべての内容を読む必要がありfile_get_contents()ます。メソッドでパラメーターを送信しPOSTてからコンテンツを読み取ることができるメソッドはありますPHPか?

回答:


1259

PHP5でのCURLを使用しない方法:

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

メソッドの詳細とヘッダーの追加方法については、PHPマニュアルを参照してください。次に例を示します。

  • stream_context_createhttp : //php.net/manual/en/function.stream-context-create.php

64
ヘッダーに配列を使用する場合は、キーまたは値を「\ r \ n」で終了しないでください。stream_context_create()は、最初の「\ r \ n」までのテキストのみを取得します
ラプター

11
URLはfile_get_contents()、fopenラッパーが有効になっている場合にのみ、ファイル名として使用できます。php.net/manual/en/…を
ピノ

3
@I愛file_get_contents()
デッドロック

14
CURLを使用しない特別な理由はありますか?
jvannistelrooy 2015

37
PHPの@jvannistelrooy CURLは、file_get_contents()PHPのコアの一部である拡張機能ですが、すべての環境に存在するわけではありません。また、拡張機能を不必要に使用すると、アプリの攻撃面が広がる可能性があります。たとえば、Google php curl cve
Pocketsand

139

あなたは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
これは私にとってはうまくいきました。コンテンツを含まないページに送信しようとしているため、file_get_contentsバージョンは機能しませんでした。
CommentLuv

9
file_get_contentsソリューションは、(共有ホスティングの場合のように)allow_url_fopenがオフのPHP構成では機能しません。このバージョンはカールライブラリを使用しており、私は最も「普遍的」だと思うので、投票します
Dayron Gallardo 2014

81
このコードサンプルのコピー元のサイトはありませんでした: davidwalsh.name/curl-post
efreed

4
それほど重要ではありませんが、CURLOPT_POSTFIELDSパラメータデータは実際には文字列に変換する必要はありません( "urlified")。引用:「このパラメーターは、 'para1 = val1&para2 = val2&...'のようなurlencoded文字列として、またはキーとしてフィールド名、値としてフィールドデータを含む配列として渡すことができます。値が配列の場合、Content-Typeヘッダーはmultipart / form-dataに設定されます。」リンク:php.net/manual/en/function.curl-setopt.php
エドワード

2
また、別の方法で書いても問題ありませんが、CURLOPT_POSTパラメータがマニュアルページでブール値に設定するように指示されているため、ここで数値として指定されている理由がわかりません。引用:「CURLOPT_POST:通常のHTTP POSTを実行するにはTRUE」リンク:php.net/manual/en/function.curl-setopt.php
エドワード

68

curlを使用してデータを投稿するには、次の関数を使用します。$ dataは投稿するフィールドの配列です(http_build_queryを使用して正しくエンコードされます)。データはapplication / 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は、curlがCURLOPT_POSTFIELDSパラメーターに渡された配列を正しくエンコードするため、http_build_queryが省略される可能性があると述べていますが、この場合、データはmultipart / form-dataを使用してエンコードされることに注意してください。

この関数は、application / x-www-form-urlencodedを使用してデータがエンコードされることを期待するAPIで使用します。そのため、http_build_query()を使用します。


配列をCUR​​LOPT_POSTFIELDSに渡すと、データがmultipart / form-dataを使用してエンコードされるため、望ましくない場合があります。
Dima L.

ユーザーは
file_get_contents

明確にするために、@ DimaLだと思います。削除されたコメントに応答しています。配列を文字列にhttp_build_query変換$dataし、multipart / form-dataとしての出力を回避します。
ToolmakerSteve

@ Radon8472- コンテンツを含む... CURLOPT_RETURNTRANSFER, true結果に$responseなります。
ToolmakerSteve

@ToolmakerSteveが言ったように、問題はでfile_get_contentsあり、あなたのソリューションは多くの人が持っていないものをCURLが必要です。あなたのソリューションはおそらく機能していますが、ネイティブの組み込みファイル/ストリーム関数でこれを行う方法の質問には答えていません。
Radon8472

42

完全にユニットテストされ、最新のコーディングプラクティスを使用しているオープンソースパッケージのガズルを使用することをお勧めします。

Guzzleのインストール

プロジェクトフォルダーのコマンドラインに移動し、次のコマンドを入力します(既にパッケージマネージャーコンポーザーがインストールされていると想定しています)。Composerのインストール方法についてヘルプが必要な場合は、こちらをご覧ください

php composer.phar require guzzlehttp/guzzle

Guzzleを使用してPOSTリクエストを送信する

Guzzleは軽量のオブジェクト指向APIを使用しているため、使い方は非常に簡単です。

// 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
これがすでに投稿されているネイティブのPHPソリューションよりも優れている点と、cURLのメリットについて知っておくと便利です。
artfulrobot 16

9
@artfulrobot:ネイティブのPHPソリューションには多くの問題(httpsへの接続、証明書の検証など)があるため、ほとんどすべてのPHP開発者がcURLを使用しています。そして、なぜこの場合にcURLを使用しないのですか?それは簡単です。Guzzleには、「低レベルのcURL処理の問題」をすべて取り除く抽象化された簡単で軽量なインターフェースがあります。とにかく最新のPHPを開発しているほとんどすべての人がComposerを使用しているため、Guzzleの使用は非常に簡単です。
Andreas

2
おかげで、私はguzzleが人気があることを知っていますが、composerが悲しみを引き起こすユースケースがあります(たとえば、guzzleまたは他の依存関係の(異なるバージョン)をすでに使用している可能性のある大きなソフトウェアプロジェクト用のプラグインを開発している)ので、この情報を知っておくとよいでしょうどのソリューションが最も堅牢になるかについての決定
artfulrobot

26

あなたがそうしているなら、別のCURLメソッドがあります。

さまざまなフラグとsetopt()呼び出しを組み合わせて、PHPのカール拡張機能の動作を理解すれば、これは非常に簡単です。この例では、送信する準備ができたXMLを保持する変数$ xmlを取得しています。その内容を例のテストメソッドに投稿します。

$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

最初に接続を初期化し、次にsetopt()を使用していくつかのオプションを設定しました。これらは、PHPにpostリクエストを作成していることと、データを提供してそれと一緒にデータを送信していることをPHPに伝えます。CURLOPT_RETURNTRANSFERフラグは、curlに、出力ではなく、curl_execの戻り値として出力を提供するように指示します。次に、呼び出しを行って接続を閉じます-結果は$ responseにあります。


1
3番目のcurl_setopt()呼び出しでは、最初の引数はで$chないはず$curlです、正しいですか?
jcomeau_ictx

これと同じコードを使用してJSONデータをPOSTできますか?しかし、$ xmlをsay $ jsonに置き換えます($ jsonはおそらくJSON文字列ですか?)
Neal Davis

24

万が一Wordpressを使用してアプリを開発している場合(実際には、非常に単純なものでも認証、情報ページなどを取得するのに便利な方法です)、次のスニペットを使用できます。

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

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

Webサーバーで利用可能なものに応じて、実際のHTTPリクエストを作成するさまざまな方法を使用します。詳細については、HTTP APIのドキュメントをご覧ください。

WordPressエンジンを起動するためのカスタムテーマまたはプラグインを開発したくない場合は、WordPressルートの隔離されたPHPファイルで次のように実行できます。

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

// ... your code

テーマを表示したり、HTMLを出力したりすることはありません。WordpressAPIでハックしてください!


22

フレッド・タンリクートのカールベースの答えについて考えてみます。それらのほとんどはすでに上記の回答に記載されていますが、すべてをまとめて回答を表示することをお勧めします。

以下は、curlに基づいてHTTP-GET / POST / PUT / DELETEリクエストを作成するために記述したクラスです。

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

改善点

  • http_build_queryを使用してrequest-arrayからクエリ文字列を取得します(配列自体も使用できるため、http//php.net/manual/en/function.curl-setopt.phpを参照してください)。
  • エコーする代わりに応答を返します。ところで、curl_setopt($ ch、CURLOPT_RETURNTRANSFER、true);という行を削除することで、戻りを回避できます。。その後、戻り値はブール値(true =要求は成功し、それ以外の場合はエラーが発生しました)であり、応答がエコーされます。参照:http : //php.net/en/manual/function.curl-exec.php
  • curl_closeを使用して、セッションのクローズとcurl-handlerの削除をクリーンアップします。参照:http : //php.net/manual/en/function.curl-close.php
  • 数値を使用する代わりに、curl_setopt関数にブール値を使用します(ゼロ以外の数値もtrueと見なされることは知っていますが、trueを使用するとより読みやすいコードが生成されますが、それは私の意見です)
  • HTTP-PUT / DELETE呼び出しを行う機能(RESTfulサービステストに役立ちます)

使用例

取得する

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

役職

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

プット

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

削除

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

テスト中

この単純なクラスを使用して、クールなサービステストを行うこともできます。

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

私にとっては、「キャッチされないエラー:未定義のメソッドHTTPRequester :: HTTPost()への呼び出し」と表示されます。私は単にあなたのクラスを私の.phpファイルに貼り付けました。他に必要なことはありますか?
LinusGeffarth 2018

1
コードを投稿していただけますか?コードスニペットがなければ、何が問題なのかを推測するのはかなり困難です。
mwatzer、2018

私が言ったように、私はあなたのものを私のプレーンなphpファイルに文字通りコピーしました、そしてそれは私にこのエラーを与えました。
LinusGeffarth 2018

1
さて、問題が表示されます。例では間違っていました。HTTPRequester :: HTTPost()の代わりにHTTPRequester :: HTTPPost()を呼び出す必要があります
mwatzer

1
ああ。それは見逃しがちです。余分なPを見つける前に、コメントを5倍のように読まなければなりませんでした。ありがとう!
LinusGeffarth

19

上記のカールのない方法の別の方法は、ネイティブストリーム関数を使用することです。

  • stream_context_create()

    オプションプリセットで指定されたオプションでストリームコンテキストを作成して返します。

  • stream_get_contents()

    と同じですがfile_get_contents()stream_get_contents() 既に開いているストリームリソースを操作し、指定されたオフセットで始まるmaxlengthバイトまでの残りのコンテンツを文字列で返します。

これらのPOST関数は、次のようになります。

<?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
このCURLを使用しない方法は、GoogleからreCAPTCHAを検証するのにうまく機能しました。この答えは、このGoogleのコードで収束する:github.com/google/recaptcha/blob/master/src/ReCaptcha/...
シャビモンテロ

1
fclose()if を使用する必要$fpはありませんfalsefclose()リソースがパラメータであることを期待しているからです。
Floris

1
@Florisが編集したばかりで、fcloseのドキュメントで「ファイルポインタは有効である必要があります」と記載されています。お気づきありがとうございます!
CPHPython

8

での送信GETまたはPOSTリクエストのより良い方法はPHP以下の通りです:

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

コードは、公式ドキュメントhttp://docs.php.net/manual/da/httprequest.send.phpから取得されます


1
@akinuriの強調表示に感謝します。新しいものを共有します。
Imran Zahoor

PHP 5xでそれを行う方法?

この技術を使用して5倍のための上記@YumYumYumしてくださいチェックアウトdbauの答えphp.net/manual/en/function.stream-context-create.phpを それとも、常に標準カール・ソリューションに戻ることができます。
Imran Zahoor

5

もう1つ使用できます

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

詳細はこちら


2
これは、ほとんどインストールされていないPECL拡張機能に依存しています。マニュアルページが削除されているので、まだ利用可能かどうかさえわかりません。
miken32 2016年

5

私は同様の問題を探していて、これを行うより良いアプローチを見つけました。だからここに行く。

次の行をリダイレクトページ(たとえば、page1.php)に置くだけです。

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

REST API呼び出しのPOSTリクエストをリダイレクトするためにこれが必要です。このソリューションは、カスタムヘッダー値だけでなく、投稿データでもリダイレクトできます。

こちらが参考リンクです。


1
これは、ページリクエストリダイレクトする方法ではなく、PHPでPOSTリクエストを送信する方法を教えてください確かに、これはPOSTパラメータを転送しますが、それはまったく同じではありません
Wesley Smith

DelightedD0D @、申し訳ありませんが、私は違い取得できませんでしたredirect a page request with POST param対をsend POST request。私にとっては両方の目的は同じですが、間違っている場合は修正してください。
Arindam Nayak 2016年

1
POSTメソッドでパラメーターを送信し、PHP経由でコンテンツを読み取ることができるメソッドはありますか?OPは、phpスクリプトが一連のPOSTパラメータを作成し、それらを別のphpページに送信し、スクリプトがそのページから出力を受信することを望んでいます。このソリューションは、単にPOST済みの値のセットを受け入れ、それらを別のページに転送するだけです。彼らはかなり異なっています。
ウェズリー・スミス

5

ここでは、cURLなしでコマンドを1つだけ使用しています。超シンプル。

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はどのように機能しますか?それらの間のセパレーターは何ですか?
Muhammad Idrees

@Sayedidrees key2を追加するには、2番目の配列項目として入力できます。'key1' => 'Hello world!'、 'key2' => 'second value'
Liga

これは、zapierで使用しているときに非常にうまく機能します。
Moxet

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.