จะเปลี่ยนการหมดเวลาของเซสชันใน PHP ได้อย่างไร


154

ฉันต้องการที่จะขยายการหมดเวลาเซสชั่นใน PHP

ฉันรู้ว่าเป็นไปได้ที่จะทำเช่นนั้นโดยการแก้ไขไฟล์ php.ini แต่ฉันไม่สามารถเข้าถึงได้

ดังนั้นจึงเป็นไปได้ที่จะทำเฉพาะกับรหัส PHP?



1
ที่เกี่ยวข้องนี่เป็น php.ini แต่ฉันคิดว่า yo สามารถใช้ ini_set ได้เช่น @matino กล่าวว่าstackoverflow.com/questions/520237/ …
J-Rou

คำตอบ:


324

การหมดเวลาของเซสชันเป็นแนวคิดที่จะต้องนำไปใช้ในรหัสหากคุณต้องการการค้ำประกันที่เข้มงวด นั่นเป็นวิธีเดียวที่คุณจะมั่นใจได้อย่างแน่นอนว่าไม่มีเซสชันใดจะรอดชีวิตหลังจากไม่มีการใช้งาน X นาที

หากการผ่อนคลายข้อกำหนดนี้เล็กน้อยเป็นที่ยอมรับและคุณสบายดีเมื่อวางขอบเขตล่างแทนขีด จำกัด ที่เข้มงวดกับระยะเวลาคุณสามารถทำได้อย่างง่ายดายและไม่ต้องเขียนตรรกะที่กำหนดเอง

ความสะดวกสบายในสภาพแวดล้อมที่ผ่อนคลาย: อย่างไรและทำไม

หากเซสชันของคุณถูกนำไปใช้กับคุกกี้ (ซึ่งอาจเป็น) และหากลูกค้าไม่เป็นอันตรายคุณสามารถกำหนดขอบเขตบนของช่วงเวลาเซสชันโดยปรับแต่งพารามิเตอร์บางอย่าง หากคุณใช้การจัดการเซสชั่นเริ่มต้นของ PHP กับคุกกี้การตั้งค่าsession.gc_maxlifetimeพร้อมsession_set_cookie_paramsจะทำงานให้คุณเช่นนี้:

// 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!

สิ่งนี้ทำงานได้โดยการกำหนดค่าเซิร์ฟเวอร์เพื่อเก็บข้อมูลเซสชันไว้เป็นเวลาอย่างน้อยหนึ่งชั่วโมงที่ไม่มีการใช้งานและสั่งให้ไคลเอ็นต์ของคุณทราบว่าพวกเขาควร "ลืม" รหัสเซสชันของพวกเขาหลังจากช่วงเวลาเดียวกัน ต้องใช้ทั้งสองขั้นตอนเพื่อให้บรรลุผลตามที่คาดหวัง

  • หากคุณไม่บอกให้ลูกค้าลืมรหัสเซสชันหลังจากผ่านไปหนึ่งชั่วโมง (หรือหากลูกค้าประสงค์ร้ายและเลือกที่จะเพิกเฉยต่อคำแนะนำของคุณ) พวกเขาจะใช้รหัสเซสชันเดิมต่อไปและระยะเวลาที่มีประสิทธิภาพจะไม่กำหนดขึ้น นั่นเป็นเพราะเซสชันที่อายุการใช้งานหมดอายุบนฝั่งเซิร์ฟเวอร์จะไม่ถูกเก็บรวบรวมขยะทันที แต่เฉพาะเมื่อใดก็ตามที่เซสชัน GC เข้ามา

    GC เป็นกระบวนการที่มีราคาแพงดังนั้นโดยทั่วไปความน่าจะเป็นนั้นค่อนข้างเล็กหรือเป็นศูนย์ (เว็บไซต์ที่ได้รับความนิยมจำนวนมากอาจทำให้ GC น่าจะเป็นไปได้ทั้งหมดและกำหนดให้มันเกิดขึ้นในพื้นหลังทุก ๆ X นาที) ในทั้งสองกรณี (สมมติว่าลูกค้าที่ไม่ร่วมมือ) ขอบเขตที่ต่ำกว่าสำหรับช่วงเวลาเซสชันที่มีประสิทธิภาพจะเป็นsession.gc_maxlifetimeแต่ขอบเขตบนจะไม่แน่นอน

  • หากคุณไม่ได้ตั้งค่าsession.gc_maxlifetimeช่วงเวลาเดียวกันเซิร์ฟเวอร์อาจละทิ้งข้อมูลเซสชันว่างก่อนหน้านั้น ในกรณีนี้ลูกค้าที่ยังคงจดจำรหัสเซสชันของตนจะแสดง แต่เซิร์ฟเวอร์จะไม่พบข้อมูลที่เกี่ยวข้องกับเซสชันนั้นทำงานได้อย่างมีประสิทธิภาพราวกับว่าเซสชันเพิ่งเริ่มทำงาน

