Làm cách nào để thay đổi thời gian chờ phiên trong PHP?


154

Tôi muốn kéo dài thời gian chờ phiên trong php

Tôi biết rằng có thể làm như vậy bằng cách sửa đổi tệp php.ini. Nhưng tôi không có quyền truy cập vào nó.

Vì vậy, nó có thể làm điều đó chỉ với mã php?



1
Liên quan, đây là trong php.ini, nhưng tôi nghĩ bạn có thể sử dụng ini_set như @matino đã nói stackoverflow.com/questions/520237/ trên
J-Rou

Câu trả lời:


324

Thời gian chờ phiên là một khái niệm phải được thực hiện trong mã nếu bạn muốn đảm bảo nghiêm ngặt; đó là cách duy nhất bạn có thể hoàn toàn chắc chắn rằng sẽ không có phiên nào tồn tại sau X phút không hoạt động.

Nếu thư giãn yêu cầu này một chút có thể chấp nhận được và bạn ổn với việc đặt giới hạn dưới thay vì giới hạn nghiêm ngặt về thời lượng, bạn có thể thực hiện dễ dàng và không cần viết logic tùy chỉnh.

Thuận tiện trong môi trường thoải mái: làm thế nào và tại sao

Nếu phiên của bạn được triển khai bằng cookie (có thể là chúng) và nếu máy khách không độc hại, bạn có thể đặt giới hạn trên về thời lượng phiên bằng cách điều chỉnh một số tham số nhất định. Nếu bạn đang sử dụng xử lý phiên mặc định của PHP bằng cookie, cài đặt session.gc_maxlifetimecùng với session_set_cookie_paramssẽ hoạt động cho bạn như thế này:

// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);

// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);

session_start(); // ready to go!

Điều này hoạt động bằng cách định cấu hình máy chủ để giữ dữ liệu phiên trong ít nhất một giờ không hoạt động và hướng dẫn khách hàng của bạn rằng họ nên "quên" id phiên của họ sau cùng khoảng thời gian. Cả hai bước này đều được yêu cầu để đạt được kết quả mong đợi.

  • Nếu bạn không bảo khách hàng quên id phiên của họ sau một giờ (hoặc nếu khách hàng độc hại và chọn bỏ qua hướng dẫn của bạn) thì họ sẽ tiếp tục sử dụng cùng một id phiên và thời lượng hiệu lực của nó sẽ không mang tính quyết định. Đó là bởi vì các phiên đã hết hạn sử dụng ở phía máy chủ không được thu gom rác ngay lập tức mà chỉ bất cứ khi nào phiên GC bắt đầu .

    GC là một quá trình có khả năng tốn kém, do đó, xác suất thường khá nhỏ hoặc thậm chí bằng không (một trang web nhận được số lượt truy cập khổng lồ có thể sẽ hoàn toàn từ bỏ xác suất GC và lên lịch để nó diễn ra trong nền sau mỗi X phút). Trong cả hai trường hợp (giả sử khách hàng không hợp tác), giới hạn dưới của vòng đời phiên hiệu quả sẽ là session.gc_maxlifetime, nhưng giới hạn trên sẽ không thể đoán trước.

  • Nếu bạn không đặt session.gc_maxlifetimecùng khoảng thời gian thì máy chủ có thể loại bỏ dữ liệu phiên nhàn rỗi sớm hơn; trong trường hợp này, một khách hàng vẫn còn nhớ id phiên của họ sẽ trình bày nhưng máy chủ sẽ không tìm thấy dữ liệu nào liên quan đến phiên đó, hoạt động hiệu quả như thể phiên vừa mới bắt đầu.

Sự chắc chắn trong môi trường quan trọng

Bạn có thể làm cho mọi thứ hoàn toàn có thể kiểm soát được bằng cách sử dụng logic tùy chỉnh để đặt giới hạn trên của phiên không hoạt động; cùng với giới hạn dưới từ phía trên này dẫn đến một thiết lập nghiêm ngặt.

Thực hiện việc này bằng cách lưu giới hạn trên cùng với phần còn lại của dữ liệu phiên:

session_start(); // ready to go!

$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
    // this session has worn out its welcome; kill it and start a brand new one
    session_unset();
    session_destroy();
    session_start();
}

// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;

Sự kiên trì của phiên id

Cho đến nay chúng tôi vẫn chưa quan tâm đến tất cả các giá trị chính xác của từng id phiên, chỉ với yêu cầu dữ liệu phải tồn tại miễn là chúng tôi cần chúng. Xin lưu ý rằng trong trường hợp (không chắc) mà id phiên quan trọng với bạn, bạn phải cẩn thận để tạo lại chúng session_regenerate_idkhi cần.


