PHP session_write_close() keeps sending a set-cookie header - php

In my framework, I make a number of calls to session_write_close().
Let's assume that a session has been initiated with a user agent. The following code...
foreach($i = 0; $i < 3; $i++) {
session_start();
session_write_close();
}
...will send the following request header to the browser:
Set-Cookie PHPSESSID=bv4d0n31vj2otb8mjtr59ln322; path=/
PHPSESSID=bv4d0n31vj2otb8mjtr59ln322; path=/
There should be no Set-Cookie header because, as I stipulated, the session cookie has already been created on the user's end. But every call to session_write_close() after the first one in the script above will result in PHP instructing the browser to set the current session again.
This is not breaking my app or anything, but it is annoying. Does anyone have any insight into preventing PHP from re-setting the cookie with each subsequent call to session_write_close?
EDIT
The problem seems to be that with every subsequent call to session_start(), PHP re-sets the session cookie to its own SID and sends a Set-Cookie response header. But why??

PHP does not recommend doing so, and there were bunch of bugs submitted for this. Since they think it's not a good practice - this is the bug that is not going to be fixed.

Almost every answer I found on SO says to just do a session_write_close() and session_start() over and over again...some even disable cookies with ini_set temporarily...this seems to be a very bad approach. The PHP authors provided a very clear, best-practice, path to injecting your own way of handling the sessions using session_set_save_handler.
I have created an example on another post that shows how you can replace your session_start() with Session::start() and replace session_write_close() with Session::save(). The class is a non-blocking (a user can have concurrent requests) class implemented for PHP 5.4+. In fact, it's just a tweaked version of PHP's example class.
While my example is PHP 5.4+, the same method works in older versions of PHP with callback methods instead of an interface implementation.
https://stackoverflow.com/a/27993746/482256

