2011-09-21 37 views
7

Tôi gặp sự cố với trang web PHP mà tôi đang chạy tại nơi mà người dùng bị đăng xuất sau vài phút (thời gian chính xác thay đổi, nhưng thường xuyên xảy ra sự cố), bất kể họ đã tích cực sử dụng trang web hay không.Phiên PHP hết hạn sớm

Khó khăn là tôi không thể tái tạo vấn đề này, nếu tôi đăng nhập với cùng người dùng bằng cùng một trình duyệt, tôi không bị đăng xuất, điều này cho thấy đây không phải là trường hợp trang web bị hỏng hoàn toàn. Rất tiếc, tôi không có quyền truy cập vào các máy của người dùng để chạy bất kỳ phần mềm quét tìm lưu lượng truy cập nào.

Những điều tôi đã kiểm tra là:

  • Yêu cầu người dùng thử trình duyệt khác nhau. Điều này dường như không giải quyết được vấn đề và không phải là giải pháp dài hạn vì tôi không thể quyết định trình duyệt nào khách hàng sẽ sử dụng.
  • Thời gian của máy chủ là chính xác và phù hợp với các máy người dùng.
  • Người dùng Apache chạy khi có quyền ghi vào thư mục phiên và tôi có thể thấy các tệp phiên được tạo và thời gian sửa đổi của họ đang được cập nhật.
  • Không có chức năng đệm đầu ra nào đang được sử dụng.
  • Sự cố xảy ra trên nhiều trang dường như không có điểm chung (nghĩa là không phải tất cả đều sử dụng AJAX hoặc cập nhật cơ sở dữ liệu hoặc một số lý do khác).
  • Người dùng chỉ truy cập tài khoản của họ từ một máy, nghĩa là họ không thực hiện một chút công việc trên máy tính xách tay của họ, chuyển sang màn hình nền và sau đó tự hỏi tại sao họ đăng xuất trên máy tính xách tay của họ đăng nhập đồng thời cho cùng một người dùng).

Cài đặt phiên trong PHP là mặc định của Debian và chưa được thay đổi trong tệp .htaccess hoặc bất kỳ nơi nào khác. Những người chính là:

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 xóa phiên thông qua một công việc định kỳ thay vì sử dụng thu gom rác của PHP, đó là lý do gc_probability được thiết lập để 0. Phiên bản PHP chúng tôi đang chạy là: PHP 5.2.6-1 + lenny13 với Suhosin-Patch 0.9.6.2 (cli) (phiên bản mới nhất trong Lenny, chúng tôi sẽ nâng cấp lên Squeeze sớm nhưng tôi không nghĩ đó là nguyên nhân của vấn đề).

Chúng tôi sử dụng Zend_Session để quản lý phiên, và một thể hiện của Zend_Session_Namespace được tạo ra một lần trên mỗi trang, do đó tự động gọi session_start(). Các phiên bị xóa bằng cách gọi Zend_Session :: destroy() trên trang đăng xuất, do đó, cách duy nhất để người dùng đăng xuất là:

  • Nếu họ nhấp vào liên kết đăng xuất một cách rõ ràng (chúng tôi đăng nhập khi điều này xảy ra và nó không dường như không phải là trường hợp duyệt web đang tìm nạp trước trang và do đó đăng xuất người dùng ra).
  • Nếu họ rời phiên không hoạt động trong hơn 24 phút, tại thời điểm đó Debian có thể xóa phiên của họ (có một công việc định kỳ chạy mỗi nửa giờ xóa tất cả các phiên không được sửa đổi trong hơn 24 phút).
  • Nếu họ đóng trình duyệt, vì cookie phiên của họ với thời gian hết hạn là 0 sẽ bị xóa.

