php模拟post
发帖时间:2026-10-17 04:59:54
PHP模拟POST这事,说穿了就是让服务器以为你是从表单里提交的数据。但实际你可能是用命令行、cURL或者一段脚本在跟它对话。我最早接触这玩意儿,是给一个老旧的内部系统写自动签到脚本,那系统压根没提供API,唯一入口就是个HTML表单。逼急了,只能自己伪造请求头。 先看最粗暴的方式——用cURL命令行。假设你要给`http://example.com/login.php`发个POST,带用户名和密码: ```bash curl -d "username=admin&password=123456" http://example.com/login.php ``` `-d`参数会自动把数据编码成`application/x-www-form-urlencoded`格式,这是默认表单提交方式。服务器收到后,`$_POST['username']`和`$_POST['password']`就能取到值。要是对方接口要JSON格式,得加个`Content-Type`头: ```bash curl -H "Content-Type: application/json" -d '{ "username":"admin","password":"123456"}' http://example.com/login.php ``` 但命令行终归不方便嵌入到业务逻辑里。用PHP原生实现的话,最基础的是`file_get_contents`配合流上下文: ```php $postData = http_build_query(['username' => 'admin', 'password' => '123456']); $options = [ 'http' => [ 'method' => 'POST', 'header' => "Content-Type: application/x-www-form-urlencoded\r\n" . "Content-Length: " . strlen($postData) . "\r\n", 'content' => $postData, 'timeout' => 10 ] ]; $context = stream_context_create($options); $result = file_get_contents('http://example.com/login.php', false, $context); ``` 这段代码里有个细节容易踩坑——`Content-Length`必须手动算,少一个字节服务器就可能卡住等剩余数据。另外`http_build_query`会把数组自动编码,比手拼字符串安全得多,至少不用操心特殊字符转义。 真正干活的时候,我更推荐用cURL扩展。它处理重定向、Cookie、SSL证书这些坑爹情况要省心得多: ```php $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => 'http://example.com/login.php', CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query(['username' => 'admin', 'password' => '123456']), CURLOPT_RETURNTRANSFER => true, CURLOPT_FOLLOWLOCATION => true, // 自动跟随跳转 CURLOPT_COOKIEJAR => 'cookies.txt', // 保存会话Cookie CURLOPT_COOKIEFILE => 'cookies.txt', CURLOPT_TIMEOUT => 15 ]); $response = curl_exec($ch); curl_close($ch); ``` `POSTFIELDS`传字符串时,cURL会自动带`Content-Type: application/x-www-form-urlencoded`。但你要是传个关联数组,它反而会变成`multipart/form-data`格式——这俩在服务端解析上有细微差别,某些严格的接口会校验Content-Type,所以最好统一用`http_build_query`转成字符串。 有个真实案例。去年给一个电商平台写库存同步工具,对方接口要求POST数据里嵌套JSON字段,同时还带一个文件上传。我当时用cURL的`CURLFile`处理文件,JSON部分放在`POSTFIELDS`数组里,但发现服务端一直报格式错误。折腾了半天,才发现问题出在——数组里混了`CURLFile`对象,cURL自动切到了`multipart`模式,而对方的JSON字段期望的是纯文本。解决办法是把JSON字段单独编码成字符串塞进数组,让它作为`multipart`的一部分传输。 模拟POST也不总是为了绕开限制。有时候纯粹是调试需要——比如本地起了个服务,想快速测接口返回码,又不想开浏览器填表单。写个简单脚本,循环发POST,看响应时间波动,比手工点一百遍按钮靠谱多了。 最后提醒一句,别拿这招去刷票、爬数据或者干违反robots协议的事。服务器日志里全留痕,真想查你,POST来源IP一翻一个准。技术本身中立,但用的人得有点数。