2015-06-25 35 views
1

我使用webkithtmltopdf生成PDF &要覆蓋所有現有文件進行更新。調試文件不被原子(可能PDF.js瀏覽器的問題)

我不能確定這是否保證了原子更新,或者我們會使用不同的PDF工具有一天,所以我一直在使用一個臨時文件中的一些PHP代碼,它包裹。一旦臨時文件被創建,我使用PHP的rename()函數來覆蓋實際的文件。

我已經確保臨時文件&輸出文件存在於同一個分區上,但是當我運行我的腳本時,如果我請求PDF時,有時會從瀏覽器中獲得「PDF文件無法顯示」類型的消息它被覆蓋的確切時刻。

我怎麼能嘗試調試呢?我在Apache錯誤日誌中沒有看到任何錯誤。我在訪問日誌中看到「200」和「206」請求。我不確定我在Content-Length上尋找什麼,或者pdf.js如何與服務器一起工作。

代碼如下所示:

$output = sprintf(__DIR__."/pdfs/%s.pdf", $id); 
$tmpOutput = $output . '.tmp'; 
$cmd = 'wkhtmltopdf '. escapeshellarg($url) . ' ' . escapeshellarg($tmpOutput); 

exec($cmd); 
chmod($tmpOutput, 0777); 
rename($tmpOutput, $output); 
chmod($output, 0777); 

其值得一提的,我用chmod要解決我的Gearman的工人,由主管運行,這是由根部開始運行這一事實。如果這是一個權限問題,我希望在Apache錯誤日誌中有一個錯誤,但不是 - 我也希望有一個403狀態代碼或類似的東西,但我在日誌中看到的是200或206 。

+1

原子?這是什麼意思,像原子和東西? – meda

+1

@meda喜歡改變的變量,而不其他線程改變它 –

+0

原子意味着,在任何時候,任何進程讀取路徑應該得到一個完全成型的PDF文件。由於在更新它的確切時刻讀取它,它不應該得到空白或部分文件。它可以獲取舊文件或新文件。 –

回答

0

大多數的PDF閱讀器從淨以塊的形式讀取的PDF文件,使用Range頭,這意味着在多個HTTP請求(指定哪個字節範圍從它想要的文件,例如1000-5000,所以字節計數4000)。 Web服務器回覆HTTP 206 Partial Content響應代碼。如果您在這些部分請求之間更改PDF文件,PDF閱讀器將收到損壞的文件(部分來自舊文件,部分來自新文件)。

HTTP協議應防止它 - 如果該文件中改變關於第一請求的PDF閱讀器也應接收ETAg頭,這是獨特的和變化。在隨後的請求中,PDF閱讀器應該發送If-Match標題,以便Web服務器可以通知它該文件是否仍然相同。但有時這不起作用。您可以禁用這個Apache配置中Range請求(或.htaccess文件):

<Files *.pdf> 
    Header set Accept-Ranges none 
</Files> 

另外,還要確保您的臨時文件始終是唯一的,所以沒有2個PHP程序將在同一寫入相同的臨時文件名時間。