2013-03-08 103 views
3

在我的PHP代碼中,我打開一個文件並向其中添加文本。我使用以下代碼:什麼時候fopen失敗?

$ourFileHandle = fopen($ourFileName, 'a') or die("can't open file"); 

這發生在PHP頁面加載時。現在如果兩個人同時加載PHP頁面會發生什麼?此代碼是否適用於其中一個人,對於其他人,它是否會執行die()?一般來說,什麼時候可以fopen失敗?

謝謝。

+0

這將無法按預期工作,除非您鎖定該文件,這會損害併發性。無論你在做什麼,幾乎肯定會用數據庫做得更好。 – DaveRandom 2013-03-08 23:37:36

回答

6

TL; DR - 只是使用數據庫

這不是一個簡單的主題。你所做的一定不會像多個併發請求那樣工作,因爲大多數系統將允許所有請求打開文件,並且可能有多個腳本可以同時寫入文件,最終可能會導致如果你這樣做了文件中的垃圾。

可能的解決方法有很多種不同的方法,但我會在這裏介紹三種我認爲最可行的方法。

  1. 使用數據庫。無論你想要做什麼,這幾乎都是最好的解決方案。一個RDBMS將處理所有這些併發問題而不會跳過一個節拍,如果你這樣做,你將永遠不會遇到任何併發問題。

  2. 使用flock()要求文件的獨佔鎖定。此功能使用建議鎖定來防止多個併發進程同時訪問該文件。這將適合您多個PHP進程的需求,但如果它們不支持PHP使用的相同類型的建議鎖定系統,則可能無法與其他外部程序一起使用。
    flock()「塊」,直到在文件上獲取鎖定。這意味着它會損害請求併發 - 只有一個請求可以一次寫入文件。此外,它並不保證會按請求的順序提供鎖,因此最終可能會導致一個請求永遠不會獲得對文件的鎖定,而其他稍後到達的請求將得到滿足。

  3. 使用後臺進程來處理文件訪問,並讓腳本與進程進行通信。這有點像滾動你自己的版本1),它不適用於心靈的懦弱,但是如果正確完成,它可以被用來產生很好的效果。
    使用此模型,人們使用某種形式的進程間通信將需要寫入文件的數據轉發到後臺(持久)進程。這個後臺進程管理對文件的寫入,確保消息按照正確的順序完整寫入。通常(使用PHP時)這樣的IPC將通過套接字來實現。這不是微不足道的,但可能是最強大的解決方案。


從一個更一般的點,通常fopen()失敗,因爲權限問題或低級別的操作系統問題。操作系統也可以提供一個「真正的」鎖定機制,以防止其他程序打開文件。然而,真正的「原因列表fopen()可能會失敗」很難提供,因爲有這麼多的可能性。

顯然,如果您嘗試以讀取模式打開文件並且文件不存在,則會失敗。但是,上面的代碼是以寫入模式打開文件 - 如果文件不存在,則不會必然失敗 - 如果目錄路徑存在並且調用進程有權寫入該目錄,則會創建該文件。

2

fopen會失敗,主要是因爲這些原因:

  • 文件不存在
  • 文件權限不允許該文件打開(書面方式,閱讀,exexuting等)
  • 文件用於另一個進程(即第三方應用程序)
  • 文件正被另一個PHP腳本/資產鎖定
+0

1)不相關,'a'模式將創建文件2)足夠公平3)和4)是相同的點並且不相關,因爲他沒有試圖獲取文件上的鎖。 – DaveRandom 2013-03-08 23:39:04

+2

@DaveRandom請「加上我的答案」,因爲他問:「一般來說,什麼時候可以打開失敗?':)這些都是fopen可能會失敗的原因和影響。 :)歡呼 – 2013-03-08 23:40:20

+0

@ ZlatanO。 +1;)我錯了 – hek2mgl 2013-03-08 23:43:00

1

fopen可能會失敗,如果您沒有權限或有其他低級別的問題,多次是沒有問題的,但同時寫入它可能會導致'條紋',所以使用(阻止)flock