2011-09-21 91 views
7

我在使用PHP的網站,我在哪裏的用戶正在幾分鐘後退出運行工作的問題(具體時間有所不同,但它是足夠頻繁是一個問題),不管是否他們一直在積極使用該網站。PHP會話過期早

困難的是,我不能重現這個問題,如果我登錄,使用相同的瀏覽器我沒有得到登出,這表明它是不是網站被徹底打破的情況下,同樣的用戶。不幸的是,我不能訪問用戶機器來運行任何流量嗅探軟件。

我已經檢查的事情是:

  • ,讓用戶在嘗試不同的瀏覽器。這似乎無法解決問題,因爲我無法指定客戶使用哪種瀏覽器,因此這不是一個長期解決方案。
  • 服務器時間正確,符合用戶機器。
  • 用戶Apache運行時具有寫入會話文件夾的權限,我可以看到正在創建的會話文件及其修改時間正在更新。
  • 沒有使用輸出緩衝功能。
  • 問題發生在各種頁面上,這些頁面似乎沒有任何共同之處(即不是它們都使用AJAX,或更新數據庫或其他原因)。
  • 用戶只從一臺機器上訪問他們的帳戶,即他們不這樣做一點工作,對他們的筆記本電腦,切換到桌面,然後不知道爲什麼他們已經退出對他們的筆記本電腦(我們不允許多個同時登錄同一用戶)。

PHP中的會話設置是Debian的默認設置,並且在.htaccess文件或其他任何地方都沒有更改過。主要的有:

session.cookie_lifetime 0 
session.gc_divisor 100 
session.gc_maxlifetime 1440 
session.gc_probability 0 
session.save_handler files 
session.save_path /var/lib/php5 
session.use_cookies On 

的Debian通過cron作業刪除而不是使用PHP的垃圾收集器,這就是爲什麼gc_probability設置爲0,我們正在運行的PHP版本的會議:PHP 5.2.6-1 + lenny13與Suhosin-Patch 0.9.6.2(cli)(Lenny的最新版本,我們將盡快升級到Squeeze,但我不認爲這是問題的原因)。

我們使用Zend_Session來管理會話,並在每個頁面上創建一次Zend_Session_Namespace的實例,從而自動調用在session_start()。會議由調用Zend_Session :: destroy()方法的退出頁面上清除,所以唯一的辦法用戶應該退出是:

  • 如果他們明確地點擊註銷鏈接(我們會記錄發生這種情況時,並沒有關係瀏覽器預取頁面並將用戶登錄出去似乎不是這種情況)。
  • 如果他們離開會話閒置超過24分鐘,此時的Debian可能會刪除他們的會話(有它運行每半小時刪除已未修改在24分鐘內的所有會話cron作業)。
  • 如果他們關閉瀏覽器,因爲他們的會話cookie的過期時間爲0將被刪除。

用於查看用戶是否登錄的檢查有:

  • 他們有一個有效的會話(通過看我們是否可以訪問$ zsession-檢查> USER_ID)。
  • 會話表中有一行具有匹配的用戶標識和會話標識,並且這是在不到一小時前更新的最後一次。我們在註銷時刪除此行,以便即使會話仍然存在於磁盤上,任何人都無需登錄即可訪問該帳戶。

任何人都可以推薦其他的東西,我可以嘗試嗎?

編輯:一些額外的東西根據意見,我已經試過離開:

  • 設置session.cookie_domain:這似乎是在PHP中有着很奇怪的行爲。如果我沒有設置此變量並將其保留爲「'(空字符串)的默認值,那麼www.domain.com的請求將生成www.domain.com的cookie。但是,如果我將cookie_domain設置爲'www.domain.com',則Cookie的域名爲'.www.domain.com'(注意前導點,這意味着對www.domain.com下方的所有內容均有效,例如subsite.www .domain.com)。
  • 設置session.cookie_lifetime:PHP似乎沒有更新每個請求的到期時間,所以如果我將cookie_lifetime設置爲3600,cookie將在用戶第一次訪問該站點後一小時過期,即使他們登錄並不斷使用它。

