2013年6月15日 星期六

PHP 使用 file_get_contents 接收 POST 的資料

一般接收 POST 資料都是使用 $_POST 這個變數,
但 $_POST 只能取得 Content-type 為 application/x-www-form-urlencoded 或 multipart/form-data 的資料。
當 Content-type 為 text/xml、application/xml、application/json、... 等其他類型的資料,$_POST便無法取得。

若有接收其他類型 Content-type 的需求,可以使用 php://input,
php://input 可以讀取 request body 的資料,所以可以取得 HTTP POST 的資料,
但有一個限制,就是當 Content-type 為 multipart/form-data ,php://input 會取得空值,無法使用

下面範例 php://input 搭配 file_get_contents 使用,和 $_POST 比較在 Content-type 分別為 multipart/form-data、application/x-www-form-urlencoded、text/xml 時,兩者接收資料的情況

接收資料的程式:
後面範例用來 request 的網址:http://127.0.0.1/test/test.php
$postdata = file_get_contents("php://input",'r'); 
var_dump($postdata); // php://input
var_dump($_POST);

範例 1:(multipart/form-data)
使用 curl 模擬 HTTP POST,Content-type 為 multipart/form-data
(CURLOPT_POSTFIELDS 資料為陣列時,會以 multipart/form-data 方式傳送)
$ch = curl_init();
$data = array('aa'=>'123', 'bb'=>'456');
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/test/test.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_exec($ch);
curl_close($ch);
輸出結果:file_get_contents("php://input",'r') 取不到 multipart/form-data 的值
$postdata:string(0) ""
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }

範例 2:(application/x-www-form-urlencoded)
使用 curl 模擬 HTTP POST,Content-type 為 application/x-www-form-urlencoded
$ch = curl_init();
$data = 'aa=123&bb=456';
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/test/test.php');
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded"));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_exec($ch);
curl_close($ch);
輸出結果:file_get_contents("php://input",'r') 和 $_POST 的資料一樣,但 $_POST 已轉成陣列
$postdata (OK):string(13) "aa=123&bb=456"
$_POST (OK):array(2) { ["aa"]=> string(3) "123" ["bb"]=> string(3) "456" }

範例 3(text/xml)
使用 curl 模擬 HTTP POST,Content-type 為 text/xml
$ch = curl_init();
$data = '<?xml version="1.0" encoding="utf-8"?><root><aa>123</aa><bb>456</bb></root>';
curl_setopt($ch, CURLOPT_URL, 'http://127.0.0.1/test/test.php');
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-type: text/xml;charset=\"utf-8\""));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HEADER,0);
curl_exec($ch);
curl_close($ch);
輸出結果:file_get_contents("php://input",'r') 可以讀取 POST 過來的 XML 資料,$_POST 無法讀取
$postdata (OK):string(36) "<?xml version="1.0" encoding="utf-8"?><root><aa>123</aa><bb>456</bb></root>"
$_POST:array(0) {}


結論:
所以如果有一 PHP 程式,用來接收其它地方 POST 過來的body資料,例如是 XML 或 JSON 的資料,就可以利用 file_get_contents("php://input",'r') 來取得 POST 過來的內容。

參考:
http://php.net/manual/en/function.file-get-contents.php (file_get_contents)
http://www.php.net/manual/en/wrappers.php.php (php://)
http://www.php.net/manual/en/wrappers.php (Supported Protocols and Wrappers)
http://php.net/manual/en/reserved.variables.post.php ($_POST)

沒有留言:

張貼留言