php函數file_get_contents(一)


早在2010年時候遇到過這樣的事情,因為file_get_contents函數造成服務器掛掉的情況,現在覺得很有必要總結下。

公司里有經常有這樣的業務,需要調用第三方公司提供的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 $opts = array(
2   'http'=>array(
3     'method'=>"GET",
4     'timeout'=>10,
5   )
6 );
7 $context = stream_context_create($opts);
8 $html =file_get_contents('http://www.example.com', false, $context);
9 echo $html;

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

另外還有一個說法也可以改變讀取url的超時時間,就是修改php.ini中的default_socket_timeout的值,或者 ini_set('default_socket_timeout',    10);  但是我沒有測試過不知道行不行。
有了解決方法之后,服務器就不會掛掉了。
在解決的過程中我還發現起到關鍵作用的是stream_context_create方法,里面method 可以是GET,那么能否可以POST呢?還有沒有其他的參數?
還有一個為老同事告訴我們還有一個比file_get_contents更好的辦法,就是用CURL。
請看下面兩篇。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM