
本文详解如何通过 PHP 原生方式(file_get_contents + stream_context_create)发送带表单数据的 POST 请求,并在服务端准确捕获完整的 HTTP 请求头及原始请求体,避免误用 exec(curl) 导致的上下文丢失与安全风险。
本文详解如何通过 PHP 原生方式(`file_get_contents` + `stream_context_create`)发送带表单数据的 POST 请求,并在服务端准确捕获完整的 HTTP 请求头及原始请求体,避免误用 `exec(curl)` 导致的上下文丢失与安全风险。
在 PHP 中调试 POST 请求时,一个常见误区是混淆「请求头(Request Headers)」与「请求体(Request Body)」——你当前代码中试图通过 apache_request_headers() 打印客户端发送的 Header,但实际期望看到的是提交的表单参数(如 feed_them_social=yes),而这些参数默认不会出现在 HTTP 头部中,而是以 application/x-www-form-urlencoded 格式编码后置于请求体(content)内。
你原代码的问题核心在于:
- ❌ 错误调用 exec('curl ...') 并传入 $context(这是一个资源句柄,非字符串),导致命令无效且无法传递真实数据;
- ❌ apache_request_headers() 只能读取 HTTP 请求头(如 Content-Type, User-Agent),无法直接获取 POST 表单内容;
- ✅ 正确路径应为:客户端用 file_get_contents() 发送结构化 POST 请求 → 服务端用 $_POST 或 file_get_contents('php://input') 解析请求体。
✅ 推荐修正方案(客户端):
$postdata = http_build_query([
'feed_them_social' => 'yes',
'refresh_token' => get_option('custom_refresh_token'),
'time' => esc_html(get_option('custom_token_exp_time')),
]);
$opts = [
'http' => [
'method' => 'POST',
'header' => "Content-type: application/x-www-form-urlencoded\r\n" .
"Content-Length: " . strlen($postdata) . "\r\n",
'content' => $postdata,
]
];
$context = stream_context_create($opts);
$response = file_get_contents('https://my-url.com', false, $context);
if ($response === false) {
throw new Exception('HTTP request failed: ' . error_get_last()['message']);
}
echo '<pre>'; print_r($response); echo '</pre>';⚠️ 注意事项:
- Content-Length 必须显式设置(file_get_contents 不自动计算),否则部分服务器(如 Apache + mod_php)可能拒绝解析请求体;
- 确保目标 URL 的服务端脚本(如 https://my-url.com/receive.php)启用 $_POST 自动解析(需 Content-Type: application/x-www-form-urlencoded 且数据格式合法);
- 若需原始请求体(例如调试或处理非标准编码),服务端请使用:
$rawBody = file_get_contents('php://input'); // 获取未解析的 POST body parse_str($rawBody, $postData); // 手动解析为数组 print_r($postData);
? 总结:不要用 exec(curl) 拼接上下文;优先使用 file_get_contents() 配合 stream_context_create() 实现安全、可控的 HTTP 请求;服务端获取参数应依赖 $_POST(表单提交)或 php://input(原始体),而非误读请求头。