Các kiểm tra cho thấy cho dù một người dùng đang đăng nhập là:

  • Họ có một phiên hợp lệ (kiểm tra bằng cách nhìn thấy cho dù chúng ta có thể truy cập $ zsession-> user_id).
  • Có một hàng trong bảng phiên có ID người dùng và ID phiên phù hợp và cập nhật này được cập nhật lần cuối chưa đầy một giờ trước. Chúng tôi xóa hàng này khi đăng xuất để ngay cả khi phiên đó vẫn tồn tại trên đĩa, không ai có thể truy cập tài khoản đó mà không cần đăng nhập.

Có thể đề xuất những điều khác mà tôi có thể thử không?

Edit: Một số điều bổ sung Tôi đã cố gắng dựa trên ý kiến ​​trái:

  • Thiết session.cookie_domain: Đây dường như có hành vi rất kỳ quặc trong PHP. Nếu tôi không đặt biến này và để mặc định là '' (chuỗi rỗng), thì yêu cầu cho www.domain.com sẽ tạo ra một cookie của www.domain.com. Tuy nhiên, nếu tôi đặt cookie_domain thành 'www.domain.com', tên miền cho cookie là '.www.domain.com' (dấu chấm đầu thông báo, có nghĩa là hợp lệ cho mọi thứ bên dưới www.domain.com, ví dụ: subsite.www .domain.com).
  • Đặt session.cookie_lifetime: PHP dường như không cập nhật thời gian hết hạn trên mỗi yêu cầu, vì vậy nếu tôi đặt cookie_lifetime thành 3600, cookie sẽ hết hạn sau một giờ sau khi người dùng truy cập trang web lần đầu tiên, ngay cả khi họ đăng nhập và sử dụng liên tục .

Chỉnh sửa 2: Dựa vào những thứ khác người đã hỏi: trang web

  • được lưu trữ trong một trung tâm dữ liệu, trên một VLAN riêng biệt. Không ai truy cập trang web trên cùng một mạng với trang web.
  • Không có xác thực IP được sử dụng, cũng không phải là địa chỉ IP của ứng dụng được sử dụng trong bất kỳ phần nào của quá trình phiên (ví dụ: chúng tôi không đính kèm phiên vào địa chỉ IP và chặn người dùng nếu yêu cầu tiếp theo của họ đến từ IP khác nhau).
+0

Lần cuối cùng tôi gặp sự cố tương tự, tôi đã bỏ lỡ các phiên chính xác trong một tệp php nhất định (tất cả các tệp khác đều ổn). Kết quả là phiên đã trở thành không hợp lệ sau khi người dùng cố gắng rời khỏi trang nhất định đó để anh ấy đã đăng xuất sau các loại phút khác nhau tùy thuộc vào thời điểm anh ấy điều hướng đến trang. Đừng xem đây là giải pháp. Xem nó như là một gợi ý, nơi bạn có thể tìm một số sai lầm. Chúc may mắn! ^^ – Marco

+0

Các múi giờ (hoặc thời gian máy chủ sai) có thể gây ra sự cố trong một số trường hợp. – Smar

+1

@Smar Nó có thể nhưng tôi đã nói rõ ràng 'Thời gian máy chủ là chính xác và phù hợp với máy người dùng'. – pwaring

Trả lời

1

Cuối cùng, câu trả lời là chỉ cần bỏ phiên và viết mã của riêng tôi rất đơn giản Cookie mà khác với các phiên trong các cách sau:

  1. Stores một hash (hơi giống một session ID) trong cơ sở dữ liệu thay vì trong tệp.
  2. Đặt cookie hết hạn sau 3600 giây từ bây giờ (cập nhật trên mỗi trang) thay vì 0 giây (sau này dường như gây ra sự cố cho người dùng IE, mặc dù tôi không bao giờ có thể sao chép lại).
  3. Chỉ gửi tiêu đề cookie khi người dùng đăng nhập hoặc đăng nhập.

Nó không phải là một tình huống lý tưởng vì có một số phát minh lại bánh xe đang diễn ra, nhưng giải pháp nhỏ của tôi dường như hoạt động khi phiên PHP không hoạt động và việc làm là điều quan trọng nhất.

0