Câu hỏi: nếu gọi điều này, hãy để jsut nói mỗi phút, nó sẽ tăng giới hạn của nó chứ? ví dụ lúc 10:00 tôi gọi nó để giới hạn của nó sẽ là 11:00, sau 1 dặm, 10:01, giới hạn sẽ là 11:01?
oneofakind

@oneofakind: Nếu bạn gọi chính xác là gì?
Jon

1
Những cái này: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind

@oneofakind: Có, nhưng chỉ khi bạn gọi session_start() như vậy (nếu không thì không có tác dụng gì cả) và chỉ khi bạn luôn gọi hai người đó trước session_start(nếu không thì gc_maxlifetimecó khả năng ảnh hưởng đến tất cả các phiên hiện đang mở, trong khi session_set_cookie_paramschỉ có thể ảnh hưởng đến một phiên mới bắt đầu bằng yêu cầu hiện tại).
Jon

@Jon nếu tôi gọi session_start () một lần nữa, nó sẽ đặt lại mọi thứ trong $ _SESSION của tôi chứ? nếu bạn có ý bởi "có khả năng ảnh hưởng đến tất cả các phiên" thì sao? Cảm ơn vi đa trả lơi.
oneofakind

33

Nếu bạn sử dụng xử lý phiên mặc định của PHP, cách duy nhất để thay đổi thời lượng phiên đáng tin cậy trong tất cả các nền tảng là thay đổi php.ini . Đó là bởi vì trong một số nền tảng, bộ sưu tập rác được triển khai thông qua một tập lệnh chạy mọi thời gian nhất định ( tập lệnh cron ) đọc trực tiếp từ php.ini , và do đó mọi nỗ lực thay đổi nó trong thời gian chạy, ví dụ như thông qua ini_set(), đều không đáng tin cậy và rất có thể sẽ không làm việc

Ví dụ: trong các hệ thống Debian Linux, bộ sưu tập rác bên trong của PHP bị tắt theo session.gc_probability=0mặc định trong cấu hình và thay vào đó được thực hiện thông qua /etc/cron.d/php, chạy ở XX: 09 và XX: 39 (nghĩa là, mỗi nửa giờ). Công việc định kỳ này tìm kiếm các phiên cũ hơn session.gc_maxlifetime được chỉ định trong cấu hình và nếu tìm thấy bất kỳ, chúng sẽ bị xóa. Kết quả là, trong các hệ thống ini_set('session.gc_maxlifetime', ...)này được bỏ qua. Điều đó cũng giải thích tại sao trong câu hỏi này: các phiên PHP hết thời gian quá nhanh , OP gặp vấn đề ở một máy chủ nhưng các vấn đề đã chấm dứt khi chuyển sang một máy chủ khác.

Vì vậy, do bạn không có quyền truy cập vào php.ini , nếu bạn muốn làm điều đó một cách hợp lý, sử dụng xử lý phiên mặc định không phải là một tùy chọn. Rõ ràng, kéo dài tuổi thọ cookie là đủ cho máy chủ của bạn, nhưng nếu bạn muốn một giải pháp hoạt động đáng tin cậy ngay cả khi bạn chuyển đổi máy chủ, bạn phải sử dụng một giải pháp thay thế khác.

Các phương pháp thay thế có sẵn bao gồm:

  1. Đặt trình xử lý phiên (lưu) khác trong PHP để lưu các phiên của bạn trong một thư mục khác hoặc trong cơ sở dữ liệu, như được chỉ định trong PHP: Trình xử lý phiên tùy chỉnh (hướng dẫn sử dụng PHP) , để công việc định kỳ không tiếp cận được với nó và chỉ PHP thu gom rác nội bộ diễn ra. Tùy chọn này có thể có thể sử dụng ini_set()để đặt session.gc_maxlifetime nhưng tôi thích bỏ qua tham số maxlifetime trong gc()cuộc gọi lại của mình và tự mình xác định tuổi thọ tối đa.

  2. Hoàn toàn quên đi việc xử lý phiên nội bộ PHP và thực hiện quản lý phiên của riêng bạn. Phương pháp này có hai nhược điểm chính: bạn sẽ cần các biến phiên toàn cầu của riêng mình, do đó bạn mất lợi thế của siêu lớp $_SESSIONvà nó cần nhiều mã hơn do đó có nhiều cơ hội hơn cho các lỗi và lỗi bảo mật. Quan trọng nhất, số nhận dạng phiên phải được tạo ra từ các số ngẫu nhiên hoặc giả ngẫu nhiên được bảo mật bằng mật mã để tránh dự đoán ID phiên (dẫn đến việc chiếm quyền điều khiển phiên có thể xảy ra) và điều đó không dễ thực hiện với PHP. Ưu điểm chính là nó sẽ hoạt động ổn định trong tất cả các nền tảng và bạn có toàn quyền kiểm soát mã. Đó là cách tiếp cận được thực hiện bởi phần mềm diễn đàn phpBB (ít nhất là phiên bản 1; tôi không chắc về các phiên bản gần đây hơn).

