CodeIgniter Framework Source Notes (--session) files file driver Implementation __ Framework

Source: Internet
Author: User
Tags flock md5 rewind rtrim codeigniter file permissions

The file driver for CI is to meet the following three conditions:
1, drive to implement open, read, write, close, Destory, GC six methods.
Session_Start (), The Open (), read () method is invoked. And there is a certain probability of triggering the GC () method.
Session_commit () or session_write_close (), triggers the Write (), close () method.
Session_destory () triggers the Desotry () method.

These six methods implement the following functions:
Open: Gets and creates a path to save the file
READ: Retrieves or creates a session_id corresponding file based on session_id, gets the file action pointer and locks the flock
Write: Writes the content to the session_id corresponding file when the session content changes. The write is a full volume write. The contents of the Session_data include the new session key value pairs and the existing key value pairs.
Close: Releases (flock) the file lock and closes the (fclose) file pointer.
destory: Deletes the server session_id corresponding file, and clears the client corresponding session_id cookie information
GC: Determines whether a file expires: Determines whether the session's corresponding session expires based on the file's last modification time (Filemtime ()) and the current time. This method is called at a certain probability when session_start.

2, drive to support session_regenerate_id ().
This method regenerates a new session_id and creates a file named after this session_id. Then copy the contents of the old session_id file into the new file. Finally delete the file where old session_id resides.

3, the driver to achieve session Lock: Here using File lock mode.

implementation: file-driven

