Computer lessons

Php cookie lifetime. Sessions

The period of operation of the PHP $_SESSION variables, and as a consequence, the activity of web applications, depends on the duration of the session. For example, if a user is logged into the system, the time during which he can be inactive without having to re-enter his login and password depends on this parameter.

There are different ways to set session lifetimes. Let's try to figure it out using the Linux operating system as an example.

How to find out the session lifetime

Before setting up, it is worth looking at the current state. There are several methods to do this:

1. On the server using the php command

php -i | grep session

We get a list of parameters related to sessions. We are interested in:

  • session.cookie_lifetime => 0 => 0
  • session.gc_maxlifetime => 1440 => 1440

These values ​​are the default value. cookie_lifetime => 0 talks about the effect of cookies until the browser is closed, if you set this parameter to a certain value, the session will be interrupted when the session is active, so it is better to leave it at zero.

2. Using the php function ini_get

$maxlifetime = ini_get("session.gc_maxlifetime");
$cookielifetime = ini_get("session.cookie_lifetime");

Echo $maxlifetime;
echo $cookielifetime;

systemctl restart apache2 || systemctl restart httpd

* in Linux versions without systemd we use the command service apache2 restart or service httpd restart.

If we use FastCGI (PHP-FPM):

Configuration via .htaccess file

This file allows the webmaster to manage some web server settings. To edit it you need access to the site files. The method will not work if the PHP handler is not Apache, but, for example, NGINX + PHP-FPM. Although, there is also a way (more on it below).

We add the following to the .htaccess file:

php_value session.gc_maxlifetime 86400
php_value session.cookie_lifetime 0

* as you can see, the parameters are the same as when configured via php.ini.

As mentioned above, the method will not work if Apache is not used. However, the setup can be done on the server (again, we must have the appropriate access).

Open the web server configuration file, for example, in php-fpm:

vi /etc/php-fpm.d/www.conf

and edit/add:

php_value = 86400
php_value = 0

Then we restart the service:

systemctl restart php-fpm || service php-fpm restart

Setting a parameter in application code

The method can be useful when different portal pages should have different session lifetimes. To do this, you can use the PHP functions ini_set and session_set_cookie_params, for example:

Ini_set("session.gc_maxlifetime", 86400);
ini_set("session.cookie_lifetime", 0);
session_set_cookie_params(0);

Session_start();

Functions must be called before opening a session (session_start).

Setting up a session in the application

Some applications may override settings. In this case, you need to set the session lifetime in the program parameters. Each application has its own settings, which you need to figure out yourself. Let's take an example of setting up a session in the Bitrix CMS.

Let's go to Group of users- select a group - Safety. Find the parameter “Session lifetime (minutes)” and set the time, for example 1440 (24 hours in minutes).

How to automatically renew sessions

If a session is issued for a specific period and ends at a specific time, it may result in the user's active session being interrupted. It is much more convenient if the session duration is automatically extended if the visitor refreshes the page. For this, there is the cookie_lifetime parameter, which in all the examples above we set to 0.

If we set the cookie_lifetime value to 86400, then the session will be terminated after 24 hours. This is not always convenient.

If there is a need to control and interrupt the session, you can use the PHP function session_destroy().

Session file storage path

The storage location for session files is specified by the parameter session.save_path also, so is the time of life. By default, the path can be used /var/lib/php/sessions.

This is an important parameter - if the web server does not have write permissions to this directory, this will lead to the inability to store sessions, which will cause unexpected results from applications.

Greetings, dear community.

First of all, I want to thank you for a very useful resource. More than once I have found many interesting ideas and practical advice here.

The purpose of this article is to highlight the pitfalls of using sessions in PHP. Of course, there is PHP documentation and plenty of examples, and this article is not intended to be a complete guide. It is designed to reveal some of the nuances of working with sessions and protect developers from unnecessary waste of time.

The most common example of using sessions is, of course, user authorization. Let's start with the most basic implementation in order to gradually develop it as new tasks arise.

(In order to save space and time, we will limit our examples to only the session functions themselves, instead of building here a full-fledged test application with a beautiful class hierarchy, comprehensive error handling and other good stuff).