Có một ví dụ về (1) trong tài liệu chosession_set_save_handler() . Ví dụ này dài nhưng tôi sẽ sao chép nó ở đây, với các sửa đổi liên quan cần thiết để kéo dài thời lượng phiên. Lưu ý bao gồm session_set_cookie_params()để tăng tuổi thọ cookie.

<?php
class FileSessionHandler
{

    private $savePath;
    private $lifetime;

    function open($savePath, $sessionName)
    {
        $this->savePath = 'my_savepath'; // Ignore savepath and use our own to keep it safe from automatic GC
        $this->lifetime = 3600; // 1 hour minimum session duration
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $this->lifetime < time() && file_exists($file)) { // Use our own lifetime
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
    );

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

session_set_cookie_params(3600); // Set session cookie duration to 1 hour
session_start();
// proceed to set and retrieve values by key from $_SESSION

Cách tiếp cận (2) phức tạp hơn; về cơ bản, bạn phải tự thực hiện lại tất cả các chức năng phiên. Tôi sẽ không đi vào chi tiết ở đây.


Bất cứ ai có thể xác nhận điều đó?
Oli

@Oli: Có vẻ đúng sau khi đọc một chữ thảo. Bạn cũng có thể muốn xem stackoverflow.com/questions/520237/ , nhưng nếu bạn không có quyền truy cập vào php.inicác tùy chọn thực tế của mình thì bị hạn chế nghiêm trọng.
Jon

Ngoài ra, trên Ubuntu 14 có vẻ như /usr/lib/php5/maxlifetimesẽ không tính được giá trị dưới 24 phút. Vì vậy, bạn không thể đặt thời gian chờ phiên của mình thấp hơn mức đó.
Henry

"Hoàn toàn quên đi việc xử lý phiên nội bộ PHP và thực hiện quản lý phiên của riêng bạn." người đàn ông tốt, đó là lời khuyên nguy hiểm. Một cơn ác mộng an ninh chắc chắn sẽ dẫn đến.
Kzqai

@Kzqai Tôi cũng lưu ý rằng "nó cần nhiều mã hơn do đó có nhiều cơ hội hơn cho các lỗi và lỗi bảo mật". Đó không phải là lời khuyên, tôi đang liệt kê các lựa chọn thay thế, nhưng nếu bạn có một gợi ý để cải thiện nó, xin vui lòng làm.
Pedro Gimeno

3

Thêm nhận xét cho bất kỳ ai sử dụng Plesk có vấn đề với bất kỳ điều nào ở trên vì điều đó làm tôi phát điên, đặt session.gc_maxlifetime từ tập lệnh PHP của bạn sẽ không hoạt động vì Plesk có tập lệnh thu gom rác riêng chạy từ cron.

Tôi đã sử dụng giải pháp được đăng trên đường dẫn bên dưới để chuyển công việc định kỳ từ hàng giờ sang hàng ngày để tránh vấn đề này, sau đó câu trả lời hàng đầu ở trên sẽ hoạt động:

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-simes-timing-earlier- ngạc nhiên


3

Đặt $_SESSION['login_time'] = time(); vào trang xác thực trước đó. Và đoạn trích dưới đây trong mọi trang khác mà bạn muốn kiểm tra thời gian chờ phiên.

if(time() - $_SESSION['login_time'] >= 1800){
    session_destroy(); // destroy session.
    header("Location: logout.php");
    die(); // See https://thedailywtf.com/articles/WellIntentioned-Destruction
    //redirect if the page is inactive for 30 minutes
}
else {        
   $_SESSION['login_time'] = time();
   // update 'login_time' to the last time a page containing this code was accessed.
}

Chỉnh sửa: Điều này chỉ hoạt động nếu bạn đã sử dụng các tinh chỉnh trong các bài đăng khác hoặc Bộ sưu tập rác bị vô hiệu hóa và muốn kiểm tra thủ công thời lượng phiên. Đừng quên thêm die()sau khi chuyển hướng, bởi vì một số tập lệnh / robot có thể bỏ qua nó. Ngoài ra, trực tiếp phá hủy phiên session_destroy()thay vì dựa vào chuyển hướng cho điều đó có thể là một lựa chọn tốt hơn, một lần nữa, trong trường hợp máy khách độc hại hoặc robot.


2

Chỉ cần một thông báo cho một lưu trữ chia sẻ máy chủ hoặc thêm vào tên miền =

Để cài đặt của bạn hoạt động, bạn phải có một thư mục phiên lưu khác cho tên miền được thêm bằng cách sử dụng php_value session.save_path "thư mụcA / sessionA".

Vì vậy, hãy tạo một thư mục đến máy chủ gốc của bạn, không vào public_html và không được công khai truy cập từ bên ngoài. Đối với cpanel / máy chủ của tôi hoạt động tốt, quyền truy cập thư mục 0700. Hãy thử ...

