雖然日常開發較少用到 PHP 模擬 POST 提交,但在 API 串接、第三方支付回調、爬蟲等場景中非常常見。本文整理三種主流實作方式並提供完整代碼範例。
利用 PHP 內建的串流上下文建立 HTTP POST 請求:
<?php
function file_get_contents_post($url, $post) {
$options = array(
'http' => array(
'method' => 'POST',
'content' => http_build_query($post),
),
);
$result = file_get_contents($url, false, stream_context_create($options));
return $result;
}
$data = file_get_contents_post(
"https://www.a.com/post/post.php",
array('name' => 'caiknife', 'email' => 'caiknife@gmail.com')
);
var_dump($data);
功能最完整、效能最好、支援 HTTPS、可設定超時、Header 等進階選項:
<?php
function curl_post($url, $post) {
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post,
);
$ch = curl_init($url);
curl_setopt_array($ch, $options);
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
$data = curl_post(
"https://www.a.com/post/post.php",
array('name' => 'caiknife', 'email' => 'caiknife@gmail.com')
);
var_dump($data);
手動組裝 HTTP 協議封包,理解 HTTP 協議本質的最佳方式:
<?php
function socket_post($url, $post) {
$urls = parse_url($url);
if (!isset($urls['port'])) { $urls['port'] = 80; }
$fp = fsockopen($urls['host'], $urls['port'], $errno, $errstr);
if (!$fp) { echo "$errno, $errstr"; exit(); }
$post = http_build_query($post);
$length = strlen($post);
$header = <<<HEADER
POST {$urls['path']} HTTP/1.1
Host: {$urls['host']}
Content-Type: application/x-www-form-urlencoded
Content-Length: {$length}
Connection: close
{$post}
HEADER;
fwrite($fp, $header);
$result = '';
while (!feof($fp)) {
$result .= fread($fp, 512);
}
// 移除 HTTP Header,只保留 Body
$result = explode("\r\n\r\n", $result, 2);
return $result[1];
}
$data = socket_post(
"https://www.a.com/post/post.php",
array('name' => 'caiknife', 'email' => 'caiknife@gmail.com')
);
var_dump($data);
| 方法 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| file_get_contents | 語法簡潔、無需擴充 | 功能有限、難以處理複雜 Header | 簡單 GET/POST、內部服務呼叫 |
| cURL | 功能完整、效能佳、支援多協議 | 需安裝擴充(現代 PHP 預設啟用) | 生產環境首選、API 串接、爬蟲 |
| Socket | 無依賴、可控制每個協議細節 | 手動處理 Header/Body 分離、錯誤處理複雜 | 教學用途、特殊協議需求 |
/**
* 模擬 POST 進行 URL 請求
* @param string $url
* @param array $post_data
*/
function request_post($url = '', $post_data = array()) {
if (empty($url) || empty($post_data)) { return false; }
// 陣列轉查詢字串
$o = "";
foreach ($post_data as $k => $v) {
$o .= "$k=" . urlencode($v) . "&";
}
$post_data = substr($o, 0, -1);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
function testAction() {
$url = 'https://mobile.jschina.com.cn/jschina/register.php';
$post_data = array(
'appid' => '10',
'appkey' => 'cmbohpffXVR03nIpkkQXaAA1Vf5nO4nQ',
'member_name' => 'zsjs124',
'password' => '123456',
'email' => 'zsjs124@126.com',
);
$res = request_post($url, $post_data);
print_r($res); // 通常回傳 JSON 格式
}
http_build_query() 會自動處理 URL 編碼,建議統一使用