我需要將服務器端創建的檔案發送tmpfile()到瀏覽器。
我正在使用兩個不同的 Docker 容器:php和nginx(docker compose)。
我的 nginx 配置(Docker 容器nginx):
server {
listen 80 default_server;
index index.php index.html index.htm;
root /app;
location ~ [^/]\.php(/|$) {
autoindex on;
autoindex_exact_size on;
try_files $uri =404;
fastcgi_split_path_info ^(. \.php)(/. )$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
error_log stderr warn;
access_log /dev/stdout main;
}
我的 PHP 代碼(Docker 容器php):
<?php
$file = tmpfile();
fwrite($file, "hello world");
$metaData = stream_get_meta_data($file);
$fileName = $metaData['uri'];
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header('Content-type: text/plain');
header('Content-Length: ' . filesize($fileName));
header('X-Sendfile: ' . $fileName);
fclose($file);
但是瀏覽器只得到一個空頁面而不是下載彈出視窗。
uj5u.com熱心網友回復:
好的,讓我們從頭開始。
很明顯,nginx 需要直接訪問將通過
X-Accel-Redirectheader 提供的檔案。nginx這意味著您將需要在您的容器和容器之間建立某種共享卷php。通常這不是問題(例如,請參閱如何在 Docker 容器之間共享資料一文)。但是tmpfile()會在臨時目錄(或類似的目錄)中創建一個臨時檔案/tmp并使其成為容器之間的共享卷可能非常棘手。即使您設法解決了前一部分,在該
fclose($file);行之后臨時檔案也將被關閉并洗掉。這就是為什么嘗試使用tmpfile()andX-Accel-Redirect一起是一個壞主意的主要部分。好吧,您可以嘗試重繪 輸出緩沖區并等待一段時間,讓 nginx 有機會在腳本關閉并洗掉檔案之前讀取檔案,但我不確定它是否能正常作業,也不能似乎也是一個很好的解決方案。
你能做些什么呢?
首先,你根本不需要堅持X-Accel-Redirect。當您想使用 nginx 提供已存在的檔案時,它可以為您帶來顯著的性能優勢。但是您將首先創建該檔案,使用 PHP 將一些資料寫入磁盤,然后使用 nginx 從磁盤讀取它。您可以簡單地將該資料直接寫入STDOUT.
這種方法的缺點是您事先不知道資料量,并且無法設定正確的Content-Length標頭以使您的資料通過分塊編碼的 HTTP 流提供服務。如果您不想那樣做,您可以使用輸出緩沖ob_...功能。使用 開始緩沖ob_start(),然后在將所有資料寫入緩沖區后,使用ob_get_contents()獲取其內容并ob_get_length()獲取資料大小,然后使用 關閉輸出緩沖區ob_end_clean()。現在,您將能夠Content-Length在將資料發送到之前正確設定標頭STDOUT(或者如果出現問題,則回傳正確的錯誤代碼)。
作為最后的手段,如果您仍然想完全使用tmpfile()它,您可以在使用該功能STDOUT關閉/洗掉它之前將其內容輸出到。readfile()
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/428582.html