ความมั่นใจในสภาพแวดล้อมที่สำคัญ

คุณสามารถควบคุมทุกสิ่งได้อย่างสมบูรณ์โดยใช้ตรรกะที่กำหนดเองเพื่อวางขอบเขตบนบนการไม่ใช้งานเซสชัน พร้อมกับขอบล่างจากด้านบนผลลัพธ์นี้ในการตั้งค่าที่เข้มงวด

ทำสิ่งนี้โดยการบันทึกขอบเขตบนพร้อมกับส่วนที่เหลือของข้อมูลเซสชัน:

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;

การคงอยู่ของรหัสเซสชัน

จนถึงตอนนี้เรายังไม่ได้กังวลกับค่าที่แน่นอนของแต่ละ ID เซสชั่นเฉพาะกับข้อกำหนดที่ว่าข้อมูลควรมีอยู่ตราบเท่าที่เราต้องการให้พวกเขา โปรดทราบว่าในกรณีที่ไม่น่าเป็นไปได้ว่าเซสชันนั้นมีความสำคัญกับคุณคุณจะต้องระมัดระวังในการสร้างขึ้นมาใหม่session_regenerate_idเมื่อจำเป็น


คำถาม: ถ้าเรียกสิ่งนี้มา jsut พูดทุกนาทีมันจะเพิ่มขีด จำกัด หรือไม่ ตัวอย่างเมื่อ 10:00 ฉันเรียกมันว่าดังนั้นขีด จำกัด จะเป็น 11:00 หลังจาก 1 ไมล์, 10:01 ขีด จำกัด จะเป็น 11:01 หรือไม่
oneofakind

@oneofakind: ถ้าคุณเรียกว่าอะไรกันแน่?
Jon

1
สิ่งเหล่านี้: ini_set ('session.gc_maxlifetime', 3600); session_set_cookie_params (3600);
oneofakind

@oneofakind: ใช่ แต่เฉพาะเมื่อคุณโทรsession_start()ด้วย (ไม่เช่นนั้นจะไม่มีผลใด ๆ ) และเฉพาะในกรณีที่คุณโทรหาทั้งสองก่อนหน้านี้เสมอsession_start (มิฉะนั้นgc_maxlifetimeอาจมีผลกระทบต่อเซสชันทั้งหมดที่เปิดอยู่ในขณะsession_set_cookie_paramsนี้เท่านั้น คำขอปัจจุบัน)
Jon

@ จอนถ้าฉันเรียก session_start () อีกครั้งมันจะรีเซ็ตทุกอย่างใน $ _SESSION ของฉันหรือไม่ ถ้าคุณหมายถึงโดย "มีศักยภาพที่จะส่งผลกระทบต่อทุกเซสชั่น" อย่างไร? ขอบคุณสำหรับการตอบกลับ.
oneofakind

33

ถ้าคุณใช้การจัดการเซสชั่นเริ่มต้นของ PHP, วิธีเดียวที่จะเชื่อถือได้เปลี่ยนระยะเวลาการใช้งานในทุกแพลตฟอร์มคือการเปลี่ยนแปลงphp.ini นั่นเป็นเพราะในบางแพลตฟอร์มการรวบรวมขยะจะดำเนินการผ่านสคริปต์ที่ทำงานทุกเวลา ( สคริปต์cron ) ที่อ่านโดยตรงจากphp.iniดังนั้นความพยายามใด ๆ ที่จะเปลี่ยนมันในเวลาทำงานเช่นผ่านini_set()ไม่น่าเชื่อถือและเป็นไปได้มากที่สุด จะไม่ทำงาน

