スペースシャトルの貨物室のことをペイロード・ベイと言うそうです

おまとめ三行

application/x-www-form-urlencoded
application/json
JSONペイロードの可能性を探ってみるのが良い
Ajaxなどを使ってデータをPOSTすることはよくあると思うんですが、送信されたデータをPHPで受け取る場合、送り方によって$_POSTで値を取れる場合と取れない場合があります。

簡単に言うと、Content-Typeが「application/x-www-form-urlencoded」だと$_POSTで受け取れますが、「application/json」だと受け取れません。

とりあえず両方見てみましょう。

今回はajaxリクエストするURLを「post.php」、PHPで受け取るURLを「receive.php」とします。



application/x-www-form-urlencoded

例えばjQueryの$.ajaxを使ってフォームデータを送信する場合を考えてみます。

//post.php
<form>
  <input type="hidden" name="name" value="name" />
  <input type="hidden" name="age" value="30" />
  <button type="button" id="post">button</button>
</form>

<script>
$(function(){
  $('#post').click(function(){
    $.ajax({
      type: 'POST',
      url: 'receive.php',
      data: $('form').serialize(),
      contentType: 'application/x-www-form-urlencoded'
    }).then(function(data){
      console.log(data);
    });
  });
});
</script>

//receive.php
print_r($_POST);

だいぶざっくりですが、とりあえずこんな感じでフォームデータを送信できますね。

この場合、$_POSTの中身はこうなります。

Array
(
  [name] => name
  [age] => 30
)

特に問題はないですね。普通にフォームのデータを$_POSTで受け取れています。

今回は明示的にContent-Typeを指定しましたが、省略した場合は自動的に「application/x-www-form-urlencoded」になります。



application/json

Content-Typeが「application/json」の場合、フォームのデータはJSON形式で送信することになります。JSONペイロードとか言うこともあるみたいですが、これだと$_POSTに値が入ってきません。

//post.php
<form>
  <input type="hidden" name="name" value="name" />
  <input type="hidden" name="age" value="30" />
  <button type="button" id="post">button</button>
</form>

<script>
$(function(){
  $('#post').click(function(){
    $.ajax({
      type: 'POST',
      url: 'receive.php',
      data: JSON.stringify($('form').serializeArray()),
      contentType: 'application/json'
    }).then(function(data){
      console.log(data);
    });
  });
});
</script>

「JSON.stringify($(‘form’).serializeArray())」ってのはフォームの内容をJSONの形に直すやり方です。詳細については今回は省略。

こんな感じでデータをPOSTすると$_POSTの中身は空になります。



じゃあどうやってJSONデータを取れば良いのかってーと、こうです。

//receive.php
$data = file_get_contents("php://input");
$json = json_decode($data, true);
print_r($json);

「php://input」は読み込み専用のストリームです。リクエストの body 部から生のデータを読み込むことができるとマニュアルには書いてあります。まあ何のことだかよく分かんねっすけど、application/jsonでJSONデータをPOSTした場合はリクエストの中身がJSONデータになるんで、それをそっくりそのまま取得したけりゃ「file_get_contents(“php://input”)」と書けってことですね、きっと。

ちなみに今回の場合だとreceive.phpの$jsonの中身はこんな風になってます。

Array
(
  [0] => Array
  (
    [name] => name
    [value] => name
  )

  [1] => Array
  (
    [name] => age
    [value] => 30
  )
)

$_POSTの時と少し違いますね。これはJSON形式でデータを送ると必ずこうなるってわけじゃなくて、「JSON.stringify($(‘form’).serializeArray())」でデータをJSON形式に直した場合にこうなるってだけです。自分でフォームのデータを送信する前に整形して「[{name:’name’},{age:30}]」みたいなJSONデータに直してあげれば$_POSTの時と同じような形になります。






いろんなAPIを使っていると、$_POSTでデータを受け取れる時もあれば取れない時もあります。最近自分が触った中ではFacebookのMessengerとかメール配信サービスのSendgridのAPIはJSONペイロードでデータをPOSTしてくるので、$_POSTではデータを取れませんでした。

何はともあれ、$_POSTでデータが取れなくても焦らず落ち着いて、まずはJSONペイロードの可能性を探ってみるのが良いかと思います。