Class Ci_session_files_driver extends Ci_session_driver implements Sessionhandlerinterface {//File save path protected $

    _save_path;

    File manipulation handle protected $_file_handle;

    filename protected $_file_path;

    Whether the new document identifies protected $_file_new; ------------------------------------------------------------------------//Constructor Public function __construct (&A
        MP; $params) {parent::__construct ($params);
            Initializes the file save path, setting the Session.save_path option in PHP.ini (isset ($this->_config[' Save_path ') according to the configuration file) {
            $this->_config[' save_path '] = RTrim ($this->_config[' Save_path '], '/\\ ');
        Set the Session.save_path option in php.ini according to the profile Ini_set (' Session.save_path ', $this->_config[' Save_path ')); else {//if $config[' Sess_save_path ' in the configuration file does not exist, use the default path in the current INI $this->_config['
        Save_path '] = RTrim (Ini_get (' Session.save_path '), '/\\ '); }
    }

    // ---------------The first parameter of the---------------------------------------------------------//open method//$save_path corresponds to Ini_get (' Session.save_pa Th ')//The second parameter $name corresponds to the Ini_get (' session.name ') public function open ($save _path, $name) {//If the file diameter does not exist, try to create
                Build if (! Is_dir ($save _path)) {if (! mkdir ($save _path, 0700, TRUE)) { If you cannot create a directory, throw new Exception ("Session:configured save Path". $this->_config[' Save_path ']. "' I
        s not directory, doesn ' t exist or cannot is created. '} If the directory is not writable, throw an exception ElseIf (! is_writable ($save _path)) {throw new Exception ("session:configured
        Save path ' ". $this->_config[' Save_path ']." ' Isn't writable by the PHP process. "
        The path to the file save, where the file is saved with a bit of material to avoid conflict $this->_config[' save_path ' = $save _path; $this->_file_path = $this->_config[' Save_path ']. Directory_separator. $name//we ' ll usE The session cookie name as a prefix to avoid collisions.

        ($this->_config[' match_ip ']? MD5 ($_server[' REMOTE_ADDR '): ");
    return $this->_success; }//------------------------------------------------------------------------//read//Parameter $session_id corresponds to Sess The value of ion_id () is public function read ($session _id) {//if session_id () the corresponding file action pointer is an empty if ($this->_file_ha  Ndle = = NULL) {//Just using fopen () with ' c+b ' mode would being perfect, but it is only// Available since PHP 5.2.6 and we have to set permissions for new files,//So we ' d have to hack around this.
            ..
            It is recommended that you use c+ mode when opening a file because the schema does not delete the original contents of the file when the file exists (w+ mode clears the original file content)//But the mode is only valid after PHP 5.2.6, so we have to do different things depending on whether the file exists. File does not exist in ' w+ ' mode, the file exists on the ' r+ ' mode//when the requested session file does not exist, the ' w+b ' read-write mode is used to create the file, get the action handle if (($this->_file_n EW =!
          File_exists ($this->_file_path. $session _id)) = = = TRUE)  {//use ' w+b ' mode to open the file, get the action handle if ($this->_file_handle = fopen ($this->_file_path. $sessi on_id, ' w+b ') = = FALSE) {//If success cannot be created, return failure log_message (' Error '),
                    "Session:file '". $this->_file_path. $session _id. "' doesn ' t exist and cannot be created.");
                return $this->_failure; If the requested session file exists, open the file in ' r+b ' read-write mode to get the action handle ElseIf (($this->_file_handle = fopen ($this->_file_path. $session _id, ' r+b ')) = = FALSE) {//if failed to read successfully, return failure log_message (' Error ', "session:unable to open fi
                Le ' ". $this->_file_path. $session _id.");
            return $this->_failure;
            The file pointer was successfully obtained and assigned to the $this->_file_handle//lock file pointer to a $this->_file_handle (LOCK_EX is an exclusive lock) Note: The release lock (Lock_un) is placed in the close () function if (Flock ($this->_file_handle, LOCK_EX)= = FALSE) {//Not locked successfully, log, release file pointer, then return failed.
                Log_message (' Error ', ' session:unable to obtain lock for file '. $this->_file_path. $session _id. ");
                Fclose ($this->_file_handle);
                $this->_file_handle = NULL;
            return $this->_failure; }//Needed by write () to detect session_regenerate_id () calls///assign $session_id to the properties of the image $this->_se SSION_ID//session_regenerate_id () after changing SessionID, in the Write method, which preserves the old SessionID $this->_session_i

            D = $session _id;
                If it is a newly generated file, set the file permissions to ($this->_file_new) {//Read Only permission, no Execute permissions
                chmod ($this->_file_path. $session _id, 0600);
            $this->_fingerprint = MD5 (');//summary is NULL character MD5 return '; }//We shouldn ' t need this, but apparently we do ...//check Https://github.com/bcit-ci/Codeigniter/issues/4039//if $this->_file_handle = = FALSE, return failure.  This is git on a call Aanbar's brother found, and then fill up the $this->_file_handle = = FALSE This judgment,//Because fopen success when the file pointer, if open failure return FALSE ElseIf
        ($this->_file_handle = = FALSE)
        {return $this->_failure; else {//If the pointer is not empty//The file internal offset pointer is again pointed to the opening rewind ($this->_file_handle
        );
        } $session _data = '; Read the content for ($read = 0, $length = filesize ($this->_file_path. $session _id); $read < $length; $read + = strlen ($
                Buffer) {if ($buffer = fread ($this->_file_handle, $length-$read)) = = FALSE) {
            Break
        $session _data. = $buffer;
        ->_fingerprint = MD5 ($session _data) based on content generated file summary $this
    return $session _data; Write Note: The writes for the session are all written, not incremental write//parameter $session_id corresponding to the value//parameter of session_id () $session_Data is not just the currently pending writes, it contains the saved data for the entire session + the data public function write that is currently being written ($session _id, $session _data) {/********* SESSION_REGENERATE_ID () processing begins *****************///If the program calls SESSION_REGENERATE_ID (), it causes the $session_id after the function call (
        Parameter $session_id) is inconsistent with the $session_id ($this->_session_id) before the function call.
            At this point we need to close the old file pointer, open a new file to get operation pointers//The IF condition statement here is actually a short-circuit operation, decomposition is/*if ($session _id!== $this->_session_id) { $close _flag= $this->close ()//Call Close closes the old pointer $read _flag= $this->read ($session _id);//read function parameter is new $SE
            SSION_ID, which creates a new file//error in one of the two steps above, then returns a failure.
            In fact, OR is also short-circuit operation, the first $close_flag=== $this->_failure, will not be followed by the implementation of $this->read ($session _id)//To explain the idea, first ignore this 
        if ($close _flag=== $this->_failure OR $read _flag=== $this->_failure) return $this->_failure; }*/if ($session _id!== $this->_session_id && ($this->close () = = $this->_failure OR $th Is->read ($session_id) = = = = $this->_failure)) {return $this->_failure;
            }//If $this->_file_handle is not a resource type, an error is returned if (! Is_resource ($this->_file_handle)) {
        return $this->_failure; ///If the session content summary of the current request is the same as $session_data, then the new SessionID file is generated successfully//and the touch function is used to test the existence of the file and detect the $this->_file_ New token (the tag is set to True if the file does not exist in read)//If the condition is satisfied, it is returned successfully elseif ($this->_fingerprint = = MD5 ($session _data
                ) {return (! $this->_file_new && Touch ($this->_file_path. $session _id)) ?
        $this->_failure: $this->_success; /***************** session_regenerate_id () processing end *****************///If it is a ready-made file, then empty the content if (! $t
            His->_file_new) {//Empty file contents Ftruncate ($this->_file_handle, 0);
        Point the file internal offset pointer back to the opening rewind ($this->_file_handle);
}        Session writes are written in full volume, not in incremental writes///$session_data content is written to the file. if ($length = strlen ($session _data)) > 0) {for ($written = 0; $written < $length; $written = =  $result) {if ($result = fwrite ($this->_file_handle, substr ($session _data, $written)) = = =
                FALSE) {break; } if (! Is_int ($result)) {$this->_fingerprint = MD5 (substr ($se
                Ssion_data, 0, $written));
                Log_message (' Error ', ' session:unable to write data. ');
            return $this->_failure;
        }//Get Session content Summary $this->_fingerprint = MD5 ($session _data);
    return $this->_success;
    }//Close//close () executes after the program that is currently requested executes, or performs public function close () when Session_commit (), Session_write_close () is invoked.
      {if (Is_resource ($this->_file_handle)) {//Free file lock      Flock ($this->_file_handle, Lock_un);
            Release the file pointer fclose ($this->_file_handle);
        Empty variable $this->_file_handle = $this->_file_new = $this->_session_id = NULL;
    return $this->_success; }//Destroy public Function destory ($session _id) {//Call Close () method if ($this->close () = = $
                this->_success) {if (File_exists ($this->_file_path. $session _id)) {
                Deletes the corresponding client cookie $this->_cookie_destroy (); Delete server-side file return unlink ($this->_file_path. $session _id)?
            $this->_success: $this->_failure;
        return $this->_success; }//Call Close () method failed ElseIf ($this->_file_path!== NULL) {//clear PHP cached information for this file, Is_file (
        ), Is_dir (), file_exists () have influence Clearstatcache ();    Repeat the above statement, and then delete once if (File_exists ($this->_file_path. $session _id)) {$this
                ; _cookie_destroy (); Return unlink ($this->_file_path $session _id)?
            $this->_success: $this->_failure;
        return $this->_success;
    return $this->_failure; }//------------------------------------------------------------------------//gc method. When Session_Start () is called for probability, delete expired files Public Function GC ($maxlifetime) {if (! Is_dir ($this->_config[' Save_pat H ']) OR ($directory = opendir ($this->_config[' Save_path ')) = = FALSE) {log_message (' Debug ', ' Sess
            Ion:garbage collector couldn ' t list files under directory '. $this->_config[' Save_path '].
        return $this->_failure;
        $ts = Time ()-$maxlifetime; To determine the regular session file name, so as to avoid mistakenly deleting the file $pattern = sprintf ('/^%s[0-9a-f]{%d}$/', Preg_quote ($this->_config[' cookie_name '], '/'), ($this->_config[' match_ip '] = = TRUE? 72:40)

        ); while ($file = Readdir ($directory))!== FALSE} {//If the filename doesn ' t match this pattern, it ' s
                Either not a session file or was not ours////////. Preg_match (!, $file) based on the creation time. OR! Is_file ($this->_config[' Save_path '). Directory_separator. $file) OR ($mtime = filemtime ($this->_config[' Save_path ').
            Directory_separator. $file)) = = FALSE OR $mtime > $ts) {continue; } unlink ($this->_config[' Save_path ').
        Directory_separator. $file);

        } closedir ($directory);
    return $this->_success; }

}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.