ตัวอย่างเช่นในระบบ Debian Linux การรวบรวมขยะภายในของ PHP ถูกปิดใช้งานโดยการตั้งค่าsession.gc_probability=0เริ่มต้นในการกำหนดค่าและจะทำแทนผ่าน /etc/cron.d/php ซึ่งทำงานที่ XX: 09 และ XX: 39 (นั่นคือ ทุกครึ่งชั่วโมง) งาน cron นี้ค้นหาเซสชันที่เก่ากว่าsession.gc_maxlifetime ที่ระบุในการกำหนดค่าและหากพบสิ่งใดสิ่งเหล่านั้นจะถูกลบออก เป็นผลให้ในระบบเหล่านี้ini_set('session.gc_maxlifetime', ...)จะถูกละเว้น นั่นยังอธิบายว่าทำไมในคำถามนี้: เซสชัน PHP หมดเวลาเร็วเกินไป OP มีปัญหาในโฮสต์หนึ่ง แต่ปัญหาหยุดทำงานเมื่อเปลี่ยนไปใช้โฮสต์อื่น

ดังนั้นหากคุณไม่สามารถเข้าถึงphp.iniได้หากคุณต้องการทำแบบพกพาการใช้การจัดการเซสชันเริ่มต้นไม่ใช่ตัวเลือก เห็นได้ชัดว่าการยืดอายุคุกกี้นั้นเพียงพอสำหรับโฮสต์ของคุณ แต่ถ้าคุณต้องการโซลูชันที่ทำงานได้อย่างน่าเชื่อถือแม้ว่าคุณจะเปลี่ยนโฮสต์คุณต้องใช้ทางเลือกอื่น

