關於Nginx安裝PHP的fileinfo和xsendfile模組的一些事宜

天府雲創發表於2018-10-18

Fileinfo作用:本模組中的函式通過在檔案的給定位置查詢特定的 魔術 位元組序列 來猜測檔案的內容型別以及編碼(通俗來講就是獲取檔案的MIME資訊)也可以幫助系統顯示圖片。

根據手冊的介紹fileinfo擴充套件從php5.3之後預設是開啟的,所以不需要我們單獨安裝。但是有的整合環境為了編譯php的時候提高速度或者節省資源就去掉了這個擴充套件的安裝。所以就需要我們自己動手來安裝了。

首先檢查系統是否已經安裝  或者直接執行 find / -name fileinfo

  1. [root@shengwei ~]# php -i|grep fileinfo   
  2. Configure Command =>  './configure'  '--prefix=/alidata/server/php' '--enable-opcache' '--with-config-file-path=/alidata/server/php/etc' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pdo-mysql=mysqlnd' '--enable-fpm' '--enable-fastcgi' '--enable-static' '--enable-inline-optimization' '--enable-sockets' '--enable-wddx' '--enable-zip' '--enable-calendar' '--enable-bcmath' '--enable-soap' '--with-zlib' '--with-iconv' '--with-gd' '--with-xmlrpc' '--enable-mbstring' '--without-sqlite' '--with-curl' '--enable-ftp' '--with-mcrypt' '--with-freetype-dir=/usr/local/freetype.2.1.10' '--with-jpeg-dir=/usr/local/jpeg.6' '--with-png-dir=/usr/local/libpng.1.2.50' '--disable-ipv6' '--disable-debug' '--with-openssl' '--disable-maintainer-zts' '--disable-safe-mode' '--disable-fileinfo'  
  3. fileinfo  
  4. fileinfo support => enabled  


如果出現上面說明已經安裝

fileinfo已整合至php專案原始碼內(https://pecl.php.net/package/Fileinfo)

php原始碼包下載地址:http://cn2.php.net

tar -zxvf php-7.1.0.tar.gz

cd php-7.1.0/ext/fileinfo

當前目錄執行 /usr/local/php/bin/phpize

如果執行成功,會有類似下面的資訊
Configuring for:
PHP Api Version:         20151012
Zend Module Api No:      20151012
Zend Extension Api No:   320151012

執行configure配置

./configure --with-php-config=/usr/local/php/bin/php-config --enable-fileinfo

  如果提示php-config命令不存在 configure: error: Cannot find php-config. Please use --with-php-config=PATH

  

  可以執行yum install php-devel, 安裝php-devel,安裝完成之後再執行這條命令即可。

編譯安裝

make && make install

如果安裝成功,會有類似下面的資訊

Installing shared extensions:     /usr/local/php/lib/php/extensions/no-debug-non-zts-20151012/

修改php.ini配置項

echo 'extension="fileinfo.so"' >> /usr/local/php/etc/php.ini

重啟php服務

service php-fpm restart

php -i | grep fileinfo

......

fileinfo

fileinfo support => enabled

在nginx中x-sendfile解決方案

很多時候使用者需要從網站下載檔案,如果檔案是可以通過一個固定連結公開獲取的,那麼我們只需將檔案存放到 webroot下的目錄裡就好。但大多數情況下,我們需要做許可權控制,例如下載 PDF 賬單,又例如下載網盤裡的檔案。這時,我們通常藉助於指令碼程式碼來實現,而這無疑會增加伺服器的負擔。

例如下面的程式碼:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

<?php

  // 使用者身份認證,若驗證失敗跳轉

  authenticate();

  // 獲取需要下載的檔案,若檔案不存在跳轉

  $file= determine_file();

  // 讀取檔案內容

  $content=file_get_contents($file);

  // 傳送合適的 HTTP 頭

  header("Content-type: application/octet-stream");

  header('Content-Disposition: attachment; filename="'basename($file) .'"');

  header("Content-Length: ".filesize($file));

  echo$content// 或者 readfile($file);

?>

一、這樣做有什麼問題?

這樣做意味著我們的程式需要將檔案內容從磁碟經過一個固定的 buffer 去迴圈讀取到記憶體,再傳送給前端 web 伺服器,最後才到達使用者。當需要下載的檔案很大的時候,這種方式將消耗大量記憶體,甚至引發 php 程式超時或崩潰。Cache 也很頭疼,更不用說中斷重連的情況了。
一個理想的解決方式應該是,由 php 程式進行許可權檢查等邏輯判斷,一切通過後,讓前臺的 web 伺服器直接將檔案傳送給使用者——像 Nginx 這樣的前臺更善於處理靜態檔案。這樣一來 php 指令碼就不會被 I/O 阻塞了。

二、什麼是 X-Sendfile?

X-Sendfile 是一種將檔案下載請求由後端應用轉交給前端 web 伺服器處理的機制,它可以消除後端程式既要讀檔案又要處理髮送的壓力,從而顯著提高伺服器效率,特別是處理大檔案下載的情形下。

X-Sendfile 通過一個特定的 HTTP header 來實現:在 X-Sendfile 頭中指定一個檔案的地址來通告前端 web 伺服器。當 web 伺服器檢測到後端傳送的這個 header 後,它將忽略後端的其他輸出,而使用自身的元件(包括 快取頭 和 斷點重連 等優化)機制將檔案傳送給使用者。

不過,在使用 X-Sendfile 之前,我們必須明白這並不是一個標準特性,在預設情況下它是被大多數 web 伺服器禁用的。而不同的 web 伺服器的實現也不一樣,包括規定了不同的 X-Sendfile 頭格式。如果配置失當,使用者可能下載到 0 位元組的檔案。

使用 X-Sendfile 將允許下載非 web 目錄中的檔案(例如/root/),即使檔案在 .htaccess 保護下禁止訪問,也會被下載。

不同的 web 伺服器實現了不同的 HTTP 頭 

SENDFILE 頭 使用的 WEB 器
X-Sendfile Apache, Lighttpd v1.5, Cherokee
X-LIGHTTPD-send-file Lighttpd v1.4
X-Accel-Redirect Nginx, Cherokee

使用 X-SendFile 的缺點是你失去了對檔案傳輸機制的控制。例如如果你希望在完成檔案下載後執行某些操作,比如只允許使用者下載檔案一次,這個 X-Sendfile 是沒法做到的,因為後臺的 php 指令碼並不知道下載是否成功。

三、怎樣使用?

Apache 請參考mod_xsendfile模組。下面我介紹 Nginx 的用法。

Nginx 預設支援該特性,不需要載入額外的模組。只是實現有些不同,需要傳送的 HTTP 頭為 X-Accel-Redirect。另外,需要在配置檔案中做以下設定

?

1

2

3

4

location /protected/ {

 internal;

 root  /some/path;

}

internal表示這個路徑只能在 Nginx 內部訪問,不能用瀏覽器直接訪問防止未授權的下載。


於是 PHP 傳送 X-Accel-Redirect 給 Nginx:

?

1

2

3

4

5

6

7

]<?php

  $filePath'/protected/iso.img';

  header('Content-type: application/octet-stream');

  header('Content-Disposition: attachment; filename="'basename($file) .'"');

  //讓Xsendfile傳送檔案

  header('X-Accel-Redirect: '.$filePath);

?>

這樣使用者就會下載到 /some/path/protected/iso.img 這個路徑下的檔案。
如果你想傳送的是 /some/path/iso.img 檔案,那麼 Nginx 配置應該是

?

1

2

3

4

location /protected/ {

 internal;

 alias  /some/path/; # 注意最後的斜槓

}

相關文章