Windows下PHP服務nginx不能使用file_get_contents的緣由

注意:本文爲轉載,原文連接: Windows下PHP服務nginx不能使用file_get_contents/curl/fopen的緣由!

1、問題說明

在Windows環境下搭建了一個本地開發服務環境,使用Nginx作服務,可是在使用file_get_contents()獲取本地的連接時http://127.0.0.1/index.php,出現了這樣的錯誤:php

file_get_contents(http://127.0.0.1/index.php) [<a href='function.file-get-contents'>function.file-get-contents</a>]: failed to open stream: HTTP request failed!

本地電腦php環境爲:nginx+php+mysql;因而找到這篇文章作個筆記,記錄下!html

這兩天一直在搞windows下nginx+fastcgi的file_get_contents請求。我想,不少同窗都遇到當file_get_contents請求外網的http/https的php文件時毫無壓力,好比echo file_get_contents(‘http://www.baidu.com’) ,它會顯示百度的頁面。但當你請求localhost/127.0.0.1本地網絡的php服務時卻一直是timeout,不管你將請求時間和腳本運行時間多長都沒法返回數據,如file_get_contents(‘http://localhost/phpinfo.php’) 。然而當你嘗試請求html這樣的靜態文件時卻徹底沒有問題。是什麼緣由呢?!mysql

首先,咱們知道file_get_contents/curl/fopen打開一個基於tcp/ip的http請求時,請求數據發送到nginx,而nginx則委託給php-cgi(fastcgi)處理php文件,通常狀況fastcgi處理完一個php請求後會立刻釋放結束信號,等待下一個處理請求(固然也有程序假死,一直佔用資源的狀況)。打開nginx.conf,咱們看到下面這一行:nginx

location ~ .php {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        fastcgi_param  SCRIPT_FILENAME  d:/www/htdocs$fastcgi_script_name;
        include        fastcgi_params;
}

上面已經清楚地看到,全部使用php結尾的文件都通過fastcgi處理,而在php.ini的配置文件中也有一句:web

cgi.force_redirect = 1

代表,全部php程序安全地強制轉向交給cgi處理。sql

但在windows中,本地127.0.0.1:9000怎樣與php-cgi聯繫的呢?!答案是增長一個php-cgi進程,用它來監聽127.0.0.1:9000。經過控制器命令:windows

RunHiddenConsole.exe D:/www/php/php-cgi.exe  -b 127.0.0.1:9000 -c C:/WINDOWS/php.ini

咱們就能夠在啓動windows時,開啓一個php-cgi.exe進程監聽來自127.0.0.1:9000 的請求。在dos命令下打開netstat –a就能夠看到本地計算機下的9000端口處於listening狀態(也就是空置,若是沒有發送任何請求的話)。瀏覽器

好了,該說說在php中使用file_get_contents()、curl()、fopen()函數訪問localhost時爲何不能返回結果。咱們再來試驗在index.php中加入file_get_contents(‘http://127.0.0.1/phpinfo.php’) 語句向phpinfo.php發送一個請求,這時瀏覽器中的狀態指示一直在打轉,表示它一直在工做中。打開Dos中的netstat命令,能夠看到本地的9000端口的狀態爲:ESTABLISHED,表示該進程在聯機處理中。實際上,這裏咱們已經同時向nginx發送了兩個基於http的php請求,一個是解析index.php,而另外一個是phpinfo.php,這樣矛盾就出來了,由於咱們的windows系統只加載了一個http進程,所以,它沒法同時處理兩個php請求,它只能先處理第一個請求(index.php),而index.php卻又在等待phpinfo.php處理結果,phpinfo.php沒人幫它處理請求,由於它一直在等待index.php釋放結束信號,所以,形成了程序的阻塞狀態,陷入了死循環。因此咱們就看到了瀏覽器的狀態指示一直在打轉。Curl()與fopen函數的緣由也相同。安全

2、解決方法

找到了緣由,咱們也就有了解決辦法。網絡

一是,向系統增長一個http請求,當一個php-cig內要加載另外一個請求時,它可以分配其它http處理額外的php請求。這時需給另外一個http sever分配不一樣的端口,好比8080。nginx的案例以下:

http {  
    server {  
        listen          80;  
        server_name     127.0.0.1;  
        location / {  
            index index.php;  
            root  /web/www/htdocs;  
        }  
    }  
    server {  
        listen          8080;  
        server_name     127.0.0.1;  
        location / {  
            index index.html;  
            root  /web/www/htdocs;  
        }  
    }  
    include    /opt/nginx/conf/vhosts/php.conf;  
}

這樣,端口80與8080能夠分別處理不一樣的程序,好比:
test.php

echo file_get_contents('http://localhost:8080/phpinfo.php');

固然,在*unix下有更多選擇,好比fork。

另外提醒下,網上有人說,經過去掉地址中的http://協議標記,而使用相對地址就規避函數的檢查,實際狀況是否是這樣呢?!當在index.php中使用file_get_contents(‘phpinfo.php’); 時,咱們能夠看到函數輸出了phpinfo.php的源代碼,至關於file_get_contents(‘file:c:wwwphpinfo.php’); ,它實際上只是讀取你的文本內容,由於file_get_contents()函數首先是處理file協議的,而curl則直接報錯沒法解析。所以這些人純粹是不學無術的騙子。

還有人提出修改hosts文件,增長localhost www.xxx.com影射關係,函數經過www.xxx.com訪問本地php,這其實也是不治本的偏方,由於這只是方便計算機的dns解析,最終www.xxx.com交給127.0.0.1,然後者交給惟一http,仍是阻塞。

相關文章
相關標籤/搜索