I would like to know if there is a way to prevent PHP from sending a cookie when calling session_start().
My use case is for a site optimisation:
(1a) I first open a session/send headers.
(1b) Then generate and output some text content.
(1c) To enhance session read/write I call "session_write_close" as soon as I don't need to write in the session anymore.
(2) Finally I have a post-page rendering process (for stats) that requires a write access to the session. The session is closed, I cannot call session_start() again since it sends a cookie and it's to late for that. This is a computation-heavy process, so I have to do it after the page is sent to the client.
The client already received a session-cookie. So I don't need session_start() to send a new (and redundant) one.
Does someone know a way to intercept the cookie or something similar ? Of course I want to avoid the "Cannot send session cookie - headers already sent". This error is invisible for the user because the page is already renderered but it looks ugly in the logs.
My question seems to be a redundant one, but it is not. I know how headers and content work (send headers first, content after). It's just that PHP does not let me do what I want.
I would like to know if there is a way to prevent PHP from sending a cookie when calling session_start().
Yes there is, by telling PHP to not use cookies for sessions. The PHP setting is session.use_cookies:
ini_set('session.use_cookies', 0); # disable session cookies
session_start();
By default cookies are enabled because they are considered more safe then using URL parameters (see Sessions and securityDocs).
(2) Finally I have a post-page rendering process (for stats) that requires a write access to the session. The session is closed, I cannot call session_start() again since it sends a cookie and it's to late for that. This is a computation-heavy process, so I have to do it after the page is sent to the client.
It's probably possible to tell PHP that the cookie is already set by adding it into the $_COOKIE superglobal arrayDocs. I never experimented with it, but in case you use session_start() and PHP sees that the session cookie has been already set (by the browser, not PHP, $_COOKIE represent the browser cookies), it won't send the headers (again) to set the cookie (which as I understand you is what you want).
Edit: Some test script to play around with:
<?php
header('Content-Type: text/plain;');
echo "Incomming Cookies:\n";
print_r($_COOKIE);
// to simulate that this is a new session, the session cookie is removed
// which makes PHP think it is a new session when invoking session_start()
// unset($_COOKIE['PHPSESSID']);
// run the first session
session_start(); // creates the session cookie (as we don't have one yet)
printf("Session %s has been started: %s\n", session_name(), session_id());
var_dump($_SESSION);
$_SESSION['variable'] = isset($_SESSION['variable']) ? $_SESSION['variable']++ : 0;
session_commit();
printf("Session has been closed, remaining id is: %s\n", session_id());
// visual confirmation that session cookie has been created
echo "Outgoing Cookies:\n";
print_r(headers_list());
// run the second session
ini_set('session.use_cookies', 0); # disable session cookies
session_start();
printf("Second session %s has been started: %s\n", session_name(), session_id());
var_dump($_SESSION);
$_SESSION['2nd-variable'] = isset($_SESSION['2nd-variable']) ? $_SESSION['2nd-variable']++ : 0;
session_commit();
You need to call it with a web-browser (and PHP sessions must be configured to work).
I thought I should mention another great way to prevent the cookie (and the cache limiter) headers from being sent when calling session_start.
The session_start call takes an options array where you can set any of the session. prefix variables, and you can disable these things for just that call.
session_start(array(
'use_cookies' => '0',
'cache_limiter' => ''
));
Note that use_cookies keeps the cookie from being sent, and setting the cache limiter to an empty string keeps it from updating the cache headers (not the best documented feature).
Here are two notices that this will fix (this is helpful when you need to work through multiple sessions).
Warning: session_start(): Cannot send session cookie - headers already sent
and
Warning: session_start(): Cannot send session cache limiter - headers already sent
You can use ob_start() function to buffer the headers/content, you may clear the buffer contents using ob_clean()
Related
on every page (first lines, first code) I have those two lines of code:
define("DIRECT_ACCESS", true);
defined("DIRECT_ACCESS") OR die(header("Location: https://website.com/"));
after those two lines of code, I always do session_start();, I read that session_start() should come as a first thing, before anything. Session_status() shows that session is active and working properly, so I have a couple of questions:
1. Why does the session work if it should be the first line, before other code?
2. Is there anything dangerous that can happen, could something stop working later if I don't put session_start() as the first line of code?
Thanks for your time trying to help me.
I read that session_start() should come as a first thing, before anything.
That statement is basically wrong.
There're a few things to take into account when initialising sessions:
With the default (and recommended) settings, session ID is transmitted through a cookie. Server-side cookies are set through HTTP headers. HTTP headers need to be sent before response body. Thus you need to avoid constructs like this:
echo 'Hello, World!';
session_start();
You cannot use session data before it's retrieved from the persistent storage. That's precisely what session_start() does. So you cannot do this:
$user_name = $_SESSION['user_name'];
session_start();
Some times you may want to close the session in order to unlock the storage. You do that with session_write_close(). Once you do that, session data remains loaded but changes won't persist. So please avoid:
session_write_close();
$_SESSION['user_name'] = 'john.doe';
Other than that, you're free to start sessions whenever you see fit.
my code is simple:
<?php
session_start();
session_regenerate_id();
?>
When the first time I request this page, the HTTP request with no cookie, then it will response with two 'set-cookie:PHPSESSID=xxxxxx'
Then I thought that I may write code like this:
<?php
session_start();
if(!empty($_SERVER['HTTP_COOKIE'])){
session_regenerate_id();
}
?>
While then, whether my HTTP request with cookie: PHPSESSID=xxxxxx or not, it will responses with only one 'set-cookie:PHPSESSID=xxxxxx'
However, my solution is very awkward.
Any professional PHPer can tell me, how to write a professional code to handle the problem which is the HTTP request may with cookie 'PHPSESSID' or without cookie 'PHPSESSID'.
Have a look at session_start()
session_start() creates a session or resumes the current one based on a session identifier passed via a GET or POST request, or passed via a cookie.
So when you not want that PHPSESSION-Cookie you need to remove session_start()
Set cookie with setcookie('cookie_name', 'some_value') and then get the cookie with $_COOKIE['cookie_name']. Check difference for cookie and session so you are sure you need a cookie for your operation :)
This is a small test. I set a cookie and then try to access it:
<?php
setcookie("t",0,time()+900);
echo ($_COOKIE['t']+10);
setcookie("t",0,time()-3600);
?>
When I run the code I get an error message as below:
Notice: Undefined index: t in /var/www/x/testcookie.php on line 5
10
Why can't I access the cookie?
It doesn't work that way. setcookie just says "with next http connection tell client (browser) to set this cookie. The browser sends it back in next http connection, if it has not expired yet. Only then it is contained in $_COOKIE array. So you can check that it is set in PHP after next page reload.
Besides in your code second cookie will not be set, because you outputted something to the browser which is forbidden before setcookie function (any header function).
setcookie() defines a cookie to be sent along with the rest of the HTTP headers. Like other headers, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.
Once the cookies have been set, they can be accessed on the next page
load with the $_COOKIE
you need understand how cookies works. with setcookie you sent header to browser, which tells browser to store cookie. And $_COOKIE superglobal contains cookies which comes from user request headers. so it means that variable which you set with setcookie only be available in $_COOKIE array after refresh, when it comes back with user request headers. And remember that set headers you can only before any output, so second setcookie will not work.
I am trying to setup a session management with cookies in PHP.
My code is as follows:
if(empty($_COOKIE )) {
setcookie('session_id', md5(uniqid()), time()+(EXPIRE CONSTANT));
}
$session_id = isset($_COOKIE['session_id']) ? $_COOKIE['session_id'] : 0;
I will then check session_id for 0 and print an error message if cookies are disabled.
This works fine if cookies are really disabled.
The problem is, if a user clears his history the first time he visits
the site he will get the error message even if cookies are enabled.
Anyone have any clues about this ?
Thank you in advance
When you do the setcookie call, the cookies will be sent when the header is output to the browser. This means the cookie won't be available until the next page load (when the client sends the cookie back to the server). This is mentioned in the php manual for setcookie http://php.net/manual/en/function.setcookie.php:
setcookie() defines a cookie to be sent along with the rest of the HTTP headers. Like other headers, cookies must be sent before any output from your script (this is a protocol restriction). This requires that you place calls to this function prior to any output, including and tags as well as any whitespace.
Once the cookies have been set, they can be accessed on the next page load with the $_COOKIE or $HTTP_COOKIE_VARS arrays. Note, superglobals such as $_COOKIE became available in PHP 4.1.0. Cookie values also exist in $_REQUEST.
You won't be able to determine if cookies are enabled/disabled until the page has reloaded (from php). I think you'll have to do this check with javascript, or to stay in php do a redirect after setting the cookie for the first time, something like:
if(empty($_COOKIE)) {
if (isset($_GET['cookieset'])) {
// do error message, cookie should be set
}
setcookie('session_id', md5(uniqid()), time()+(EXPIRE CONSTANT));
header('location: http://mysite.com/index.php?cookieset=1');
exit;
}
$session_id = isset($_COOKIE['session_id']) ? $_COOKIE['session_id'] : 0;
#bencoder : I have done the test on iPad and Chrome/PC : you are right for iPad, you do need to refresh the page before you can read the cookie data, but on Chrome/PC, after deleting all cookies, if you set a new one from PHP, you can perfectly get the values directly on the first page load. Why ? There must be a more precise explanation. Why two different behaviors? Does the order of this output/availability of the data depend on the browser request to the server? Interesting to know...
I am trying to set a cookie for a site if it does not exist. It is not working.
if(isset($_COOKIE['about'])){
$_COOKIE['about'] += 1;
}
if(!isset($_COOKIE['about'])){
setcookie("about", 1, time()+3600);
}
I have also tried
if(empty($_COOKIE['about'])){
setcookie("about", 1, time()+3600);
}
The $_COOKIE superglobal is only available for you to read values from. Writing to it does not update the cookie, since that requires a new Cookie header to be sent to the browser. You would probably be better served by sessions backed by cookies, since PHP allows you to modify the session without explicitly saving/setting the cookie.
You can only read stuff from the $_COOKIE superglobal, try setting it normally:
setcookie("about",$_COOKIE['about']+1,time()+3600);
So all together:
if(isset($_COOKIE['about'])){
$_COOKIE['about'] += 1;
}else{
setcookie("about", 1, time()+3600);
}
Note the else, you've checked before if the cookie isset, so there is no need to check again as either it is or it isn't.
Make sure you have not sent any information to the user yet as the setcookie call is just an alias to header() (but with a specific schema to follow). You may have error output disabled and are missing the message, so it appears to work but is failing in the background.
setcookie should be one of the first calls on your page, up there with starting a session and setting a header.