php請求遠端url內容方法

github_zwl發表於2017-10-16

php請求遠端url內容方法

php請求遠端url內容有兩個方法fopen/file_get_contents和curl。

1,fopen/file_get_contents與curl的差異

(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)curl可以模擬多種請求,例如:POST資料,表單提交等,使用者可以按照自己的需求來定製請求。而fopen / file_get_contents只能使用get方式獲取資料。

2,如果遠端伺服器關閉,file_get_contents處理方法,可以參考這篇文章,http://www.cnblogs.com/scofi/articles/3607529.html

公司裡有經常有這樣的業務,需要呼叫第三方公司提供的HTTP介面,在把介面提供的資訊顯示到網頁上,程式碼是這樣寫的: file_get_contents("http://example.com/") 。

有一天突然接到運維同事的報告,說是伺服器掛了,查出原因說是因為file_get_contents函式造成的,那麼為什麼一個函式會把伺服器給搞掛掉呢?
經過詳細的查詢發現第三方公司提供介面已經壞掉了,就是因為介面壞掉了,才導致伺服器掛掉。
問題分析如下:
       我們程式碼是“file_get_contents("http://example.com/") “獲取一個 URL 的返回內容,如果第三方公司提供的URL響應速度慢,或者出現問題,我們伺服器的PHP程式將會一直執行去獲得這個URL,我們知道,在 php.ini 中,有一個引數 max_execution_time 可以設定 PHP 指令碼的最大執行時間,但是,在 php-cgi(php-fpm) 中,該引數不會起效。真正能夠控制 PHP 指令碼最大執行時間的是 php-fpm.conf 配置檔案中的以下引數: <value name="request_terminate_timeout">0s</value>   預設值為 0 秒,也就是說,PHP 指令碼會一直執行下去,當請求越來越多的情況下會導致php-cgi 程式都卡在 file_get_contents() 函式時,這臺 Nginx+PHP 的 WebServer 已經無法再處理新的 PHP 請求了,Nginx 將給使用者返回“502 Bad Gateway”。CPU的利用率達到100% ,時間一長伺服器就會掛掉。
問題的解決:
     已經找到問題,那麼我們該怎麼解決呢?
     當時想到的解決問題的辦法就是設定PHP的超時時間,用set_time_limit; 設定超時時間,這樣就不會卡住了。程式碼上線後發現伺服器還是會掛掉,好像根本不起作用。後來查了資料才知道,set_time_limit設定的是PHP程式的超時時間,而不是file_get_contents函式讀取URL的超時時間。set_time_limit和修改php.ini檔案裡max_execution_time  效果是一樣的。
要設定file_get_contents函式的超時時間,可以用resource $context的timeout引數,程式碼如下:
 
1
2
3
4
5
6
7
8
9
$opts array(
  'http'=>array(
    'method'=>"GET",
    'timeout'=>10,
  )
);
$context = stream_context_create($opts);
$html =file_get_contents('http://www.example.com', false, $context);
echo $html;

程式碼中的timeout就是file_get_contents讀取url的超時時間。

另外還有一個說法也可以改變讀取url的超時時間,就是修改php.ini中的default_socket_timeout的值,或者 ini_set('default_socket_timeout',    10);  但是我沒有測試過不知道行不行。
有了解決方法之後,伺服器就不會掛掉了。
http://www.cnblogs.com/scofi/articles/3607533.html

上篇說到我們說到設定file_get_contents超時時間用到了 stream_context_create方法,那麼這個方法到底是什麼呢?

查了下資料, stream_context_create建立並返回一個文字資料流並應用各種選項,可用於fopen(),file_get_contents()等過程的超時設定、代理伺服器、請求方式、頭資訊設定的特殊過程。這樣看起來功能就強大了,不僅僅可以設定超時時間,還可以設定代理伺服器,請求方式和頭資訊,下面我們就測試下吧:
request.php請求頁面負責發起請求:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
 $data array("name" => 'test_name',"content" => 'test_con');
 $data = http_build_query($data);
 $opts array(
   'http'=>array(
     'method'=>"POST",
     'header'=>"Content-type: application/x-www-form-urlencoded\r\n".
               "Content-length:".strlen($data)."\r\n" .
               "Cookie: foo=bar\r\n" .
               "\r\n",
     'content' => $data,
   )
 );
 $cxContext = stream_context_create($opts);
 $sFile file_get_contents("http://127.0.0.1/reponse.php", false, $cxContext);  
 echo $sFile;
?>

reponse.php被請求的頁面:

1
2
3
4
<?php
var_dump($_POST);
var_dump($_COOKIE);
?>

  執行之後的結果為:

string(132) "array(2) { ["content"]=> string(8) "test_con" ["name"]=> string(9) "test_name" } array(1) { ["foo"]=> string(3) "bar" } "  
說明file_get_contents可以post資料和cookie資料到目標url,並獲得內容。
3,curl的用法總結,http://www.cnblogs.com/scofi/articles/3607538.html
(1)使用curl,get獲取資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$url 'http://www.example.com';
//初始化一個 cURL 物件
$ch  = curl_init();
//設定你需要抓取的URL
curl_setopt($ch, CURLOPT_URL, $url);
// 設定cURL 引數,要求結果儲存到字串中還是輸出到螢幕上。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//是否獲得跳轉後的頁面
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
$data = curl_exec($ch);
curl_close($ch);
echo $data;
?>

(2)使用curl。post獲取資料

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
function curl_post($url$arr_data){
   $post_data = http_build_query($url_data);
   $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch,  CURLOPT_POSTFLELDS, $post_data);
    $data = curl_exec($ch);
    curl_close($ch);
    echo $data;
}
$arr_post array(
    'name'=>'test_name',
    'age'   => 1
);
curl_post("http://www.explame.com/"$arr_post);
?>

(3)使用代理抓取頁面,什麼要使用代理進行抓取呢?以google為例吧,如果去抓google的資料,短時間內抓的很頻繁的話,你就抓取不到了。google對你的ip地址做限制這個時候,你可以換代理重新抓。

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://google.com");
curl_setopt($ch, CURLOPT_HEADER, false); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//是否通過http代理來傳輸
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, TRUE);
curl_setopt($ch, CURLOPT_PROXY, 125.21.23.6:8080); 
//url_setopt($ch, CURLOPT_PROXYUSERPWD, 'user:password');如果要密碼的話,加上這個 
$result=curl_exec($ch);
curl_close($ch);
?>

(4)繼續保持本站session呼叫,在實現使用者同步登入的情況下需要共享session,如果要繼續保持本站的session,那麼要把sessionid放到http請求中。

1
2
3
4
5
6
7
8
9
10
11
<?php
$session_str = session_name().'='.session_id().'; path=/; domain=.explame.com';
session_write_close(); //將資料寫入檔案並且結束session
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_COOKIE, $session_str);
$ret = curl_exec($ch);
curl_close($ch);
?>


相關文章