วิธีการทางเลือกที่มีอยู่รวมถึง:

  1. ตั้งค่าตัวจัดการเซสชั่นที่แตกต่างกัน (บันทึก) ใน PHP เพื่อบันทึกเซสชันของคุณในไดเรกทอรีที่แตกต่างกันหรือในฐานข้อมูลตามที่ระบุไว้ในPHP: Custom Session Handlers (คู่มือ PHP)เพื่อให้งานcronไม่ถึงและ PHP เท่านั้น การรวบรวมขยะภายในจะเกิดขึ้น ตัวเลือกนี้อาจใช้ประโยชน์จากini_set()การตั้งค่าsession.gc_maxlifetimeแต่ฉันต้องการเพียงแค่ละเว้นพารามิเตอร์maxlifetimeในการgc()โทรกลับของฉันและกำหนดอายุการใช้งานสูงสุดด้วยตัวเอง

  2. ลืมการจัดการเซสชันภายใน PHP อย่างสมบูรณ์และใช้การจัดการเซสชันของคุณเอง วิธีการนี้มีข้อเสียเปรียบหลักสองประการ: คุณจะต้องใช้ตัวแปรเซสชันทั่วโลกของคุณเองดังนั้นคุณจึงสูญเสียความได้เปรียบจาก$_SESSIONsuperglobal และต้องการรหัสมากขึ้นจึงมีโอกาสมากขึ้นสำหรับข้อบกพร่องและข้อบกพร่องด้านความปลอดภัย สิ่งสำคัญที่สุดคือตัวระบุเซสชันควรสร้างขึ้นจากตัวเลขสุ่มหรือแบบเทียมที่มีความปลอดภัยแบบเข้ารหัสเพื่อหลีกเลี่ยงการคาดการณ์ ID เซสชัน (นำไปสู่การหักหลังเซสชันที่เป็นไปได้) และนั่นไม่ใช่เรื่องง่ายที่จะทำกับ PHP แบบพกพา ข้อได้เปรียบหลักคือมันจะทำงานได้อย่างต่อเนื่องในทุกแพลตฟอร์มและคุณสามารถควบคุมโค้ดได้อย่างสมบูรณ์ นั่นเป็นวิธีที่นำมาใช้เช่นโดยซอฟต์แวร์ฟอรัมphpBB (อย่างน้อยเวอร์ชัน 1; ฉันไม่แน่ใจเกี่ยวกับเวอร์ชันล่าสุดเพิ่มเติม

มีตัวอย่างของ (1) ในการเป็นเอกสาร session_set_save_handler()ตัวอย่างมีความยาว แต่ฉันจะทำซ้ำที่นี่ด้วยการแก้ไขที่เกี่ยวข้องที่จำเป็นในการขยายระยะเวลาของเซสชัน บันทึกการรวมของsession_set_cookie_params()เพื่อเพิ่มอายุการใช้งานคุกกี้ด้วย

<?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

วิธีการ (2) มีความซับซ้อนมากขึ้น โดยทั่วไปคุณจะต้องใช้ฟังก์ชั่นเซสชันทั้งหมดด้วยตัวเองอีกครั้ง ฉันจะไม่ลงรายละเอียดที่นี่


มีใครยืนยันได้บ้าง
Oli

@Oli: มันดูถูกต้องหลังจากอ่านคร่าวๆ คุณอาจต้องการดูstackoverflow.com/questions/520237/ …แต่ถ้าคุณไม่สามารถเข้าถึงphp.iniตัวเลือกการปฏิบัติของคุณจะถูก จำกัด อย่างรุนแรง
Jon

นอกจากนี้ใน Ubuntu 14 ดูเหมือนว่า/usr/lib/php5/maxlifetimeจะไม่คำนวณค่าต่ำกว่า 24 นาที ดังนั้นคุณไม่สามารถตั้งค่าการหมดเวลาเซสชันของคุณให้ต่ำกว่านั้นได้
เฮนรี่

"ลืมการจัดการเซสชันภายใน PHP ทั้งหมดและใช้การจัดการเซสชันของคุณเอง" มนุษย์พระเจ้าที่ดีนั่นคือคำแนะนำที่เป็นอันตราย ฝันร้ายด้านความปลอดภัยย่อมส่งผลให้
Kzqai

@ Kzqai ฉันยังทราบว่า "มันต้องการรหัสเพิ่มเติมจึงมีโอกาสมากขึ้นสำหรับข้อบกพร่องและข้อบกพร่องด้านความปลอดภัย" ไม่ใช่คำแนะนำฉันกำลังหาทางเลือก แต่ถ้าคุณมีข้อเสนอแนะในการปรับปรุงโปรดทำ
Pedro Gimeno

3

การเพิ่มความคิดเห็นสำหรับใครก็ตามที่ใช้ Plesk มีปัญหากับข้อใดข้อหนึ่งข้างต้นเพราะมันทำให้ฉันเป็นบ้าการตั้งค่า session.gc_maxlifetime จากสคริปต์ PHP ของคุณจะไม่ทำงานเหมือนที่ Plesk มีสคริปต์การรวบรวมขยะของตัวเองทำงานจาก cron

ฉันใช้วิธีแก้ปัญหาโพสต์ในลิงค์ด้านล่างของการย้ายงาน cron จากรายชั่วโมงเป็นรายวันเพื่อหลีกเลี่ยงปัญหานี้แล้วคำตอบด้านบนควรทำงาน:

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

https://websavers.ca/plesk-php-sessions-timing-earlier-expected


3

ใส่$_SESSION['login_time'] = time();ลงในหน้าการตรวจสอบก่อนหน้า และด้านล่างในหน้าอื่น ๆ ที่คุณต้องการตรวจสอบการหมดเวลาของเซสชัน

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.
}

แก้ไข:ใช้งานได้เฉพาะเมื่อคุณใช้การปรับแต่งในโพสต์อื่น ๆ หรือปิดใช้งานการรวบรวมขยะและต้องการตรวจสอบระยะเวลาเซสชันด้วยตนเอง อย่าลืมเพิ่มdie()หลังจากเปลี่ยนเส้นทางเนื่องจากสคริปต์ / โรบ็อตบางตัวอาจเพิกเฉย นอกจากนี้การทำลายเซสชั่นโดยตรงด้วยsession_destroy()แทนที่จะพึ่งพาการเปลี่ยนเส้นทางสำหรับที่อาจเป็นตัวเลือกที่ดีกว่าอีกครั้งในกรณีของลูกค้าที่เป็นอันตรายหรือหุ่นยนต์


2

เพียงแจ้งให้ทราบล่วงหน้าสำหรับการโฮสต์เซิร์ฟเวอร์ที่ใช้ร่วมกันหรือเพิ่มในโดเมน

