11

A neat feature which I found in CakePHP was the ability to set a flash message, say on some save script, then have that message displayed on the following page. Something like, Post updated, or Error - no file found.

The way Cake does it is with this session object. I am trying to avoid sessions like the plague because of their odd requirements for scalability. Can I not just simply store the flash message in a cookie (client side) and then delete that cookie once it's displayed on the following page? What would be some pros/cons to this approach - or more simply, why does Cake uses session (I'm assuming that relates to the _SESSION collection).

Cheers!

p.s. In my implementation I also make it fade out with a setTimeout command in javascript. I find that's a nice way to end the whole process.

Sehdev
  • 5,486
  • 3
  • 11
  • 34
MikeMurko
  • 2,214
  • 1
  • 27
  • 56
  • "I am trying to avoid sessions like the plague because of their odd requirements for scalability". Can you elaborate? – Mike B May 16 '11 at 18:20
  • Yes, when scaling web servers horizontally into a farm you cannot guarantee that the same server is hit on the same request - therefore it might be processing on Server A, generate a session flash message, and then on the subsequent redirect show a page from Server B which has no knowledge of the other server's sessions. There are solutions to this, but they aren't optimal IMO (i.e. sticky sessions, etc). – MikeMurko May 16 '11 at 19:23
  • @MileMurko The solution to that particular problem implemented by most HA applications is to switch the session save handler to use a database or distributed caching solution like memcache. This makes the session data available from any web-head. If your question is 'Which is better' then you need to explain in detail why you don't inherently prefer one solution over the other. – Mike B May 16 '11 at 19:28
  • @MileMurko - I'd really test out the DB session handler before implementing it for your platform or application. I had a client that recieved 12-14 Billion HTTP requests a month and it wasn't a source of conflict using db backed session, but they also avoided using _SESSION for anything but ACL and user identity while cutting down chatter by perma-caching this information into Memcache. – David May 16 '11 at 21:52

4 Answers4

4

I don't see why you can't use a cookie with an expiration of say 10 minutes from creation date. Downside if the user walks away and comes back in 11 minutes they might not see the flash cookie message...but you won't have to worry about flooding a client with cookies.

Just make some simple content rules to ensure that no privileged information is put into a flash message and you should be good.

A simple implementation could be something procedural like:

function setFlash($id ,$message){
   setcookie("flash_{$id}", $message, time() + 60 * 10);
}


function getFlashes(){
   $flashes = array();
   foreach($_COOKIE as $id => $value){
        if(strpos($id, "flash_") === 0){
             $flashes[$id] = $value;
             //clear flash and set expiration to 10 minutes in past
             setcookie($id, "", time() * 60 * -10);

         }
  }
  return $flashes;
   //Input cleansing not included for brevity/clarity
}

Alternatively if the flash is originating soley from the client side, you can use something like https://github.com/marcuswestin/store.js to try and use localSession store to manage flash messages.

David
  • 17,673
  • 10
  • 68
  • 97
4

The problem with a cookie is that the user may disable this functionality. If so, your flash message won't be showed. CakePHP try to be general enough and uses session storage.

You have 3 options:

  1. Session: the most used approach. It will work in any client computer but, as you say, it could give problems with some server configurations.
  2. Cookies: it's a good option in general, but the user may block this mechanism. Only recommendable when the your app requirements include the need of cookies.
  3. Data base: the universal solution. The problem is that it requieres an access to the database (slow). An ID should be passed with the URL (GET method) so the application knows which database register corresponds to this access.

In my applications I use a combination of the 2nd and 3rd approaches: I test for cookies and if they are available, I use them. If not, I use database access, BUT I always cache the DB access in order to not query more than once for each message.

Ivan
  • 14,692
  • 17
  • 59
  • 96
  • 5
    If cookies are disabled, will sessions really work? Doesn't sessions rely on cookies? (If you haven't enabled PHPSESSID) – Markus Hedlund May 23 '11 at 11:14
  • 1
    But then how would you persist your session from one transaction to the next? The session store is server side, but the session identity token something that must be given to the client for it to then hand back on the next POST/GET call. – David May 25 '11 at 17:07
  • 3
    As @David says, the server identifies the user over multiple requests, by storing a cookie on her computer. – Markus Hedlund May 26 '11 at 11:25
  • If cookies aren't enabled on the user's computer, then there's really absolutely no way to implement flash messages. – danronmoon Nov 02 '12 at 15:20
0

Another idea is the transport of the message via the hash in the url:

if (isset($_POST['submit'])) {
    ...
    header("Location: ".$_SERVER["REQUEST_URI"]."#".urlencode($msg));
    ...
}

Advantages:

  • Does work without cookies / sessions / databases / memcaches etc. :-)
  • Does not rely on client clock as cookies do
  • No other client request can "steal" the message

Disadvantage:

Community
  • 1
  • 1
Marcel
  • 3,749
  • 6
  • 29
  • 35
  • Depending on the implantation you also run the risk of someone injecting into the page and doing something like domain.com?error="you need to click this link to fix this error link.com" – Mav2287 Feb 13 '21 at 23:19
0

Sessions are unfortunately not always reliable when followed by Header("Location ...");

I was thinking of putting it to GET request or Hash tag as was suggested, and you can erase it on next page using javascript from the URL using window.history.pushState.

Edit: Unless session_write_closed(); is used.

Martin Zvarík
  • 2,120
  • 22
  • 27