Function startSession() ( // If the session has already been started, stop executing and return TRUE // (the session.auto_start parameter in the php.ini settings file must be disabled - the default value) if (session_id()) return true; else return session_start(); // Note: Prior to version 5.3.0, the session_start() function returned TRUE even if an error occurred. // If you are using a version prior to 5.3.0, perform an additional check for session_id() // after calling session_start() ) function destroySession() ( if (session_id()) ( // If there is an active session, delete the session cookies, setcookie(session_name(), session_id(), time()-60*60*24); // and destroy the session session_unset( ); session_destroy(); ) )

Note: It is assumed that the reader has basic knowledge about PHP sessions, so we will not cover the principle of operation of the session_start() and session_destroy() functions here. The tasks of layout of the login form and user authentication are not related to the topic of the article, so we will also omit them. Let me just remind you that to identify the user in each subsequent request, at the moment of successful login, we need to store the user identifier in a session variable (named userid, for example), which will be available in all subsequent requests within the life of the session. It is also necessary to implement processing the result of our startSession() function. If the function returns FALSE, display the login form in the browser. If the function returned TRUE, and a session variable containing the identifier of the authorized user (in our case - userid), exists - display the page of the authorized user (for more information about error handling, see the addition dated 2013-06-07 in the section on session variables).

So far everything is clear. Questions begin when you need to implement user inactivity control (session timeout), enable multiple users to work simultaneously in one browser, and also protect sessions from unauthorized use. This will be discussed below.

Monitoring user inactivity using built-in PHP tools

The first question that often arises among developers of all kinds of consoles for users is automatic termination of the session in the event of inactivity on the part of the user. There is nothing easier than to do this using the built-in capabilities of PHP. (This option is not particularly reliable or flexible, but we will consider it for completeness).

Function startSession() ( // User inactivity timeout (in seconds) $sessionLifetime = 300; if (session_id()) return true; // Set the cookie lifetime ini_set("session.cookie_lifetime", $sessionLifetime); // If user inactivity timeout is set, set the session lifetime on the server // Note: For a production server, it is recommended to preset these parameters in the php.ini file if ($sessionLifetime) ini_set("session.gc_maxlifetime", $sessionLifetime); if (session_start( )) ( setcookie(session_name(), session_id(), time()+$sessionLifetime); return true; ) else return false; )

A few clarifications. As you know, PHP determines which session needs to be launched by the cookie name sent by the browser in the request header. The browser, in turn, receives this cookie from the server, where the session_start() function places it. If the browser cookie has expired, it will not be sent in the request, which means PHP will not be able to determine which session to start and will treat this as creating a new session. The PHP settings parameter session.gc_maxlifetime, which is set equal to our user inactivity timeout, sets the lifetime of a PHP session and is controlled by the server. Controlling the session lifetime works as follows (here we consider an example of storing sessions in temporary files as the most common and default option in PHP).

When a new session is created, a file called sess_ is created in the directory set as the session storage directory in the PHP settings parameter session.save_path , Where - session identifier. Next, in each request, at the time of launching an already existing session, PHP updates the modification time of this file. Thus, in each subsequent request, PHP, by the difference between the current time and the time of the last modification of the session file, can determine whether the session is active or its lifetime has already expired. (The mechanism for deleting old session files is discussed in more detail in the next section.)

Note: It should be noted here that the session.gc_maxlifetime parameter applies to all sessions within one server (more precisely, within one main PHP process). In practice, this means that if several sites are running on the server, and each of them has its own user inactivity timeout, then setting this parameter on one of the sites will lead to its setting for other sites. The same applies to shared hosting. To avoid this situation, separate session directories are used for each site within the same server. Setting the path to the sessions directory is done using the session.save_path parameter in the php.ini settings file, or by calling the ini_set() function. After this, the sessions of each site will be stored in separate directories, and the session.gc_maxlifetime parameter set on one of the sites will only be valid for its session. We will not consider this case in detail, especially since we have a more flexible option for monitoring user inactivity.

Controlling user inactivity using session variables

It would seem that the previous option, for all its simplicity (just a couple of additional lines of code), gives everything we need. But what if not every request can be regarded as the result of user activity? For example, a page has a timer that periodically makes an AJAX request to receive updates from the server. Such a request cannot be regarded as user activity, which means that automatically extending the session lifetime is not correct in this case. But we know that PHP updates the modification time of the session file automatically every time the session_start() function is called, which means that any request will lead to an extension of the session lifetime, and the user inactivity timeout will never occur. In addition, the last note from the previous section about the intricacies of the session.gc_maxlifetime parameter may seem too confusing and difficult to implement for some.

To solve this problem, we will abandon the use of built-in PHP mechanisms and introduce several new session variables that will allow us to control the time of user inactivity ourselves.

Function startSession($isUserActivity=true) ( ​​$sessionLifetime = 300; if (session_id()) return true; // Set the cookie lifetime before closing the browser (we will control everything on the server side) ini_set("session.cookie_lifetime", 0) ; if (! session_start()) return false; $t = time(); if ($sessionLifetime) ( // If the user inactivity timeout is set, // check the time elapsed since the last user activity // (last request time when the lastactivity session variable was updated) if (isset($_SESSION["lastactivity"]) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( // If the time elapsed since the user's last activity, / / is greater than the inactivity timeout, which means the session has expired and you need to terminate the session destroySession(); return false; ) else ( // If the timeout has not yet occurred, // and if the request came as a result of user activity, // update the lastactivity variable with the value of the current one time, // thereby extending the session time by another sessionLifetime seconds if ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) return true; )

Let's summarize. In each request, we check whether the timeout has been reached since the last user activity until the current moment, and if it has been reached, we destroy the session and interrupt the execution of the function, returning FALSE. If the timeout has not been reached, and the $isUserActivity parameter with the value TRUE is passed to the function, we update the time of the user’s last activity. All we have to do is determine in the calling script whether the request is the result of user activity, and if not, call the startSession function with the $isUserActivity parameter set to FALSE.

Update from 2013-06-07
Processing the result of the sessionStart() function

The comments pointed out that returning FALSE does not provide a complete understanding of the cause of the error, and this is absolutely fair. I did not publish detailed error handling here (the length of the article is already quite large), since this is not directly related to the topic of the article. But given the comments, I’ll clarify.

As you can see, the sessionStart function can return FALSE in two cases. Either the session could not be started due to some internal server errors (for example, incorrect session settings in php.ini), or the session lifetime has expired. In the first case, we must redirect the user to a page with an error stating that there are problems on the server and a form for contacting support. In the second case, we must transfer the user to the login form and display a corresponding message in it stating that the session has expired. To do this, we need to enter error codes and return the corresponding code instead of FALSE, and in the calling method, check it and act accordingly.

Now, even if a session on the server still exists, it will be destroyed the first time it is accessed if the user's inactivity timeout has expired. And this will happen regardless of what session lifetime is set in the global PHP settings.

Note: What happens if the browser was closed and the session name cookie was automatically destroyed? The request to the server the next time the browser is opened will not contain the session cookie, and the server will not be able to open the session and check the user's inactivity timeout. For us, this is equivalent to creating a new session and does not affect functionality or security in any way. But a fair question arises - who will then destroy the old session, if until now we have destroyed it after the timeout has expired? Or will it now hang in the sessions directory forever? To clean up old sessions in PHP, there is a mechanism called garbage collection. It runs at the time of the next request to the server and clears all old sessions based on the last modification date of the session files. But the garbage collection mechanism does not start with every request to the server. The frequency (or rather, the probability) of launching is determined by two settings parameters session.gc_probability and session.gc_divisor. The result of dividing the first parameter by the second is the probability of launching the garbage collection mechanism. Thus, in order for the session clearing mechanism to be launched with each request to the server, these parameters must be set to equal values, for example “1”. This approach guarantees a clean session directory, but is obviously too expensive for the server. Therefore, on production systems, the default value of session.gc_divisor is set to 1000, which means that the garbage collection mechanism will run with a probability of 1/1000. If you experiment with these settings in your php.ini file, you may notice that in the case described above, when the browser closes and clears all its cookies, there are still old sessions left in the sessions directory for a while. But this should not worry you, because... as already stated, this does not in any way affect the safety of our mechanism.

Update from 2013-06-07

Preventing scripts from freezing due to session file locking

The comments raised the issue of simultaneously running scripts freezing due to the session file being blocked (the most striking option is long poll).

To begin with, I note that this problem does not directly depend on the server load or the number of users. Of course, the more requests, the slower the scripts are executed. But this is an indirect dependence. The problem appears only within one session, when the server receives several requests on behalf of one user (for example, one of them is long poll, and the rest are regular requests). Each request tries to access the same session file, and if the previous request did not unlock the file, then the subsequent one will hang waiting.

To keep session file locking to a minimum, it is strongly recommended to close the session by calling the session_write_close() function immediately after all actions with session variables have been completed. In practice, this means that you should not store everything in session variables and access them throughout the execution of the script. And if you need to store some working data in session variables, then read them immediately when the session starts, save them in local variables for later use and close the session (meaning closing the session using the session_write_close function, and not destroying it using session_destroy).

In our example, this means that immediately after opening a session, checking its lifetime and the existence of an authorized user, we must read and save all additional session variables required by the application (if any), then close the session using a call to session_write_close() and continue execution of a script, be it a long poll or a regular request.

Protecting sessions from unauthorized use

Let's imagine the situation. One of your users gets a Trojan that robs the browser cookies (in which our session is stored) and sends it to the specified email. The attacker obtains the cookie and uses it to spoof a request on behalf of our authorized user. The server successfully accepts and processes this request as if it came from an authorized user. If additional verification of the IP address is not implemented, such an attack will lead to a successful hacking of the user's account with all the ensuing consequences.

Why was this possible? Obviously, because the name and session identifier are always the same for the entire lifetime of the session, and if you receive this data, you can easily send requests on behalf of another user (of course, within the lifetime of this session). This may not be the most common type of attack, but theoretically it seems quite feasible, especially considering that such a Trojan does not even need administrator rights to rob the user's browser cookies.

How can you protect yourself from attacks of this kind? Again, obviously, by limiting the lifetime of the session identifier and periodically changing the identifier within the same session. We can also change the name of the session by completely deleting the old one and creating a new session, copying all the session variables from the old one into it. But this does not affect the essence of the approach, so for simplicity we will limit ourselves to only the session identifier.

It is clear that the shorter the session ID lifetime, the less time an attacker will have to obtain and use cookies to forge a user request. Ideally, a new identifier should be used for each request, which will minimize the possibility of using someone else's session. But we will consider the general case when the session identifier regeneration time is set arbitrarily.

(We will omit the part of the code that has already been discussed).

Function startSession($isUserActivity=true) ( ​​// Session identifier lifetime $idLifetime = 60; ... if ($idLifetime) ( // If the session identifier lifetime is set, // check the time elapsed since the session was created or the last regeneration // (time of the last request when the session variable starttime was updated) if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $idLifetime) ( // Time the life of the session identifier has expired // Generate a new identifier session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( // We get here if the session has just been created // Set the time for generating the session identifier to the current time $_SESSION["starttime"] = $t; ) ) return true; )

So, when creating a new session (which occurs when the user successfully logs in), we set the session variable starttime, which stores for us the time of the last generation of the session identifier, to a value equal to the current server time. Next, in each request, we check whether enough time (idLifetime) has passed since the last generation of the identifier, and if so, we generate a new one. Thus, if during the set lifetime of the identifier the attacker who received the cookie of the authorized user does not have time to use it, the fake request will be regarded by the server as unauthorized, and the attacker will be taken to the login page.

Note: The new session ID gets into the browser's cookie when the session_regenerate_id() function is called, which sends the new cookie, similar to the session_start() function, so we don't need to update the cookie ourselves.

If we want to make our sessions as secure as possible, it is enough to set the lifetime of the identifier to one or even remove the session_regenerate_id() function from brackets and remove all checks, which will lead to the regeneration of the identifier in each request. (I have not tested the impact of this approach on performance, and I can only say that the session_regenerate_id(true) function essentially performs only 4 actions: generating a new identifier, creating a header with the session cookie, deleting the old one and creating a new session file).

Lyrical digression: If the Trojan turns out to be so smart that it will not send cookies to the attacker, but organizes the sending of a pre-prepared fake request immediately upon receiving the cookie, the method described above will most likely not be able to protect against such an attack, because between the time the Trojan receives the cookie and the sending of the fake request there will be practically no difference, and there is a high probability that at this moment the session identifier will not be regenerated.

Possibility of simultaneous work in one browser on behalf of several users

The last task that I would like to consider is the ability for several users to work simultaneously in one browser. This feature is especially useful at the testing stage, when you need to emulate the simultaneous work of users, and it is advisable to do this in your favorite browser, rather than using the entire available arsenal or opening several instances of the browser in incognito mode.

In our previous examples, we did not explicitly specify a session name, so the default PHP name (PHPSESSID) was used. This means that all the sessions we have created so far have sent a cookie to the browser under the name PHPSESSID. Obviously, if the cookie name is always the same, then there is no way to organize two sessions with the same name within the same browser. But if we used our own session name for each user, the problem would be solved. Let's do so.

Function startSession($isUserActivity=true, $prefix=null) ( ... if (session_id()) return true; // If the user prefix is ​​passed in the parameters, // set a unique session name that includes this prefix, // otherwise set common name for all users (for example, MYPROJECT) session_name("MYPROJECT".($prefix ? "_".$prefix: "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) return false; ... )

Now all that remains is to make sure that the calling script passes a unique prefix for each user to the startSession() function. This can be done, for example, by passing a prefix in the GET/POST parameters of each request or through an additional cookie.

Conclusion

In conclusion, I will provide the complete final code of our functions for working with PHP sessions, including all the tasks discussed above.

Function startSession($isUserActivity=true, $prefix=null) ( $sessionLifetime = 300; $idLifetime = 60; if (session_id()) return true; session_name("MYPROJECT".($prefix ? "_".$prefix: "")); ini_set("session.cookie_lifetime", 0); if (! session_start()) return false; $t = time(); if ($sessionLifetime) ( if (isset($_SESSION["lastactivity"] ) && $t-$_SESSION["lastactivity"] >= $sessionLifetime) ( destroySession(); return false; ) else ( if ($isUserActivity) $_SESSION["lastactivity"] = $t; ) ) if ($idLifetime ) ( if (isset($_SESSION["starttime"])) ( if ($t-$_SESSION["starttime"] >= $idLifetime) ( session_regenerate_id(true); $_SESSION["starttime"] = $t; ) ) else ( $_SESSION["starttime"] = $t; ) ) return true; ) function destroySession() ( if (session_id()) ( session_unset(); setcookie(session_name(), session_id(), time() -60*60*24); session_destroy(); ) )

I hope this article will save some time for those who have never delved too deeply into the session mechanism, and give enough insight into this mechanism for those who are just starting to get acquainted with PHP.

HTTP is a stateless protocol. This means that the user sends a request, the server responds to that request without remembering the request later. In order to track important information (for example, user preferences, user actions, etc.), cookies are created on the website using PHP. In this article, I'm going to talk about how to work with cookies, how they need to be created, what parameters they have, and how you can delete them.

What is Cookie?

Cookies are very useful for storing information directly in the user's browser itself. This is a simple text file that stores a maximum of 4kb of data.

Cookies are created by the browser at the request of the server (in accordance with the program logic). After a cookie is created on the user's side, his browser sends this information (from the cookie) back to the server using an HTTP header.

Logins, passwords, etc. are often stored in cookies. For example, you go to the site, enter your username and password. The site automatically creates cookies for you with this data. And the next time you visit the site, it simply checks for the presence of cookies and loads the user data saved in them.

//An example of an index page for such a site if($_COOKIE["login"])( header("location: /lk/index.php?login=".$_COOKIE["login"]);//Will transfer directly to your personal account ) //Next is, for example, a login and registration form

Why Cookie?

HTTP is a stateless protocol, so there is no way to keep track of a user's previous actions on a site. Cookies are the best way to store data. I know everything about wish cookies, which you break, and inside there is a piece of paper with what might happen to you in the future. As for me, this is where the legs grow, regarding the name.

PHP Cookies

Actually, since I already explained what it is, let's find out how to set cookies in PHP.

We use the SetCookie() method to set cookies in the user's browser.

Syntax for setting cookies in PHP

Setcookie(name, val, time, path, domain, secure);

name - Specifies the name of the cookie.

val - The value we want to store in the cookie. A cookie always stores a string value.

time (optional) - Set the cookie expiration time. If this field is empty, the cookies will be deleted when the browser is closed.

domain (optional field) - Set the domain in which the cookie is available. If you want to set a cookie for multiple subdomains, then use the main domain name with a dot as a prefix.

For example:

Let my.com have several subdomains such as tech.my.com, only.my.com. And I want the cookie set in my.com to be available to all my subdomains, then I set the domain as.my.com.

secure(optional) - This determines whether the cookie should be sent over a secure connection using HTTPS. Default is set to FALSE. If this is set to true, then this means that the cookie will be installed only if a secure connection exists, and it is logical that it will not be created with HTTP.

Setcookie("login","valera123");

Using the script above, we will create a cookie with the name login and the value valera123.

Note: Cookies can only store string values. They can't store an array. In order to store an array in cookies, you need to first convert them to a string. I will definitely tell you about this later.

Note: As you noticed, I did not set the lifetime of our cookie. This is why it will disappear after our browser is closed...

Using the SetCookie() method, our cookie will be set. After your script with the specified method has been executed, you can easily check the cookie in the developer panel in Chrome, or in the firebug in Firefox.


We have not defined a cookie expiration time. Let's give her 30 days. In this case, we must mention time. After that, it will live for 30 days until the user deletes it manually.

Setcookie("login","valera123",time()+3600*24*30);

3600 - 1 hour
24 - day
30 days

How to set cookies for subdomains

setcookie("login","valera123",time()+3600*24*30,"/",".my.com");

Well, actually this example has already been given

How to get cookie value in PHP

$_COOKIE - used to get the value of a cookie. Below is the code on how exactly you can get the value of the cookie that was installed earlier.

$val = $_COOKIE["login"]; echo $val; //Output valera123

How to remove Cookie in PHP

To remove cookies in PHP, set the tense to negative (past tense).

Setcookie("login","valera123",time()-3600*24);

So what happens if we set the time to negative. In this case, the cookie expires automatically.

Important points about Cookies

1. A cookie can store a maximum of 4 KB of data.

2. It can only store strings.

3. Cookies can only be accessed by the browser that sets them. Cookies installed in the Chrome browser cannot be accessed in the Mozilla browser, or any other browser.

4. Try to avoid storing confidential and highly sensitive data in cookies.

Actually, that's all. I really hope that you liked this line, share your opinion in the comments, and don’t forget to repost.

Well, let's figure it out.

First, read about HTTP on the same wiki. You don’t need to know it thoroughly, but you should have a minimal understanding of the request/response structure, understand that the request and response have headers and a body (there may not be a body, depending on the type of request/response).

So here it is. Cookies. Cookies live on the browser side. They are transmitted in the HTTP header for every request to the server (even if you went to get the pictures). There are just cookies, there are http-only cookies. Cookies can be separated by host and path. All this gives us flexibility and helps with security. In PHP, the contents of $_COOKIE are provided to us by SAPI. When PHP receives a request for processing, the SAPI used (php-fpm, cgi, mod_php have their own SAPI implementations) currently takes the headers and body of the request, parses them and fills all these superglobal arrays like $_SERVER, $_GET, etc. $_COOKIE. Everything that the client sent us (something that makes requests is the client, something that processes them is the server), and the browser sends us cookies only those that are possible based on where the request is sent. Cookies are set using the Set-Cookie header in the response, that is, here you need to read more about HTTP and not about PHP. PHP just lets you work with this stuff. You can set cookies directly by working with response headers using the header function. Moreover, if you set the lifetime of cookies to 0, then they, and not the session, will be reset when the browser is closed, since it will forget all such cookies.

Here... sessions... In PHP, a session is usually a file. Just some file with a random name. If, say, session.autostart is specified in php.ini or a session_start call is made, then a file is created for the user session (you can move it to Radish or Memcache, your storage, etc., depending on your needs. The data can also be encrypted, which is what happens by default ). This file has an ID, just some random string. And if, when processing a request, a session from the previous request was not found, a new one is created.

And now we come to the most interesting thing - how PHP connects the session from the previous request with the current one. And here everything is quite simple - cookies. When a user is assigned a session, an http-only cookie is automatically set (so that bad people can’t steal our session from js) in which the session identifier is written. In the browser debugger, you can see if you have a PHPSESSID cookie (the name can be changed in the settings, and in general, sessions can be linked not only through cookies, but these are already security issues) when you experiment with sessions.

When a request is processed by SAPI, if session.autostart is present, before starting to create a new session, puff still looks to see if we have a cookie with a session identifier, checks whether it has one, and if it does, it calms down and does not create a new one. Since the session is bound through cookies, you can set the lifetime of this cookie itself (in php.ini) and thus regulate the lifetime of the session.

Here... when to use cookies and when to use sessions? It is advisable to understand that the more data there is in cookies (and they have a word limit), the more data we transfer for each request. That is, it’s not cool when, in order to get 1 kilobyte of data, we must transfer a couple of kilobytes of cookies in the headers. People who are focused on optimization even store images on separate cookie-less domains to reduce the amount of traffic and packets (usually a simple HTTP request fits into the size of one TCP packet). If you need to work with this data from JS on any page, for example, the locale selected by the user in order to apply translations in JS, then you should use cookies. For everything else, it’s better to use sessions, of course. In any case, in the initial stages, when you don’t have to do anything very complicated.

The web server does not maintain a permanent connection with the client, and each request is processed as a new one, without any connection with the previous ones.
That is, you can neither track requests from the same visitor nor save variables for him between views of individual pages. It was to solve these two problems that sessions were invented.
Actually, sessions, in a nutshell, are a mechanism that allows you to uniquely identify a browser and creates a file for this browser on the server in which session variables are stored.

I will not describe in detail the need for such a mechanism. These are textbook cases such as a shopping cart in an e-store, authorization, as well as not entirely trivial problems, such as protecting interactive parts of a site from spam.

In principle, it’s quite easy to make your own analogue of sessions, not as functional as the one built into PHP, but similar in essence. On cookies and database.
When requesting a script, we look to see if a cookie with a specific name was received. If there is no cookie, then set it and write a new line with user data to the database. If there is a cookie, then we read the data from the database. With another request we delete old records from the database and now we have a session mechanism ready. It's not difficult at all. But there are some nuances that make it preferable to use the built-in session mechanism.

If only the first one is enabled, then at the start of the session (every call session_start()) a cookie is set for the client. The browser correctly returns this cookie with each subsequent request and PHP has a session identifier. Problems begin if the browser does not return cookies. In this case, without receiving a cookie with an identifier, PHP will always start a new session and the mechanism will not work.

If only the second one is enabled, then the cookie is not set. And this is what happens, for the sake of which, in fact, it is worth using the built-in session mechanism. After the script does its job and the page is completely formed, PHP scans the entire page and adds a session identifier to each link and to each form. It looks something like this:
Index turns into
Index
and a hidden field is added to the forms

And the browser, when you click on any link, or when you click on a button in the form, will send in the request the variable we need - the session identifier!
For obvious reasons, the identifier is only added to relative links.

Theoretically, in our homemade sessions on cookies and the database, we can manually assign ID transfer to all links - and then our own sessions will work regardless of cookies. But would you agree - it’s more pleasant when someone else does this work? ;-)

By default, both options are enabled in recent versions of PHP. How does PHP handle this? Cook is always exhibited. And links are autocompleted only if PHP did not detect a cookie with a session identifier. When a user visits the site for the first time during this session, a cookie is placed and the links are completed. On the next request, if cookies are supported, PHP sees the cookie and stops completing links. If cookies do not work, then PHP continues to properly add id to links, and the session is not lost.
Users with cookies enabled will only see the long link with the ID once.

Phew. The ID transfer is complete.
Now all that remains is to bind the data file to it on the server side.
PHP will do this for us. It's enough just to write
session_start();
$_SESSION [ "test" ]= "Hello world!" ;

And PHP will write the test variable to the file associated with this session.
There is a very important note here.
Array $_SESSION- special.
In fact, it contains the variables that we want to make available in various scripts.
To place a variable in a session, just assign it to the $_SESSION array element.
To get its value, just access the same element. An example will be below.

PHP also handles garbage collection - removing outdated files. As well as data encoding and a bunch of other necessary things. As a result of this care, working with sessions is very simple.
Here we actually come to the example of how sessions work.
A very small example:
session_start();

echo "You have updated this page". $_SESSION["counter"]++. " once. " ;
echo "
update" ;
?>

We check whether we have a counter variable in the session; if not, then we create it with the value 0, and then display its value and increase it by one. The increased value will be written to the session, and the next time the script is called, the variable will have the value 1, and so on.
Everything is very simple.

In order to have access to session variables on any pages of the site, you need to write ONLY ONE (!) line at the very beginning of EVERY file in which we need sessions:
session_start();
And then access the elements of the $_SESSION array. For example, an authorization check would look something like this:
session_start();
if ($_SESSION [ "authorized" ]<> 1 ) {
header("Location: /auth.php");
exit;
}

Removing variables from a session.
If you have register_globals=off , then just write
unset($_SESSION [ "var" ]);
If not, then near I need to write with her
session_unregister("var");

The most common errors that PHP produces when trying to work with sessions are the following:
Two of them
Warning: Cannot send session cookie - headers already sent
Warning: Cannot send session cache limiter - headers already sent

caused by the same reason, the solution is described in this thread
Third,
Warning: open(/tmp\sess_SID, O_RDWR) failed: No such file or directory (2) in full_script_path on line number(previously she looked like Warning: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/tmp)),
if translated from English, it explains the problem in detail: the path to the directory specified in php.ini where session files are written is not available. This error is the easiest to fix. Just register a directory that exists and is writable, for example,
session.save_path = c:\windows\temp
And don't forget to restart Apache after this.

As it turns out, human intelligence has no limits, and therefore I am forced to explain:
a message about the third error (the directory cannot be found) will INEVITABLY lead to the appearance of the first two, since the error message is output to the browser and headers after it cannot be used. Therefore, do not rush to look for a premature conclusion, but first write down the right path!

The next most common problem when working with sessions is the heavy legacy of register_globals. DO NOT give script variables names that match the indices of the $_SESSION array!
With register_globals=on the values ​​will overwrite each other and you will get confused.
And if register_globals=off, another error will appear: “Your script possibly relies on a session side-effect which existed until PHP 4.2.3.”, if the script has a session variable that has no value, and a global variable with the same name . To get rid of it, you must always initialize variables before use (or at least check for existence) and do not give global variables names that coincide with the indexes of the $_SESSION array.

If it doesn’t work, but no messages are displayed, then add two lines at the very beginning of the script responsible for displaying ALL errors on the screen - it’s quite possible that there are errors, but you just don’t see them.
ini_set("display_errors" , 1 );
error_reporting(E_ALL);

or see errors in error_log. In general, the topic of displaying error messages is beyond the scope of this article, so just make sure that you can at least see them. You can read a little more about finding errors in this section.

If you are sure that there are no errors, but the example given does not work anyway, then perhaps PHP does not enable passing id via URL, and cookies for some reason do not work.
Look what's wrong with your cookies.
In general, if your sessions are not working, then first try passing the session identifier manually, that is, make a link and assign an identifier to it:
session_start();
if (!isset($_SESSION [ "counter" ])) $_SESSION [ "counter" ]= 0 ;
echo "You have updated this page". $_SESSION["counter"]++. " once.

update" ;
?>

However, you should make sure that the session.use_only_cookies directive is not enabled, which prevents PHP from accepting the session ID if it was passed via URL

If this example does not work, then the problem is either in trivial typos(half of the “problems” with sessions come from a misspelled variable name), or in a too old version of PHP: support for sessions appeared in version 4.0, and the array $_SESSION- in 4.1 (Before this it was used $HTTP_SESSION_VARS).
If it works, then the problem is in the cookies. Monitor what kind of cookie the server sets to the browser, and whether the browser returns it. It is very useful to search by looking at the exchange of HTTP headers between the browser and the server.
An explanation of how cookies work is beyond the scope of this already too long text, but at least make sure that the server sends a cookie with an identifier, and the browser returns it. And at the same time the identifiers coincide with each other =)
Setting the cookie should look like
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6;
or how
Set-Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; path=/
(if you are requesting the script not from the root directory)
The server response should look like
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6
or
Cookie: PHPSESSID=prlgdfbvlg5fbsbshch6hj0cq6; b=b
if the browser returns cookies other than the session ID.

If the browser does not return cookies, check whether the cookies work at all.
Make sure that the domain you are accessing has a normal name (with at least one dot and no illegal characters such as underscores) and clear your browser cache - these are two main reasons why cookies may not work.

If the example from here works, but your own code doesn't, then the problem is obviously not in the sessions, but in the algorithm. Look for where you lost the variable, transfer the example from here step by step, and debug your script.

Another problem can arise if you use header redirection or JavaScript navigation.
The fact is that PHP automatically appends the session identifier only to links like
, but does not do this for headers, JavaScript, meta tags.
Therefore, you need to add the identifier manually, for example, like this:
header("Location: /script.php?" . session_name(). "=" . session_id());

Also, a very rare problem, and it is completely unclear where it comes from, is that the session.save_handler setting has a value different from files. If this is not so, correct it.

Safety
Session security is a broad topic. Therefore, I will focus on a few main points.
The most textbook one is not to pass the identifier through the address bar. This is written even in php.ini, but this limits the functionality of sessions. If you decide to follow this advice, then in addition to session.use_trans_sid = 0, do not forget session.use_only_cookies = 1
It is advisable to bind the session to an IP address: this way, if the identifier is stolen, the villain will still not be able to use it in most cases.
It is recommended to use the session.save_path directive, which allows you to set your own directory for saving session files. This is more secure than having them stored in the server's default shared temporary directory.

Additional Information:

  • In addition to cookies, the session mechanism also sends headers that prohibit page caching (the same cache limiter). For html this is correct and necessary. But when you try to send a file using a script that checks authorization, Internet Explorer refuses to download it. It's because of this title. Call
    session_cache_limiter("private");
    must solve the problem before starting the session.
  • Strange as it may seem, but in the array $_SESSION You can't use numeric indexes - $_SESSION [ 1 ], $_SESSION [ "10" ]- sessions will not work.
  • Somewhere between versions 4.2 and 5.0 it was not possible to set session.use_trans_sid using ini_set(). Starting from 5.0 it is already possible again.
  • Before version 4.3.3 of the cookie, PHP sent a cookie only if there was no identifier in the request when the session started. Now a cookie is sent on every call session_start()

    Example of authorization using sessions
    Let's illustrate all of the above with a small example:
    Let's create the auth.php file:
    if (isset($_POST [ "auth_name" ]))
    {
    $sql = "SELECT * FROM users WHERE name=?s";
    $row = $db -> getRow($sql, $_POST["auth_name"]);
    if ($row && password_verify ($_POST [ "auth_pass" ], $row [ "pass" ])) (
    $_SESSION [ "user_id" ] = $row [ "id" ];
    }
    header("Location: http://" . $_SERVER [ "HTTP_HOST" ]. $_SERVER [ "REQUEST_URI" ]);
    exit;
    }

    if (isset($_GET [ "action" ]) AND $_GET [ "action" ]== "logout" ) (
    session_start();
    session_destroy();
    header("Location: http://" . $_SERVER [ "HTTP_HOST" ]. "/" );
    exit;
    }

    if (!isset($_SESSION [ "user_id" ])) (
    ?>








    exit;
    }

    Now all you need to do is write the line in all protected scripts
    require "auth.php" ;
    This example assumes that the session has already started and a connection to the database has been created using the Class for safe and convenient work with MySQL. It also assumes that the password is hashed using the recommended password_hash function.
    Example of a protected file:

    session_start();
    include "safemysql.class.php" ;
    $db = new safemysql ([ "db" => "test" ]);
    include "auth.php" ;
    ?>
    secret

    logout

    OPS! Very Useful Links:
    http://www.php.net/manual/ru/ref.session.php - the latest and most recent information about session support in PHP in the official documentation, plus numerous user comments. Highly recommended reading.
    http://phpclub.ru/manrus/f/ref.session.html - A VERY outdated translation of this chapter into Russian, from the documentation translated by Alexander Pyramidin.
    http://phpclub.ru/detail/article/sessions
    An article with the pathetic title “The Truth about Sessions.” Leaves an ambivalent impression. At the beginning, the author talks VERY clearly about the session mechanism, but the methods he offers by the end of the article are completely unclear.

    A textbook article by Dmitry Borodin from the site
    http://php.spb.ru/ is strongly NOT recommended.
    Guys, it's terribly outdated. Not only does it contain factual inaccuracies, but sessions in PHP simply haven’t worked for a long time.
    Many thanks to Dima for it, this was the first article on the sessions in Russian, I studied from it myself, but now I need to send it to a well-deserved rest.
    Also, unfortunately, many other articles that are on the Internet and have not been updated for years are also outdated.