เพื่อให้การตั้งค่าของคุณใช้งานได้คุณจะต้องมีเซสชันบันทึกที่ต่างออกไปสำหรับโดเมนที่เพิ่มโดยใช้ php_value session.save_path "folderA / timesA"

ดังนั้นสร้างโฟลเดอร์ไปยังเซิร์ฟเวอร์รูทของคุณไม่ใช่ใน public_html และไม่ให้เข้าถึงจากภายนอก สำหรับ cpanel / เซิร์ฟเวอร์ของฉันทำงานได้ดีการอนุญาตของโฟลเดอร์ 0700 ลอง ...

  • โค้ด 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');

ก่อน session_start ();

หรือ

  • .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

หลังจากการค้นคว้าและทดสอบหลายอย่างสิ่งนี้ใช้ได้ผลดีกับเซิร์ฟเวอร์ cpanel / php7 ที่ใช้ร่วมกัน ขอบคุณมาก: NoiS


1

ไม่หากคุณไม่มีสิทธิ์เข้าถึง php.ini คุณไม่สามารถรับประกันได้ว่าการเปลี่ยนแปลงจะมีผลกระทบใด ๆ

ฉันสงสัยว่าคุณต้องยืดเวลาการเรียนของคุณออกไป
ขณะนี้มีการหมดเวลาที่สมเหตุสมผลในขณะนี้และไม่มีเหตุผลที่จะขยายเวลา


สวัสดี Col ฉันได้ดูทั่วสถานที่นี้เพื่อหาวิธีที่จะติดต่อคุณ ฉันเห็นว่าคุณให้คำแนะนำกับฉันในโพสต์ล่าสุดของฉันที่ถูกปิด (อาทิตย์) ฉันยุ่งกับโครงการอื่นและตอนนี้มันก็หายไป ฉันอยากลองคำแนะนำของคุณ ที่นี่มีอยู่แล้วเพื่อค้นหาสิ่งที่คุณเขียน?
สุนัขตัวเก่า

เท่าที่ฉันเห็นมันไม่เพียง แต่ปิด แต่ยังถูกลบ คนเหล่านี้ไม่มีเกียรติ ใช่ปัญหาของคุณมีวิธีแก้ไขปัญหาทั่วไปที่ฉันพูดถึง ฉันจะเขียนทางอีเมล กล่าวโดยสรุปคือมีการเรียกใช้ 2 คิวรีเพิ่มเติมเพื่อรับค่าก่อนหน้า / ถัดไปเหล่านี้ SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
สามัญสำนึกของคุณ

0

คุณสามารถแทนที่ค่าใน php.ini จากโค้ด PHP ini_set()ของคุณโดยใช้


4
-1: session.gc_maxlifetimeไม่ใช่การตั้งค่าที่ควบคุมอายุการใช้งานเซสชัน มันสามารถกระบองในการทำงานเช่นว่าถ้าคุณตั้งsession.gc_divisorไป1แต่ที่น่ากลัวเพียง
Jon

1
@ จอนฉันได้เห็นคำตอบมากมายเกี่ยวกับเรื่องนี้ดังนั้นจึงแนะนำให้ตรงกันข้ามทำไมถึงเป็นเช่นนั้น? stackoverflow.com/questions/514155/... stackoverflow.com/questions/9904105/...
Giannis christofakis

2
@yannishristofakis: gc_maxlifetimeตั้งค่าช่วงเวลาหลังจากที่ข้อมูลเซสชันมีสิทธิ์สำหรับการรวบรวมขยะ - หาก GC เกิดขึ้นหลังจากเวลาผ่านไปนานมากข้อมูลเซสชันจะถูกทำลาย (ด้วยการตั้งค่าเริ่มต้นซึ่งเหมือนกับการหมดอายุเซสชัน) แต่ GC ถูกเรียกใช้ความน่าจะเป็นในการเริ่มต้นแต่ละเซสชันดังนั้นจึงไม่มีการรับประกันว่าเซสชันนั้นจะหมดอายุจริง ๆ - คุณสามารถเขียนกราฟของเวลาเทียบกับเวลาได้ แต่มันจะไม่ดูเหมือนกำแพงอิฐ นั่นเป็นเพียงส่วนปลายของภูเขาน้ำแข็ง; ดูstackoverflow.com/questions/520237/…
จอน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.