cURLでbody付きのGETリクエスト

お前は何を言ってるんだ？

------------------- ↓ 余談はここから ↓-------------------
ヾ(・ω<)ﾉ"　三三三●　ⅱⅲ コロコロ♪

----


タイトルからミルコクロコップさんもビックリのことだが、
そういう依頼されたが来たというのだから小説より奇なりである。

body付きのHTTPリクエストならPOSTやPUTなどの話だと思うが、
仕様を見ると
・GETで送ってね
・クエリストリング駄目よ
(ﾟДﾟ)ﾊｧ?

つまり以下のコマンドが実現できればいいということか。

```shell-session
curl -X GET http://適当なURL/endpoint.php --data "{abc:efg}"
```

さて、これが困ったもので。
PHPでAPIの処理をするにはcURLライブラリを使うといろいろうまくいかなかったりする。
(検証部分は後書にコード付きで説明する)
あとchrome拡張とかのAPIツールとかはGET+BODYに対応してないのが多い。

 (ー_ー；)。o O (どうしよう)

取りあえずcURL以外の方法でfile_get_contentsで実装。
stream_context_createを駆使すればUser-Agentを変えたりPOSTリクエストしたりと意外に柔軟にできるので実装は可能なものの、
エラー処理問題がどうしても発生して何とも言い難いものに。
(こちらも後書に記載)

それで丸く収めようと検証記事(この記事です)を書いている途中に面白いものを見つけた。
それが

**CURLOPT_CUSTOMREQUEST**

curlコマンドの-Xにあたるものだと理解しているが、
これを使えば行けそうだ。

------------------- ↓ 本題はここから ↓-------------------
ヾ(・ω<)ﾉ"　三三三●　ⅱⅲ コロコロ♪

----

## curlでGET+BODY

### 準備

まずは受信側の準備

```php:endpoint.php
<?php
// method値の確認
echo "METHOD:".$_SERVER["REQUEST_METHOD"]."\n";
// body値の確認
// PHPでBODYの文字列を取るにはphp:://inputを取得する
echo "BODY:".file_get_contents('php://input')."\n";
```

### curlコマンドで実行

```shell-session
$ curl http://適当なURL/endpoint.php --data "{abc:efg}"
METHOD:POST
BODY:{abc:efg}
```

```shell-session
$ curl -X GET http://適当なURL/endpoint.php --data "{abc:efg}"
METHOD:GET
BODY:{abc:efg}
```

問題なく動いているね。

### CURLOPT_CUSTOMREQUESTで実装

#### コード

```php:curl.php
$url = "http://適当なURL/endpoint.php";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);

curl_setopt($ch, CURLOPT_POSTFIELDS, '{abc:efg}');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");

$res = curl_exec($ch);
curl_close($ch);
echo $res;
```

#### 実行

```shell-session
$ php curl.php
METHOD:GET
BODY:{abc:efg}
```

(`・ω・´)


------------------- ↓ 後書はここから ↓-------------------
ヾ(・ω<)ﾉ"　三三三●　ⅱⅲ コロコロ♪

----

## curlでGET+BODYを実現できるのか調査

### cURLライブラリで検証

phpは5.6.11、cURLは7.43.0。

#### 準備

まずは基本コード。
これ以降のコードは差し替えの部分だけ記述する。

```php:curl.php
$url = "http://適当なURL/endpoint.php";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);

/*** ↓ 差し替え開始 ↓ ***/
/*** ↑ 差し替え終了 ↑ ***/

$res = curl_exec($ch);
curl_close($ch);
echo $res;
```

実行すると

```shell-session
$ php curl.php
METHOD:GET
BODY:
```

#### 単純にCURLOPT_POSTFIELDSを設定

```php
/*** ↓ 差し替え開始 ↓ ***/
curl_setopt($ch, CURLOPT_POSTFIELDS, '{abc:efg}');
/*** ↑ 差し替え終了 ↑ ***/
```
実行すると

```shell-session
$ php curl.php
METHOD:POST
BODY:{abc:efg}
```

BODYは取れたけど、POSTに変化している。

#### CURLOPT_POSTをfalseに設定

ではそのあとでPOSTをfalseに設定してみる

```php
/*** ↓ 差し替え開始 ↓ ***/
curl_setopt($ch, CURLOPT_POSTFIELDS, '{abc:efg}');
curl_setopt($ch, CURLOPT_POST, false);
/*** ↑ 差し替え終了 ↑ ***/
```
実行すると

```shell-session
$ php curl.php
METHOD:GET
BODY:
```

(ﾟДﾟ;) 一緒にBODYまで消えた!?
まさにPHPマジックだわ。

#### CURLOPT_HTTPGETを設定

POSTをfalseにする代わりに、
HTTPGETを使ってみる

```php
/*** ↓ 差し替え開始 ↓ ***/
curl_setopt($ch, CURLOPT_POSTFIELDS, '{abc:efg}');
curl_setopt($ch, CURLOPT_HTTPGET, true);
/*** ↑ 差し替え終了 ↑ ***/
```
実行すると

```shell-session
$ php curl.php
METHOD:GET
BODY:
```

一緒デスタ。。。orz


## file_get_contentsの場合

せっかくなのでこちらも載せておこう

#### stream_context_createを使ってGET+BODY

```php:fget.php
$opts = array('http' =>
    array(
        'method'  => 'GET',
        'content' =>  '{abc:efg}',
    )
);

$context = stream_context_create($opts);
$res = @file_get_contents($url, false, $context);
echo $res;
```

まぁ、@からわかるようにあんまり推奨はしないけどね。