php 模拟post的新发现,重点在最后的新方法
最近两天项目需要,由于服务器正在开发,客户端进度稍快一些,没有服务器进行联调。因此我重操旧业,用PHP快速的写了一些web页面,算是当测试桩程序了,七八个web接口,基本上5到6个小时搞定了。由于当前的服务器需要与其他服务器进行对接,因此写的这个web服务还需要充当client角色,向其他服务器发送请求。
在网上搜了一下,基本上两种方法:(转自网友文章)
1.通过curl函数
$post_data = array () ;
$post_data [ ' clientname ' ] = " test08 " ;
$post_data [ ' clientpasswd ' ] = " test08 " ;
$post_data [ ' submit ' ] = " submit " ;
$url = ' http://xxx.xxx.xxx.xx/xx/xxx/top.php ' ;
$o = "" ;
foreach ( $post_data as $k => $v )
{
$o .= " $k = " . urlencode ( $v ) . " & " ;
}
$post_data = substr ( $o , 0 ,- 1 ) ;
$ch = curl_init () ;
curl_setopt ( $ch , CURLOPT_POST , 1 ) ;
curl_setopt ( $ch , CURLOPT_HEADER , 0 ) ;
curl_setopt ( $ch , CURLOPT_URL , $url ) ;
//为了支持cookie
curl_setopt ( $ch , CURLOPT_COOKIEJAR , ' cookie.txt ' ) ;
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $post_data ) ;
$result = curl_exec ( $ch ) ;
$post_data [ ' clientname ' ] = " test08 " ;
$post_data [ ' clientpasswd ' ] = " test08 " ;
$post_data [ ' submit ' ] = " submit " ;
$url = ' http://xxx.xxx.xxx.xx/xx/xxx/top.php ' ;
$o = "" ;
foreach ( $post_data as $k => $v )
{
$o .= " $k = " . urlencode ( $v ) . " & " ;
}
$post_data = substr ( $o , 0 ,- 1 ) ;
$ch = curl_init () ;
curl_setopt ( $ch , CURLOPT_POST , 1 ) ;
curl_setopt ( $ch , CURLOPT_HEADER , 0 ) ;
curl_setopt ( $ch , CURLOPT_URL , $url ) ;
//为了支持cookie
curl_setopt ( $ch , CURLOPT_COOKIEJAR , ' cookie.txt ' ) ;
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $post_data ) ;
$result = curl_exec ( $ch ) ;
2. 通过fsockopen
$URL =‘ http : //xxx.xxx.xxx.xx/xx/xxx/top.php';
$post_data [ ' clientname ' ] = " test08 " ;
$post_data [ ' clientpasswd ' ] = " test08 " ;
$post_data [ ' submit ' ] = " ログイン " ;
$referrer = "" ;
// parsing the given URL
$URL_Info = parse_url ( $URL ) ;
// Building referrer
if ( $referrer == "" ) // if not given use this script as referrer
$referrer = $_SERVER [ " SCRIPT_URI " ] ;
// making string from $data
foreach ( $post_data as $key => $value )
$values [] = " $key = " . urlencode ( $value ) ;
$data_string = implode ( " & " , $values ) ;
// Find out which port is needed - if not given use standard (=80)
if ( ! isset ( $URL_Info [ " port " ]))
$URL_Info [ " port " ] = 80 ;
// building POST-request:
$request .= " POST " . $URL_Info [ " path " ] . " HTTP/1.1 /n " ;
$request .= " Host: " . $URL_Info [ " host " ] . " /n " ;
$request .= " Referer: $referrer /n " ;
$request .= " Content-type: application/x-www-form-urlencoded /n " ;
$request .= " Content-length: " . strlen ( $data_string ) . " /n " ;
$request .= " Connection: close /n " ;
$request .= " /n " ;
$request .= $data_string . " /n " ;
$fp = fsockopen ( $URL_Info [ " host " ] , $URL_Info [ " port " ]) ;
fputs ( $fp , $request ) ;
while ( ! feof ( $fp )) {
$result .= fgets ( $fp , 128 ) ;
}
fclose ( $fp ) ;
$post_data [ ' clientname ' ] = " test08 " ;
$post_data [ ' clientpasswd ' ] = " test08 " ;
$post_data [ ' submit ' ] = " ログイン " ;
$referrer = "" ;
// parsing the given URL
$URL_Info = parse_url ( $URL ) ;
// Building referrer
if ( $referrer == "" ) // if not given use this script as referrer
$referrer = $_SERVER [ " SCRIPT_URI " ] ;
// making string from $data
foreach ( $post_data as $key => $value )
$values [] = " $key = " . urlencode ( $value ) ;
$data_string = implode ( " & " , $values ) ;
// Find out which port is needed - if not given use standard (=80)
if ( ! isset ( $URL_Info [ " port " ]))
$URL_Info [ " port " ] = 80 ;
// building POST-request:
$request .= " POST " . $URL_Info [ " path " ] . " HTTP/1.1 /n " ;
$request .= " Host: " . $URL_Info [ " host " ] . " /n " ;
$request .= " Referer: $referrer /n " ;
$request .= " Content-type: application/x-www-form-urlencoded /n " ;
$request .= " Content-length: " . strlen ( $data_string ) . " /n " ;
$request .= " Connection: close /n " ;
$request .= " /n " ;
$request .= $data_string . " /n " ;
$fp = fsockopen ( $URL_Info [ " host " ] , $URL_Info [ " port " ]) ;
fputs ( $fp , $request ) ;
while ( ! feof ( $fp )) {
$result .= fgets ( $fp , 128 ) ;
}
fclose ( $fp ) ;
上述两种方法没有封装成通用的function,我验证了方法2,发现基本上能实现功能,但有两个很大的缺点:
1. 延迟比较大,我在内网测试,用命令行进行的测试,发现响应有时候需要2S以上,不能接受。
2. 读到的response包含了HTTP头域信息,但是大部分情况下,我们只需要body部分内容,要提取body内容,还需要一番处理。
方法1感觉也很笨拙,似乎也很难满足我的需求,最后忘记在哪个英文网站上找到了下面这个方法:
function do_post_request($url, $data, $optional_headers = null)
{
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = @stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url, $php_errormsg");
}
return $response;
}
{
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = @fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url, $php_errormsg");
}
$response = @stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url, $php_errormsg");
}
return $response;
}
试用了一下,感觉效果非常好,简洁,通用,而且返回的内容仅仅是Body中内容。我也没去仔细研究这些API的说明,就采用了这个,没发现有大的问题。如果有人有类似需求,推荐大家采用这个function.
2018年7月24日
还有一个呢
function do_post_request3 ($url, $params = array()) {
$data_string = json_encode($params);
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($c, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($c, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($c, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'Content-Length: ' . strlen($data_string)));
$rsp = curl_exec($c);
curl_close($c);
return json_decode($rsp, true);
}
破罐子互摔