  • Mã php =

     #Session timeout, 2628000 sec = 1 month, 604800 = 1 week, 57600 = 16 hours, 86400 = 1 day
     ini_set('session.save_path', '/home/server/.folderA_sessionsA');
     ini_set('session.gc_maxlifetime', 57600); 
     ini_set('session.cookie_lifetime', 57600);
     ini_set('session.cache_expire', 57600);
     ini_set('session.name', 'MyDomainA');

trước session_start ();

hoặc là

  • .htaccess =

     php_value session.save_path /home/server/.folderA_sessionsA
     php_value session.gc_maxlifetime 57600
     php_value session.cookie_lifetime 57600
     php_value session.cache_expire 57600
     php_value session.name MyDomainA

Sau nhiều nghiên cứu và thử nghiệm, nó hoạt động tốt với máy chủ cpanel / php7 được chia sẻ. Rất cám ơn: NoiS


1

Không. Nếu bạn không có quyền truy cập vào php.ini, bạn không thể đảm bảo rằng các thay đổi sẽ có bất kỳ ảnh hưởng nào.

Tôi nghi ngờ bạn cần phải kéo dài thời gian phiên của bạn mặc dù.
Nó có thời gian chờ khá hợp lý tại thời điểm này và không có lý do để mở rộng nó.


Xin chào Col, tôi đã tìm khắp nơi để tìm cách liên lạc với bạn. Tôi thấy rằng bạn đã cho tôi một số gợi ý về bài đăng cuối cùng của tôi đã bị đóng cửa (Chủ nhật.) Tôi đã bận rộn với một dự án khác và bây giờ nó đã biến mất. Tôi thực sự muốn thử đề xuất của bạn. Điều này dù sao để tìm thấy những gì bạn đã viết?
Con chó già

Theo tôi có thể thấy, nó không chỉ bị đóng mà còn bị xóa. Những người này không có danh dự. Vâng, vấn đề của bạn có một giải pháp chung mà tôi đang nói đến. Tôi sẽ viết cho bạn qua email. Nói tóm lại, đó là về việc chạy 2 truy vấn bổ sung để có được các giá trị trước / sau này. SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
Ý thức chung của bạn

0

Bạn có thể ghi đè các giá trị trong php.ini từ mã PHP của bạn bằng cách sử dụng ini_set().


4
-1: session.gc_maxlifetimekhông phải là cài đặt kiểm soát thời gian tồn tại của phiên. Nó có thể được bludgeoned để làm việc như thế nếu bạn thiết lập session.gc_divisorđể 1, nhưng đó chỉ là khủng khiếp.
Jon

1
@Jon Tôi đã thấy rất nhiều câu trả lời trên SO gợi ý ngược lại, tại sao vậy? stackoverflow.com/questions/514155/ đá stackoverflow.com/questions/9904105/ trên
gianni christofakis

2
@yannishristofakis: gc_maxlifetimeđặt khoảng thời gian sau đó dữ liệu phiên đủ điều kiện để thu gom rác - nếu GC xảy ra sau khi hết thời gian đó, dữ liệu phiên sẽ bị hủy (với cài đặt mặc định, điều này giống như hết hạn phiên). Nhưng GC được kích hoạt một cách xác suất vào mỗi phiên bắt đầu, vì vậy không có gì đảm bảo phiên sẽ thực sự hết hạn - bạn có thể vẽ đường cong của đầu dò theo thời gian, nhưng nó sẽ không giống như một viên gạch. Đó chỉ là phần nổi của tảng băng chìm; xem stackoverflow.com/questions/520237/ cường
Jon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.