session_write_close just close session and write data
while session_start send cookies
if your don`t want send session cookie your mustn't call session_start

Related

Trouble with calling session_start() at the start of all PDO pages

Most of my pages use Sessions, but I'm switching to PDO and calling session_start() at the start of every page is causing problems with passing headers. I've done several hours of research and am still unclear what to do about it.
Edit - What I've been doing: The 1rst line of the sign up/sign in documents as well as auth.php is session_start();, and the 1rst line of all pages the user visits subsequent to sign up/sign is require_once('auth.php');
I'm currently passing the user id to every page with $_SESSION['SESS_USER_ID']
When they sign up/sign in I connect it like this:
$member = $stmt_user->fetch();
$_SESSION['SESS_USER_ID'] = $member['user_id'];
And on every subsequent page I call it like this:
$user_id = $_SESSION['SESS_USER_ID'];
As per the manual
As of PHP 4.3.3, calling session_start() after the session was
previously started will result in an error of level E_NOTICE. Also,
the second session start will simply be ignored.
Does this mean that I no longer need to call it on every page and can just call it once when the user commences a session?
If not, what is the simplest way to do deal with this issue?
If you are using a framework, you likely just need to call it once in that framework. If each of your requests go to different php pages, then you need to make sure it gets called at least once per request (preferably as soon as possible).
You need to make yourself a bootstrap file.
A file with all common operations performed on the every page - session start, connect to database, set global variables, etc.
And then include this file into every script called.
So, you'll be sure that you have everything you need, yet called everything once.
Though I don't understand what does this question to do with PDO (as well as a previous one).
PDO is just a database driver and have not a slightest relation to headers, sessions and the like.
You can use ob_start and ob_end_flush to buffer your outputs, so you can actually do this:
<?php
ob_start();
echo '42';
session_start(); // still works because output is buffered
ob_end_flush();
?>

Set cookie after output without ob_start

I'm guessing not, but is there a way to set a cookie in PHP without having to put ob_start() at the start of the output?
My problem is, that I am developing a class, which among others, needs to set a cookie. Now I can't tell the person who uses it "you have to make a new instance of the class before you make any output", cause that would be lame. So can I somehow pull it off?
See Headers already sent by PHP
The unprofessional workarounds listed there apply. Specifically:
<META HTTP-EQUIV="Set-Cookie"
CONTENT="cookievalue=xy;expires=Friday, 14-Dec-12 12:12:12 GMT; path=/">
Or use javascript and set document.cookie.
You cannot. Cookies are sent as part of the header, so if you've already sent the body, it's too late. Output buffering is the solution.
Perhaps you could use session variables instead.
This is my workround and is working fine for me.
// Force set cookie now
$_COOKIE['ref_url'] = $_SERVER['HTTP_REFERER'];
// Set cookie after refresh site
setcookie('ref_url', $_SERVER['HTTP_REFERER'], Affiliate::$cookieTime);
// Diplay $_COOKIE
var_dump($_COOKIE['ref_url']);

Setcookie does not set a cookie

Hi guys im trying to set a cookie using
setcookie("ms_il_cart_save_for_3", "cName", time()+3600);
header("Location: store-cart3.php");
exit;
when i am move to store-cart3.php the cookie was not set var dump on cookie shows NULL, this has work for me for a year by now. today i have updated changes no related to this piece of code, i know for a fact this worked so far, nothing is outputed with HTML before this code and i dont think i changed the files encoding, maybe my web server blocks creating cookie because of security mesures? (i have run this code today about 100 times)
this is pritty annoying any ideas?
Cookie setting will only work if headers haven't been sent yet. If you've already sent headers or content to the client then setcookie won't work. Setting cookies also requires the client to accept the cookie, if it doesn't then there's nothing you can do about that other than inform them that they need to accept cookies for your system to work.
EDIT: You said in your post that you made changes to unrelated code and now your setcookie doesn't work any more. It is possible that your unrelated code has an error in it that's causing PHP to echo an error message to the browser. This will cause all headers to be sent and any setcookie calls made after this point won't work.
When you're setting a cookie on a page that redirects in this manner, you have to set the cookie after the call to header().
So your example needs to be:
header("Location: store-cart3.php");
setcookie("ms_il_cart_save_for_3", "cName", time()+3600);
exit;
Propably you have outpuded some content before calling that functions and headers were already sent.
Try to start output buffering at start of your script by ob_start()
Also check your files for warnings/notices and BOM utf-8 bytes at begining of text file, wich ones aren't seen in text editor.
Is it browser specific? I've noticed that Blackberry browsers don't process cookies returned in a redirect response - but MSIE and Firefox are happy to.
Since the redirect is after the setcookie, I presume it would be fairly obvious if the headers had already been sent. But have you checked that the cookie is still in the response headers? (ieHTTPHeaders, firebug, tamperdata, fiddler, wireshark)
If not, try switching around the order of the setcookie() and header() calls.

PHP sessions and AJAX request (from injected JS code)

I think I forgetting something in my code but can't find what.
On my server I have simple logging.php file.
If I pass user/password parameters then a new session is created.
If I pass loggout the session is destroyed.
If I pass report the list of current session variables are reported on screen.
If I test the code writing urls in my browser all works fine. First invoke .../logging.php?user=xxx&password=xxx. The session is started and the session variables are reported to me. And finally I destroy the session passing the logout parameter.
If user request a report or a logout and no session exists a HTTP-401 error code is returned to client.
On the other hand I have a piece of JavaScript code that I can inject on web page using a bookmarklet. Once code is injected I show a toolbar where user can write user/password and send to server.
The logging actions seems to works fine, and server returns me a 200 status code, but later if I make a request to logout the server returns me a 401 error, which mean no session exists.
I was using chrome and looking at HTTP request and responses can see that when I logging the server returns in the response different values for PHPSESSIONID.
That means two different AJAX request are considered different sessions. The server seems to not recognize the second request from AJAX as if it was started by the same client.
Repeat, the PHP code works fine if I execute using browser directly but not with AJAX request, so I think I forgetting something in AJAX.
Any ideas?
Thanks in advance.
Update
To be more concise, my problem is calling php from JavaScript. It seems there are no sessions started.
Imagine a very simple PHP code:
logging.php: given a user/password starts a new session and also stores 'user' names as a session variable.
request.php: which returns the user name stored as session variable.
logout.php: which destroys the session.
My first AJAX request start a PHP session. That seems fine because a PHPSESSIONID cookie is returned from server. Also I store the user name as session variable.
The second AJAX request tries to get the user name (stored in the session) but it gets nothing and in addition a new PHPSESSIONID cookie is returned from server.
I know it seems impossible and more when I'm testing using browser url request and works fine, but it's the truth.
I'm forgetting something on AJAX, expiration times or something similar?
Update again
I made some tests and I found the problem but not the solution.
My JS code is injected through a bookmarklet.
When I inject the code in a HTML page from my server, the AJAX requests works fine. The first (logging) request gets a PHPSESSID which is passed in subsequent request to the server.
On the other hand If I load google.com and inject the code, the first (logging) request gets the PHPSESSID too but later it is not sent with next requests.
Anyone has experienced the same issue? which is the problem?
Thanks in advance.
Update again, again
Ok finally I found my problem. Because my JS is injected from a different domain (current page is from domainA and my JS code comes from domainB) cookies are not cross domain, so PHPSESSID can be shared.
A possible soulution is when I logging I will return the PHP session ID in pice of JSON data and use it for subsequent calls.
If I'm correct, you're trying to log in a user by making an AJAX request to a URL, with the username and password provided in the URL? That's not really a safe construction, the password is very vulnerable this way?!
I would advice you to implement jQuery, and transer the login details using the $.POST command:
http://api.jquery.com/jQuery.post/
Make sure all your files (also those requested by AJAX) contain session_start(); on top of the file.
When every file contains session_start(); and you're using the same $_SESSION variables to check if a user is loggedin, it should work!
Are both of your AJAX requests coming from the same page? The requests are Asynchronous, so it may be that the "logged in?" request is returning its result before the "log in" request goes through.
From what you have asked, I hope your code is (at its beginning more or less) something like:
A file logging.php like this:
<?php # file : loggging.php
if(!ini_set('session.auto_start'))
// more stuff
if(!empty($_REQUEST['user']) && !empty($_REQUEST['passwd'])) {
session_regenerate_sid(); // This is important (1)
$_SESSION['user'] = $_REQUEST['user'];
// Whatever
}
A file request.php like this..
<?php # file : request.php
if(!ini_set('session.auto_start'))
// Whatever stuff to process data
var_dump($_SESSION);
// Or a nice foreach($v as $i => $x) {
// echo("[$i] => $x\n<br />");
// } instead :)
And your logout.php should read something like..
<?php # file : logout.php
if(!ini_set('session.auto_start')) session_start();
session_destroy();
You are probably not calling either session_start() or you are calling it twice.
To check this out try this: change all your session_start() lines for:
session_name('MYCoolNewName');
session_start();
Now your session should not read PHPSESSID, instead it should be MYCoolNewName.
If it is not, then your problem is the aforementioned.
(1) I put as important session_regenerate_sid() because opened authenticated sessions are a threat out there. I'll demonstrate it with an example.
Alice visits coolwebsite.com/login.php, which gives her a SID which I'll call AliceSID.
Alice tells Bob to visit coolwebsite.com/login.php?PHPSESSID=AliceSID, and when Bob does Alice could log in his account unless Bob's session was regenerated.

Semantics of setting cookies and redirecting without getting header error

I would like to do the following in php :
setcookie('name', $value, $Cookie_Expiration,'/');
then some action
header("location:http://www.example.com")
the problem is that I get :
warning: Cannot modify header information - headers already sent by (...etc )
could you please let me know what i am doing wrong and if there is a way to do this?
by the way , this code is before any output is made ...the cookie setting part works fine on its own and so does the redirection code....the combination fails
thank you
Cookies are sent in the header, and you can't set headers if any output is already sent to the browser (which is is when you set the cookie).
The easiest solution, mind you it is a bit sloppy is to use ob_start() and ob_clean(), for example:
ob_start();
setcookie('name', $value, time()+3600);
ob_clean();
header("Location:http://www.example.com");
Please note the upper case L in the Location header, it is very important.
A better solution might be to set the cookie on the page you are redirecting to, and pass the information to set that header through a session.
From the php manual:
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.
basically saying what you already know from your warning; that the setcookie is itself sending a header. I'd probably wonder why you want to set a cookie on a page then redirect, why not just redirect and include the data in the URL then pick it up on the target page and use the data there and/or store it in a cookie then, or store in session data if you have a session set already.

Categories