A drupal_set_message() issued during the logout process is lost and never displayed.
What I did: Created an system_message_action()
and associated it with the user_logout
trigger.
What I expected: A message displayed to the user after logout.
What happened instead: No message was displayed.
I imagine this is because the session is destroyed, and the messages are queued in the session. This is not the expected behavior, though.
Solution for D7 when writing custom code:
module_load_include('pages.inc', 'user');
user_logout_current_user();
drupal_set_message('My message will be shown to the user after they are logged out.');
drupal_goto();
**Next Steps**
1. Confirm if there's a similar approach for D8/D9/D10.
2. Confirm if higher-level APIs (like the action/trigger API) exhibit this problem. If so, can they be modified using the above technique?
Comment | File | Size | Author |
---|---|---|---|
#36 | drupal.logout-session_754560_36-d7.patch | 1.11 KB | yingtho |
Comments
Comment #1
rfayThe same problem occurs, for the same reason, I'm sure, at user account creation/login.
1. Create a system message action and associate it with user_insert trigger.
2. Create a user account.
3. No message is displayed.
The trigger fires, the drupal_set_message() is executed. But nothing is displayed.
Comment #2
rfayComment #3
andypostSession should be regenerated not destroyed. I'm trying to look latter
Comment #4
Damien Tournoud CreditAttribution: Damien Tournoud commentedI believe this is delt with in the (still incomplete #813492: HTTPS sessions use an invalid merge query).
Comment #5
rfayIf we can get #721086: Create tests for system actions, clean up token replacement, clean up triggers done and then if #813492: HTTPS sessions use an invalid merge query can make progress, we need to add to it the attached patch, which will properly test.
Comment #6
rfay#813492: HTTPS sessions use an invalid merge query has been committed, so it's time to see if this was resolved.
Comment #7
Damien Tournoud CreditAttribution: Damien Tournoud commentedTemporarily un-duplicating and bumping, to keep this on the radar.
Comment #8
Damien Tournoud CreditAttribution: Damien Tournoud commentedChecked manually (the test modified by #5 seems to be gone):
- messages triggered on logout are still lost in oblivion
- messages triggered on login and user insert work
Comment #9
Damien Tournoud CreditAttribution: Damien Tournoud commentedDowngrading. This only affects logout, and looks by-design to me:
We could consider being slightly less heavy-handed here (for example by defining a hook to prevent part of the session from being destroyed). But at least this works as designed.
Comment #10
rfayThe test modified by #5 is in #721086: Create tests for system actions, clean up token replacement, clean up triggers and is here as a placeholder in case it can go back into that one later (it was commented out in that one).
Comment #11
Eronarn CreditAttribution: Eronarn commentedJust in case anyone Googling this runs across this issue - drupal_set_message stores the message in the database, tied to session. user_logout destroys the session and does a drupal_goto. Users will get a new session as soon as they load the drupal_goto'd page, but there's no way to link that to the message, which was associated with their old session. To get the drupal_set_message functionality without something like including a querystring and checking for it on the destination page, we need to give them their new session *before* the goto. Here's how I did that:
1) Call session_get_cookie_params to get the current session's attributes
2) Call session_destroy to end the current session
3) Call session_set_cookie_params based on the values returned by 1)
4) Call session_start to start a new session
5) Log the user out with $user = drupal_anonymous_user(session_id()); instead of just $user = drupal_anonymous_user();
6) drupal_set_message followed by drupal_goto will now work.
I don't know if this is the safest/sanest approach, regarding e.g. attacks on session ID, but it at least works for my simple use case. Suggestions for refinement would be appreciated.
(This was in D6, by the way, but the logout code is similar.)
Comment #12
bleen CreditAttribution: bleen commentedin #11.5 did you mean "Log the user IN...", not "Log the user out..." If not, huh?
Comment #13
Eronarn CreditAttribution: Eronarn commentedYes, good catch, thanks.
Comment #14
DamienMcKennaThis affects Drupal 6 too. Would like to see it resolved for both D6 and D7 as doing a drupal_set_message on hook_user('logout') is beneficial for the user experience.
Comment #15
DamienMcKenna@eronarn: I tried out your idea with the following code:
Unfortunately it gives the following error:
Fatal error: session_start() [<a href='function.session-start'>function.session-start</a>]: Failed to initialize storage module: user (path: /Applications/MAMP/tmp/php) in /modules/user/user.pages.inc on line 157
Going to dive into it some more.
Comment #16
DamienMcKennaI've resolved the error by changing the session_start part to:
Now to retain the messages.
Comment #17
DamienMcKennaHere's a patch against Drupal 6.
Patch sponsored by the Siebel Scholars Foundation.
Comment #18
DamienMcKennaComment #19
dmitrig01 CreditAttribution: dmitrig01 commentedno one-letter variable names. as for the rest, i have no idea
Comment #20
DamienMcKennaChanged $p to $params.
Comment #21
DamienMcKennaPatches for both D6 and D7.
Comment #23
akoepke CreditAttribution: akoepke commentedComment #24
Akaoni CreditAttribution: Akaoni commentedThis is still a problem and the scope is larger than originally outlined. Any other modules that set $_SESSION variables which aren't tied to the login lose their data on logout.
The D7 patch is outdated and needs reworking. Not sure about the D6 patch.
Comment #25
andypostMoving to 8.x
This part cares only about session params but other content stored is going to be lost
Powered by Dreditor.
Comment #26
rfaySetting to needs backport
Comment #27
pjcard CreditAttribution: pjcard commentedsubscribe (sorry if this is the wrong way to do it, but I can't see a monitor/subscribe button anywhere).
Comment #28
rfayHere is #21 rerolled for D8.
Comment #29
Damien Tournoud CreditAttribution: Damien Tournoud commentedRelated: #758730: Fatal error on logout.
The route forward seems to be what I asked for in #9: we implement drupal_session_destroy() as described in #758730: Fatal error on logout and we add a hook in there that allow contrib modules to rescue part of $_SESSION.
Comment #30
Akaoni CreditAttribution: Akaoni commentedAdding session tag.
Comment #31
moshe weitzman CreditAttribution: moshe weitzman commentedIMO, this is a small problem, not worthy a complex solution. Code that wants to set a message after logout should try to run after the destroy.
Comment #32
Akaoni CreditAttribution: Akaoni commentedHere's a simple solution: don't destroy the session on logout.
Session != login
Drupal seems to make this assumption, however.
Comment #33
lmeurs CreditAttribution: lmeurs commentedRan into the same problem with Drupal 7.12: after logging out all shopping cart related data (custom module) is gone...
Comment #34
nedjo@moshe weitzman:
Could you sketch in how this might work? Sample use case: using Rules, log out a user and present them a message about having been logged out. Currently, this would be done with two actions: (a) set a message and (b) redirect (to user/logout). But if the message is set before redirecting, it is never presented to the user as the session ends. If it is set after redirecting, it is never executed because the page execution (and session) have ended. How could a rule action execute after the destroy?
Comment #35
nedjoFor D7+ the session calls are renamed, see http://drupal.org/node/224333#session_rename.
Comment #36
yingtho CreditAttribution: yingtho commentedI have added so it retains all the old session data. This patch is for drupal 7.
Comment #37
yingtho CreditAttribution: yingtho commentedForgot to set the correct status.
Comment #39
yingtho CreditAttribution: yingtho commentedOne thing to think about is security as it will retain all the previous session data. So if a module that don't want data to be retained need to implement hook_user_logout and remove the session data there.
Comment #40
jacobfriis CreditAttribution: jacobfriis commented@yingtho #39
Agreed! Regenerating the whole session array is hazardous, not what you would expect, and acutely contrary to the concept of being logged in (versus not).
Only the 'messages' bucket - $_SESSION['messages'] - should be regenerated (and that only if non-empty ;-)
Relaying the responsibility of destroying session data to modules is not correct - and would btw never be carried into effect in the real world.
Comment #41
jacobfriis CreditAttribution: jacobfriis commentedSet Drupal message that survives session destruction (like user logout):
Module State - state_set_message(); documentation.
Comment #42
steinmb CreditAttribution: steinmb commentedDo we still need to address this in D8, or have session handling changed to such a degree that this issue only apply to D7?
Comment #43
andypostIs there a steps to reproduce?
Comment #44
jacobfriis CreditAttribution: jacobfriis commentedReproduction in D7:
Comment #51
jcisio CreditAttribution: jcisio as a volunteer and at Axess Open Web Services commentedThanks @DamienMcKenna for the 9 year old D6 patch.
Comment #52
hash6 CreditAttribution: hash6 at QED42 for Drupal India Association commentedComment #53
xjmWe would still want to fix this bug in D8 as well. Thanks!
Comment #55
catchRetitling this one.
Comment #56
dalinAt least on D7, core has been refactored a bit since the last patch from 8yrs ago. The solution now (probably similar on D8) is something like this:
Comment #57
apadernoDrupal 8.9.x is now open only to security issues.
Comment #58
dalinComment #59
dalinComment #63
larowlanI think this is doable in D9+ as follows:
Implement hook_user_logout which gets called before logout, set some sort of flag that a user is being logged out.
Add an event listener for the
\Drupal\Core\Session\AccountEvents::SET_USER
event, if the flag from above is set and the new set user is anonymous, add the message, if not, unset the flag.Bit janky to have a hook for before and event for after, but the APIs are there.
Comment #64
DamienMcKennaShould this not be fixed in core?
Comment #65
larowlanAre you meaning that core copies the messages from one session to the next?
Comment #66
DamienMcKennaYes.
Comment #67
larowlanOk, then let's keep it open