編輯2:基於其它東西的人都問:

  • 該網站是在數據中心託管,在一個單獨的VLAN。沒有人訪問該網站與該網站位於同一網絡上。
  • 沒有使用IP身份驗證,也沒有在會話過程的任何部分使用客戶端的IP地址(例如,我們不會將會話附加到IP地址,並在用戶的下一個請求來自不同的IP)。
+0

上次我有類似的問題,我錯過了在某個PHP文件中正確處理會話(所有其他文件都可以)。結果是,用戶試圖離開某個頁面後會話失效,因此他在不同類型的分鐘之後註銷,具體取決於他何時導航到頁面。不要將此視爲解決方案。把它看作是一個暗示,你可以找出一些錯誤。祝你好運! ^^ – Marco

+0

時區(或服務器時間錯誤)在某些情況下可能會導致問題。 – Smar

+1

@Smar它可以但我明確地說'服務器時間是正確的,符合用戶機器'。 – pwaring

回答

1

最後,得到的答覆是,只是取消會議,並寫它不同於會議在以下方面我自己很簡單的cookie代碼:在

  1. 存儲哈希(有點像會話ID)數據庫而不是文件。
  2. 將cookie設置爲從現在開始(每頁更新)3600秒後過期而不是0秒(後者似乎對IE用戶造成問題,儘管我無法複製它)。
  3. 僅當用戶登錄或登錄時才發送cookie標頭。

這不是一個理想的情況,因爲有一些重新發明輪子,但我的小解決方案似乎適用於PHP會話沒有的地方,並且有一個工作站點是最重要的。

0

您的網站在不同的域名?例如domain.com,www.domain.com,subdomain.domain.com?如果某些頁面被重定向到不同的域(www被認爲是不同的子域),當地址發生變化時會話將不起作用

編輯: 您必須重現問題。詢問你的客戶他們使用什麼樣的瀏覽器,他們做什麼動作,直到他們失去知覺,他們是否像你一樣查看網站的相同IP? (也就是說你們都在外部網絡中,或者都在與網站相同的網絡中)

當您設法找到問題時,請檢查請求/響應標頭,當它會話工作時,以及它不工作時然後進行比較。

+0

PHP實際上會爲所有子域設置會話cookie:'Set-Cookie \t PHPSESSID = 0a4ogbefeptfndukol3pjl7tg4;路徑= /;域= .thesite.com'。注意域名前面的點。 –

+0

實際上PHP並沒有爲所有子域設置會話cookie: Set-Cookie:PHPSESSID = 428d4be9caca21acc558c0510f22717b;路徑= /;安全 如果我在Firefox中查看cookie,它設置爲www.domain.com(我們將任何對domain.com的請求重定向到www.domain.com)。 – pwaring

+0

您使用的是哪個版本的PHP,因爲在我的上面的輸出是可見的? –

0

您的session.gc_maxlifetime設置爲1440毫秒,僅爲1.44秒。不應該是1440000毫秒= 24分鐘?

+1

'session.gc_maxlifetime'設置在幾秒鐘內。所以24小時1440是正確的。 – Marco

+1

你確定沒有其他腳本的會話壽命較短嗎?因爲具有最低生命週期的腳本得到執行。 –

+1

gc_maxlifetime是全局設置的,並且不會在任何PHP腳本中重寫。所有會話處理函數都在每個頁面上包含的一個文件中執行。 'session.cookie_lifetime'的 – pwaring

0

您可以嘗試將session.use_only_cookies設置爲值1並將session.cookie_lifetime設置爲1440秒的值。

+0

0表示瀏覽器在關閉窗口時刪除cookie,這對於會話cookie來說是理想的。 –

+1

