PHPでPOST送信。バックエンドから他システムへのPOST送信

通常であれば、HTMLの<form method=’POST’>でデータを送信したり、JavaScriptでAjax通信を実装して、主にフロントエンドから行う処理ですが、
今回は、PHPプログラム側で、POSTリクエストを送信し、結果(レスポンス)を受け取る処理を書いてみました。
PHPのcurl関数を使ってPOST送信するのが、速度的には早いらしいですが、
今回は、お手軽なfile_get_contents()を使って、実装してみました。

file_get_contents()関数をで、POSTリクエストを実現

まずはソースから

<?php

$url = 'https://adan.jp.com/plese_post_request.php';
$param = array(
  'id' => 478,
  'msg' => 'フリーランスプログラマーを積極的に募集しています♪'
);
$contents_array = post_request($url, $param);

/**
 * POST送信実行
 */
function post_request($url, $param)
{
  //リクエスト時のオプション指定
  $options = array(
    'http' => array(
    'method' => 'POST', //ここでPOSTを指定
    'header' => array(
      'Content-type: application/x-www-form-urlencoded',
      'User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:13.0) Gecko/20100101 Firefox/13.0.1'
      ),
    'content' => http_build_query($param),
    'ignore_errors' => true,
    'protocol_version' => '1.1'
    ),
    'ssl' => array(
      'verify_peer' => false,
      'verify_peer_name' => false
      )
    );

  //リクエスト実行
  $contents = @file_get_contents($url, false, stream_context_create($options));

  //ステータスコード抜粋
  preg_match('/HTTP\/1\.[0|1|x] ([0-9]{3})/', $http_response_header[0], $matches);
    $statusCode = (int)$matches[1];

    //配列で返すためにjsonのエンコード
    $contents_array = array();
    if($statusCode === 200){
      $contents_array = json_decode($contents);
    }
    return $contents_array;
}
Content-typeに関して
Content-type: application/x-www-form-urlencoded、実際のブラウザからのフォームの送信時に、Webサーバーに送信するヘッダー情報「Content-Type」名の一つで、つけないと受けっ取ってくれないWebサーバーもあるらしく、一応つけておいたほうが無難♪
verify_peerに関して
SSLサーバー証明書の検証を要求するかどうかのフラグで、今回は要求しない
verify_peer_nameに関して
ピア名の検証を要求するかどうか。。。ピア(・・?
通信相手から受け取った相手の証明書らしい。。。この値がtrueだとオレオレ証明書使ってるサーバーへはPOSTできないっぽいです。のでfalse

テストするのはちょっと手間で、
受け取り側のプログラムを用意して、そこでPOSTリクエストを受け付けた際に、ログを出力して、そのログを「tail -f」で眺めるという確認方法が一番良いかもです。

Content-typeのトラブル回避!http_build_queryの関係性

「Content-type: application/x-www-form-urlencoded」と指定してあげているのですが、
Contet-typeを指定しない場合でも動いちゃいます。また、値を指定する際にhttp_build_query関数を使ってエンコードしていますが、こちらもなくても動いちゃいます。どちらも使わなかった場合、「Content-type: multipart/form-data」がデフォルトで通信してしまう場合があります。「multipart/form-data」はファイル転送に使うプロトコルなので、オーバヘッドが大きく処理が遅くなったり、うまくPOSTできなくなる可能性が高いので。
ちなみに、エンコードしてあげない場合、「boundary=—————————-4b52323a872f」てきなかんじなります。
ちゃんと、Content-typeを指定し、http_build_query関数でちゃっとエンコードしてあげましょう。

curl関数を使ってPOSTリクエストを実現

こんどは、Linuxのcurlコマンドを扱えるcurl関数を使って、実装してみます。file_get_contents関数はcurlをラップして作られてるっぽいですね。おそらくこっちの方が速度的に早いです。のでおすすめ♪

<?php

$url = 'https://adan.jp.com/plese_post_request.php';
$param = array(
  'id' => 478,
  'msg' => 'フリーランスプログラマーを積極的に募集しています♪'
);
$contents_array = post_request($url, $param);

function post_request($url, $param)
{

  //curlおじさんを初期化
  $ch = curl_init();
  //配列をhttp_build_queryでエンコードしてあげること
  curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param));

  //上記で述べたピア問題
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

  //相手側からのデータの返り値を文字列で取得
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  //TRUE を設定すると、ヘッダの内容も出力します。
  //curl_setopt($ch, CURLOPT_HEADER, 1);

  //Content-Typeとユーザエージェントを指定
  $headers = array(
    "Content-Type: application/x-www-form-urlencoded",
    "User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"
  );
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

  //送信先の指定
  curl_setopt($ch, CURLOPT_URL, $url);
  //curlおじさん実行
  $response_json = curl_exec($ch);
  $result = json_decode($response_json);
  //curlおじさんを閉じる
  curl_close($ch);

}