Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Location https://helix.wtgc.org/system/files/users/wtsi/a/ak2/library_branding/wt... (anonymous)
Message Warning: Cannot modify header information - headers already sent by (output started at
/www/htdocs/includes/file.inc:1965) in _drupal_session_delete_cookie()
(line 466 of /www/www-live/drupal.sanger.ac.uk/htdocs/includes/session.inc).
function _drupal_session_delete_cookie($name, $secure = NULL) {
.....
466: setcookie($name, '', REQUEST_TIME - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
function file_transfer($uri, $headers) {
......
drupal_send_headers();
$scheme = file_uri_scheme($uri);
// Transfer file in 1024 byte chunks to save memory usage.
if ($scheme && file_stream_wrapper_valid_scheme($scheme) && $fd = fopen($uri, 'rb')) {
while (!feof($fd)) {
1965: print fread($fd, 1024);
Why is this cookie being deleted after the headers and file contents for a file download have been sent for an anonymous user?
Comments
Comment #1
Marc Angles CreditAttribution: Marc Angles commentedHi, we have kind of the exact same bug here.
Did you find an explanation to this one ?
Comment #2
StephenRobinson CreditAttribution: StephenRobinson commentedglad someone else has got this issue, been left on the back burner as havent found a solution.
Comment #3
mikeytown2 CreditAttribution: mikeytown2 commentedAlso getting this same error. Looks like the session is getting destroyed & causing this issue. I'll work on a patch.
Warning:
Cannot modify header information - headers already sent by (output started at includes/file.inc:1989)
LINE: 466
FUNCTION: _drupal_session_delete_cookie()
FILE: includes/session.inc
STACKTRACE:
Comment #4
mikeytown2 CreditAttribution: mikeytown2 commentedComment #5
mikeytown2 CreditAttribution: mikeytown2 commentedComment #6
StephenRobinson CreditAttribution: StephenRobinson commentedam testing this, get this alot as people link to images on my restricted internet externally
Comment #7
mikeytown2 CreditAttribution: mikeytown2 commentedHave you tested the patch to see if it fixes the problem for you?
Comment #8
StephenRobinson CreditAttribution: StephenRobinson commentedHi,
Been live for a few hours and have not seen the error again yet...
Stephen :)
Comment #9
mikeytown2 CreditAttribution: mikeytown2 commentedMarking this RTBC
Comment #10
David_Rothstein CreditAttribution: David_Rothstein commentedWhat are the steps to reproduce this - i.e. when/why is this getting called after headers have already been sent? It looks like the patch might be hiding the actual bug (which is that the cookie is supposed to be deleted, but isn't).
Drupal 8 also looks like it has equivalent code in
Drupal\Core\Session\SessionHandler
so there's a good chance the bug needs to be addressed there too.Comment #11
mikeytown2 CreditAttribution: mikeytown2 commentedIn our case, we have drupal serve images for other domains/servers. If a user gets logged out of drupal due to a session timeout and that request was the user generating an image then it can trigger this error.
Sending the file causes headers to be sent. I would suspect that advagg could cause a similar issue (as it generates static files as well) but due to css/js not being used on other domains/servers it doesn't cause this bug.
Comment #12
StephenRobinson CreditAttribution: StephenRobinson commented"In our case, we have drupal serve images for other domains/servers." me too, our librarians keep attaching images to journal site download apps, very annoying for a internal only restricted internet...
Comment #13
mikeytown2 CreditAttribution: mikeytown2 commentedThanks David_Rothstein for pointing out that SessionHandler::deleteCookie does have similar code :)
I've attached a patch for D8 based off of #4
Comment #14
mikeytown2 CreditAttribution: mikeytown2 commentedThe alternative to this would be to use drupal_save_session(FALSE); inside of file.inc. Not sure what the D8 equivalent would be.
Comment #15
StephenRobinson CreditAttribution: StephenRobinson commentedI did manage this error Warning: session_start() [function.session-start]: Cannot send session cookie - headers already sent by (output started at /www/www-live/drupal.sanger.ac.uk/htdocs/includes/file.inc:2058) in drupal_session_start() (line 292 of /www/htdocs/includes/session.inc).
only occurred when reverting a feature.
Comment #16
mikeytown2 CreditAttribution: mikeytown2 commentedD7 patch that uses
drupal_save_session(FALSE);
when transferring any file via php.Comment #17
drakeston-admin CreditAttribution: drakeston-admin commentedI am also having the same problem at my homepage of my site www.rumathi.com . the best way to solve it is to use drapul image cokiee 6.8
Comment #18
mikeytown2 CreditAttribution: mikeytown2 commentedIn D8 I think this would happen in BinaryFileResponse::sendContent() which is inside of Symfony so I'm tempted to put it in ImageStyleDownloadController::deliver() and anywhere else BinaryFileResponse is used.
SessionManager::disable() seems to be where this happens; I think I'm using it correctly.
Note that the way file transfers happen in D8 this might not be necessary; this might be a D7 and below issue.
Comment #19
mikeytown2 CreditAttribution: mikeytown2 commentedCorrect D8 patch
Comment #21
mikeytown2 CreditAttribution: mikeytown2 commentedPatches pass tests on D7 & D8.
Comment #22
JvE CreditAttribution: JvE commentedThis appear to happen both at session_destroy and session_start.
For me it is session_start:
Warning: session_start(): Cannot send session cookie - headers already sent by (output started at includes/file.inc:1973) in drupal_session_start() (line 287 of /var/www/virtual/www.ntvg.nl/includes/session.inc).
In both cases I'm wondering why a session does not already exist.
Comment #23
slashrsm CreditAttribution: slashrsm commentedLet's inject session manager via create().
Same with ExportForm and FileDownloadController.
Comment #24
mikeytown2 CreditAttribution: mikeytown2 commentedIs this the right method - Config::create()? Haven't done much D8 code yet.
Comment #25
mikeytown2 CreditAttribution: mikeytown2 commented@JvE Does #16 fix the issue for you?
Comment #26
slashrsm CreditAttribution: slashrsm commented@mikeytown2 - no, you need to add "session_manager" to create() function (there are already "lock" and "image.factory" there). This will send it to constructor of the class where you take it and save it into a class member. Then use it like this "$this->sessionManager->disable()" (assuming you saved it in a member variable called "$sessionManager").
Comment #27
mikeytown2 CreditAttribution: mikeytown2 commentedCan I get a link to an example? The API site doesn't list where the code is called from in SessionManager::disable() so I don't have a good working example on how to do this. You could also update https://www.drupal.org/node/218104 with the correct way to do this in D8 that would be helpful as well :)
Comment #28
JvE CreditAttribution: JvE commented@mikeytown2: Yes, #16 gets rid of the warning.
But I have the feeling it is simply hiding the symptom of a different fault somewhere.
As in, why would a session not yet exist at that point in the code? Anonymous users? Then why does drupal want to start a session after sending a file?
Comment #29
mikeytown2 CreditAttribution: mikeytown2 commented@JvE drupal_set_message() will start a session so I don't think it's totally unreasonable for this to happen.
Comment #30
pachabhaiya CreditAttribution: pachabhaiya commented#16 works for me. I'm not seeing any warning as mentioned in this issue after applying patch #16.
Comment #31
AlexKirienko CreditAttribution: AlexKirienko at WikiJob commentedI have faced similar issue in xmlsitemap module, which used modified file_transfer() function.
I have ported patch #16 and it works for me. Thank you.
https://www.drupal.org/node/2546646#comment-10190812
Comment #32
garbo CreditAttribution: garbo commented#16 fixes the error for my in D7 with the textimage module.
Comment #34
mikeytown2 CreditAttribution: mikeytown2 commentedJust a heads up that even with #16 applied I got this error:
LINE: 1265
FUNCTION: drupal_send_headers()
FILE: /var/www/html/includes/bootstrap.inc
STACKTRACE:
Comment #39
donquixote CreditAttribution: donquixote commentedI opened #2963530: "Cannot send session cookie" on image style generation. with steps to reproduce (on Drupal 7).
Problem, part I
The basic problem (in D7):
drupal_exit() is called in various page callbacks (*) after headers and content are printed.
file_transfer() is just one example.
The callers expect that drupal_exit() will NOT print additional headers.
However, if
- the session is in "lazy" mode (which happens on requests without a session cookie), AND
- some module writes to $_SESSION anyway (e.g. ip_geoloc).
Then drupal_exit() will send headers via
drupal_session_commit() -> drupal_session_start() -> session_start().
This would mean drupal_exit() is not fully suitable as a function for these page callbacks.
Problem, part II: Output buffering!
It is more complicated than that.
In most PHP installations, the initial output buffering level is 1 (the output_buffering setting is probably at 4096).
As long as output buffering is on level 1, the entire problem of "Headers already sent" does not exist!
One could write an example script
/test.php
like this, and it would be just fine:https://3v4l.org/tn1fR
However, the following script will produce the "Headers already sent" problem:
https://3v4l.org/1aM5E
Now
file_transfer()
is different from other page callbacks that call drupal_exit(), because file_transfer() also callsob_end_clean()
before anything else.Interesting issue: #205227: If output_buffering = Off then ob_end_clean fails to delete buffer.
This means:
Solution
I considered a number of different options.
But in the end, I think the existing patch #18, or something similar, might be the best shot.
My first idea was to change drupal_exit() so that it never sends any headers.
Instead, always send the session cookie headers before the page callback (or never).
However, this does not work if we start with empty $_SESSION, and modules write to $_SESSION during page callback or during hook_exit().
Also, this would be completely unnecessary as long as output buffering is enabled.
The next idea was to keep output buffering enabled in file_transfer().
But this might cause memory problems (not sure).
So, something like #18.
But perhaps we should make sure that output_buffering is always on the same value, to make Drupal behave more reproducibly.
And perhaps provide a version of drupal_exit() that is guaranteed to never send any headers!
Comment #40
donquixote CreditAttribution: donquixote commented@JvE (#28):
(my answer below applies to Drupal 7)
There is a "lazy" session mode in drupal_session_initialize().
This means that session_start() won't be called in bootstrap.
Instead, in drupal_exit() or drupal_page_footer(), drupal_session_commit() is called, which checks if anything is in $_SESSION, and if so, calls session_start().
Comment #48
mstrelan CreditAttribution: mstrelan at PreviousNext commentedIs this still applicable for Drupal 9 and 10? If so, we need steps to reproduce, ideally with a failing test. We should update the issue summary to use the standard template also.
Comment #49
quietone CreditAttribution: quietone at PreviousNext commentedMore information on this was asked for 8 months ago, specifically if this is still a problem, and none has been supplied.
Therefore, closing as outdated. If this is incorrect reopen the issue, by setting the status to 'Active', and add a comment explaining what still needs to be done.
Thanks!