本文主要讲file_get_contents、fsockopen、stream_context_create、curl 在php中的使用方法以及他们适合使用场景的讨论。

 

1、用file_get_contents的get方式获取

$url = 'http://sobird.me/';
$result= file_get_contents($url);

2、用file_get_contents的post方式获取

$postdata = http_build_query($data);
$options= array(
    'http' => array(
        'method'  => 'POST',
        'header'  => 'Content-type: application/x-www-form-urlencoded',
        'content' => $postdata
    )
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);

注:file_get_contents 需要php.ini里开启allow_url_fopen,allow_url_include 方可使用

3、用fopen打开url,以get方式获取

$fp = fopen($url, 'r');
stream_get_meta_data($fp);
$result = '';
while(!feof($fp)){
    $result .= fgets($fp, 1024);
}
echo $result;
fclose($fp);

4、用 fsockopen 函数打开url,以get方式获取完整的数据,包括header和body

$query = '?test=test';
$host = 'sobird.me';
$port = 80;
$timeout = 30;

if (!$fp = @fsockopen($host, $port, $errno, $errstr, $timeout)) {
    // Set error message
    switch($errno) {
        case -3:
            $errormsg = 'Socket creation failed (-3)';
        case -4:
            $errormsg = 'DNS lookup failure (-4)';
        case -5:
            $errormsg = 'Connection refused or timed out (-5)';
        default:
            $errormsg = 'Connection failed ('.$errno.')';
            $errormsg .= ' '.$errstr;
    }
}

$request = "GET $query HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= "Connection: Close\r\n";

$request.="\r\n";
fwrite($fp,$request);
$result = '';
while(!feof($fp)){
    $result .= @fgets($fp, 1024);
}
fclose($fp);
echo $result;

5、用fsockopen函数打开url,以POST方式获取完整的数据,包括header和body

$url = 'http://sobird.me/';
function HTTP_Post($URL,$data,$cookie, $referer=""){

	// parsing the given URL
    $URL_Info = parse_url($URL);

	// making string from $data
    foreach($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;

	$request = '';
	// building POST-request:
    $request.="POST ".$URL_Info["path"]." HTTP/1.1\n";
    $request.="Host: ".$URL_Info["host"]."\n";
    $request.="Referer: $referer\n";
    $request.="Content-type: application/x-www-form-urlencoded\n";
    $request.="Content-length: ".strlen($data_string)."\n";
    $request.="Connection: close\n";

    $request.="Cookie:   $cookie\n";

    $request.="\n";
    $request.=$data_string."\n";

    $fp = fsockopen($URL_Info["host"],$URL_Info["port"]);
    fputs($fp, $request);
	$result = '';
    while(!feof($fp))
    {
        $result .= fgets($fp, 1024);
    }
    fclose($fp);

    return $result;
}

$data = array(
	'test'=>'test'
); 

$cookie = '';
$referer = 'http://sobird.me/';

echo HTTP_Post($url, $data, $cookie, $referer);

6、使用curl库,打开url,以get方式获取

$url = 'http://sobird.me/';
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 5);
$file_contents = curl_exec($ch);
curl_close($ch);
echo $file_contents;

7、使用curl库,打开url,以post方式获取

$url = 'http://sobird.me/';
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, 'test=test');
$file_contents = curl_exec($ch);
curl_close($ch);
echo $file_contents;

关于curl与fsockopen。

fsockopen 是比较底层的调用,属于网络系统的socket调用,而curl经过的包装支持HTTPS认证,HTTP POST方法, HTTP PUT方法, FTP上传, kerberos认证,HTTP上传, 代理服务器, cookies, 用户名/密码认证, 下载文件断点续传,上载文件断点续传,http代理服务器管道( proxy tunneling), 甚至它还支持IPv6, socks5代理服务器,,通过http代理服务器上传文件到FTP服务器等等,功能十分强大。fsockopen 返回的是没有处理过的数据,包括数据的长度数据内容和数据的结束符。而curl是处理后的内容。

在用户使用时,curl 更加方便,但其参数很多,配置稍微复杂,fsockopen 则有固定的几个参数,简单,但获取结果可能需要再做处理。

关于file_get_contents

有些时候用 file_get_contents() 调用外部文件容易超时报错。curl 效率比 file_get_contents() 和 fsockopen() 高一些,原因是CURL会自动对DNS信息进行缓存。

file_get_contents / curl / fsockopen 在当前所请求环境下选择性操作,没有一概而论。

file_get_contents 需要php.ini里开启allow_url_fopen,请求http时,使用的是http_fopen_wrapper,不会keeplive的话curl是可以的。 file_get_contents()单个执行效率高,返回没有头的信息。

这个是读取一般文件的时候并没有什么问题,但是在读取远程问题的时候有可能就会出现问题。 如果是要打一个持续连接,多次请求多个页面。那么file_get_contents和fopen就会出问题。 取得的内容也可能会不对。所以做一些类似采集工作的时候,肯定就有问题了。

fsockopen 较底层,可以设置基于UDP或是TCP协议去交互,配置麻烦,不易操作。 返回完整信息。

总之,file_get_contents 和 curl 能干的,socket都能干。socket能干的,curl 就不一定能干了 。file_get_contents 更多的时候只是去拉取数据。效率比较高也比较简单。

只讨论 curl 与file_get_contents 的话,有这么一些结论:

  1. fopen /file_get_contents 每次请求都会重新做DNS查询,并不对DNS信息进行缓存。但是CURL会自动对DNS信息进行缓存。对同一域名下的网页或者图片的请求只需要一次DNS查询。这大大减少了DNS查询的次数。所以CURL的性能比fopen /file_get_contents 好很多。
  2. fopen /file_get_contents在请求HTTP时,使用的是http_fopen_wrapper,不会keeplive。而curl却可以。这样在多次请求多个链接时,curl效率会好一些。
  3. fopen / file_get_contents函数会受到php.ini文件中allow_url_open选项配置的影响。如果该配置关闭了,则该函数也就失效了。而curl不受该配置的影响。
  4. curl可以模拟多种请求,例如:POST数据,表单提交等,用户可以按照自己的需求来定制请求。而fopen / file_get_contents只能使用get方式获取数据。

PS:file_get_contents()函数获取https链接内容的时候,需要php 中mod_ssl的支持(或安装opensll)。

结论就是,curl 效率及稳定都比 file_get_contents() 要好,fsockopen 也很强大,但是比较偏底层。

 

参考:http://www.nowamagic.net/academy/detail/12220248