確定它是理想的,但例如,如果您正在爲瀏覽器設置特定權限的Windows域控制器下工作,則不能保證該規則可行。我在域控制器下遇到了問題,即同一個會話中的一個彈出窗口銷燬了會話cookie。在明確設定生命期後,我可以解決這個問題。 – Marco

+0

我還沒有聽說過域控制器的問題,我想這可能是解決方案。我會嘗試一下,看看會發生什麼 - 儘管我不確定PHP是否會在每次加載頁面時更新會話cookie,因此即使用戶仍處於活動狀態,cookie仍有可能在24分鐘後過期。 – pwaring

3

的Debian通過cron作業,而不是使用PHP的垃圾收集器

這是非常奇怪的刪除會話 - 什麼是,在cron作業運行的代碼?

我們就註銷刪除此行

我建議你保持這個條件,比方說2天會話過期後/刪除(但其標記爲死的地步,你現在刪除它)。此外,開始在您的Web服務器日誌中記錄會話ID。

+0

這並不奇怪,Debian已經使用了這種方法多年。實際的代碼運行如下: 09,39 * * * * root [-x/usr/lib/php5/maxlifetime] && [-d/var/lib/php5] && find/var/lib/php5/-type f -cmin + $(/ usr/lib/php5/maxlifetime)-delete – pwaring

+0

並且你已經檢查過/ usr/lib/php5/maxlifetime輸出了什麼? – symcbean

+0

是的,它輸出24(這是我所期望的)。 cron作業肯定工作正常,只能刪除24分鐘內未訪問過的會話文件。 – pwaring

1

我想你指望改變

session.gc_maxlifetime 

我也面臨同樣的問題的值。我花了很多時間,然後問我的網絡服務提供商,當他獲得許可後,他改變了價格。現在它工作正常。

+0

它已經設置爲1440秒或24分鐘,但在此之前用戶正在註銷。 – pwaring

1

是否有其他的PHP應用程序在同一個系統上運行(例如在不同的虛擬主機下?)?他們是否也將會話保存在/ var/lib/php5中?

如果是這樣,並且其中一個應用程序的會話垃圾收集閾值較低,則它們會垃圾清理應用程序的會話文件。

我做了很多ZF開發,如果我使用的是基於文件系統的會話,我將它們粘貼在應用程序/數據/會話中而不是系統默認值中。

+0

系統上只有一個應用程序,除了幾個測試站點外,它們都具有相同的GC閾值。 – pwaring

0

最後,我選擇在每個頁面請求上發送一個Set-Cookie頭,類似於FlyBy在其中一條評論中提出的建議。相關的代碼/邏輯現在(假定在session_start()已經被調用):

$this->session_name = session_name(); 
$update_cookie = isset($_COOKIE[$this->session_name]); // Check if cookie already set, as PHP will send the first Set-Cookie when the session is started 
$this->logged_in = $this->checkSession(); // Function which checks whether a valid (i.e. not timed-out) session row exists in the DB 
if ($this->logged_in) { 
    $this->updateSession(); // Update the session row to the current time 

    if ($update_cookie) { 
    // Update the cookie expiry only if it existed before the login check 
    setcookie($this->session_name, $_COOKIE[$this->session_name], $this->time + 3600, '/'); 
    } 
} 

我不知道爲什麼這個工作,但我還沒有得到任何進一步的投訴和登錄的次數有所下降大幅度地(在相同的用戶幾分鐘內不再有幾次登錄日誌)。

但是,我可能會在某些時候重寫代碼,以便在客戶端上使用數據庫行和cookie,因爲PHP中的會話功能有很多變量,所以很難找出導致問題的原因,並且會話cookie處理與處理正常cookie的方式略有不同。特別是,你必須小心使用setcookie函數,因爲由PHP啓動的會話cookie的默認路徑是'/',但是setcookie的默認路徑是當前目錄路徑,這些路徑不一定是相同的。

+0

報廢,顯然問題仍在發生,我完全沒有想法。 – pwaring