là trang web của bạn trên các tên miền khác nhau? ví dụ domain.com, www.domain.com, subdomain.domain.com? nếu một số trang được chuyển hướng đến một miền khác (www được coi là tên miền phụ khác) so với phiên sẽ không hoạt động khi địa chỉ thay đổi

EDIT: Bạn phải tạo lại sự cố. Yêu cầu khách hàng của bạn sử dụng loại trình duyệt nào, họ sẽ làm gì cho đến khi họ đăng xuất, họ có xem cùng một địa chỉ IP cho trang web như bạn không? (nghĩa là bạn đang ở cả mạng bên ngoài hoặc cả hai trong cùng một mạng với trang web)

Khi bạn quản lý để tìm sự cố, hãy kiểm tra tiêu đề yêu cầu/phản hồi khi phiên hoạt động và khi nó không hoạt động và sau đó so sánh.

+0

PHP thực sự sẽ đặt cookie phiên cho tất cả các tên miền phụ: 'Set-Cookie \t PHPSESSID = 0a4ogbefeptfndukol3pjl7tg4; path = /; domain = .thesite.com'. Lưu ý dấu chấm ở phía trước tên miền. –

+0

Thực ra PHP không đặt cookie phiên cho tất cả tên miền phụ: Đặt cookie: PHPSESSID = 428d4be9caca21acc558c0510f22717b; path = /; an toàn Nếu tôi xem cookie trong Firefox, nó được đặt cho www.domain.com (chúng tôi chuyển hướng mọi yêu cầu cho domain.com đến www.domain.com). – pwaring

+0

Bạn đang sử dụng phiên bản PHP nào vì trong đầu ra ở trên có thể nhìn thấy được? –

0

phiên của bạn.gc_maxlifetime được đặt thành 1440 mili giây chỉ là 1,44 giây. không nên là 1440000 ms = 24 phút?

+1

'session.gc_maxlifetime' được đặt theo giây. Vì vậy, 1440 trong 24 phút là chính xác. – Marco

+1

bạn có chắc chắn không có tập lệnh nào khác có thời lượng phiên thấp hơn không? bởi vì kịch bản có tuổi thọ thấp nhất được thực hiện. –

+1

gc_maxlifetime được đặt trên toàn cầu và không bị ghi đè trong bất kỳ tập lệnh PHP nào. Tất cả các chức năng xử lý phiên được thực hiện trong một tập tin được bao gồm trên mỗi trang. – pwaring

0

Bạn có thể thử đặt session.use_only_cookies thành giá trị 1 và session.cookie_lifetime thành giá trị 1440 giây.

+0

cho 'session.cookie_lifetime' 0 có nghĩa là trình duyệt xóa cookie khi cửa sổ bị đóng cho cookie phiên là lý tưởng. –

+1

Chắc chắn nó là lý tưởng, nhưng ví dụ nếu bạn đang làm việc dưới một bộ điều khiển miền cửa sổ đặt quyền cụ thể cho trình duyệt, quy tắc không được đảm bảo để hoạt động. Tôi đã có vấn đề dưới một bộ điều khiển tên miền mà một cửa sổ popup trong cùng một phiên bị phá hủy cookie phiên. Sau khi tôi đặt cuộc đời một cách rõ ràng, tôi có thể giải quyết vấn đề này. – Marco

+0

Tôi chưa nghe nói về vấn đề điều khiển miền đó, tôi đoán đó có thể là giải pháp. Tôi sẽ thử và xem điều gì xảy ra - mặc dù tôi không chắc liệu PHP cập nhật cookie phiên trên mỗi lần tải trang sao cho có nguy cơ rằng cookie có thể hết hạn sau 24 phút ngay cả khi người dùng vẫn hoạt động. – pwaring

3

Debian xóa phiên thông qua một công việc định kỳ thay vì sử dụng thu gom rác của PHP

Đó là rất kỳ quặc - và mã chạy trong công việc định kỳ là gì?

Chúng tôi xóa hàng này trên logout

tôi đề nghị bạn giữ lại để, nói rằng, 2 ngày sau khi phiên giao dịch đã hết hạn/bị xóa (nhưng cờ nó như chết tại điểm mà bạn đang xóa nó). Ngoài ra, hãy bắt đầu ghi nhật ký id phiên trong nhật ký máy chủ web của bạn.

+0

Nó không phải là đặc biệt kỳ lạ, Debian đã sử dụng phương pháp đó trong nhiều năm. Việc chạy mã thực tế là: 09,39 * * * * gốc [-x/usr/lib/php5/maxlifetime] && [-d/var/lib/php5] && tìm/var/lib/php5/-type f -cmin + $ (/ usr/lib/php5/maxlifetime) -delete – pwaring

+0

và bạn đã kiểm tra kết quả đầu ra/usr/lib/php5/maxlifetime? – symcbean

+0

Có, nó xuất 24 (đó là những gì tôi mong đợi). Công việc cron chắc chắn hoạt động chính xác và chỉ xóa các tập tin phiên mà không được truy cập trong 24 phút. – pwaring

1

Tôi nghĩ rằng bạn đếm thay đổi giá trị của

session.gc_maxlifetime 

Tôi cũng phải đối mặt với cùng một vấn đề. Tôi đã dành rất nhiều thời gian vào nó sau đó tôi yêu cầu nhà cung cấp dịch vụ web của tôi và khi ông được sự cho phép, ông đã thay đổi câu chuyện đó. Bây giờ nó hoạt động tốt.

+0

Nó đã được đặt thành 1440 giây hoặc 24 phút nhưng người dùng sẽ bị đăng xuất tốt trước đó. – pwaring

1

Có các ứng dụng php khác chạy trên cùng một hệ thống (ví dụ: trong các máy chủ khác nhau không?)? Họ cũng đang lưu các phiên trong/var/lib/php5?

Nếu có, và một trong các ứng dụng đó có ngưỡng thu gom rác trong phiên thấp, chúng sẽ làm hỏng các tệp phiên của ứng dụng của bạn.

Tôi làm rất nhiều việc phát triển ZF, và nếu tôi đang sử dụng các phiên dựa trên hệ thống tập tin, tôi dán chúng vào ứng dụng/dữ liệu/phiên thay vì mặc định của hệ thống.

+0

Chỉ có một ứng dụng trên hệ thống, ngoài một vài trang thử nghiệm nhưng tất cả đều có cùng ngưỡng GC. – pwaring

0

Cuối cùng, tôi đã chọn gửi tiêu đề Set-Cookie trên mọi yêu cầu trang, tương tự như những gì FlyBy đề xuất trong một trong các nhận xét. Mã liên quan/logic bây giờ (giả sử session_start() đã được gọi là):

$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, '/'); 
    } 
} 

Tôi không chắc tại sao điều này làm việc, nhưng tôi đã không có bất kỳ khiếu nại tiếp theo và số lượng thông tin đăng nhập đã giảm mạnh (không còn có một số thông tin đăng nhập trong nhật ký cho cùng một người dùng trong vòng vài phút của nhau). Tuy nhiên, tôi có lẽ sẽ viết lại mã tại một số điểm để chỉ sử dụng hàng cơ sở dữ liệu và cookie trên máy khách, vì chức năng phiên trong PHP có quá nhiều biến rất khó để tìm ra nguyên nhân gây ra sự cố và việc xử lý cookie phiên là hơi khác với cách xử lý cookie bình thường. Cụ thể, bạn phải cẩn thận với hàm setcookie, bởi vì đường dẫn mặc định cho cookie phiên được PHP bắt đầu là '/', nhưng mặc định cho setcookie là đường dẫn thư mục hiện tại, và chúng không nhất thiết phải giống nhau.

+0

Phế liệu, dường như vấn đề vẫn đang xảy ra và tôi đã hoàn toàn hết ý tưởng. – pwaring

Các vấn đề liên quan