While implementing flagging for anonymous users on Pressflow 6 - I've found that if a user doesn't already have any cookies, Session API will not create one. This is because of how session_api_available() checks if cookies are enabled.

For most of my users, I never want them to have a cookie to allow varnish to cache their traffic, so this essentially breaks Session API for me. Am I understanding this correctly? Do we actually need to check if there in anything in $_COOKIE ?

/**
* Determine if cookies are enabled.
*/
function session_api_available() {
return !empty($_COOKIE);
}

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jessehs’s picture

Status: Active » Needs review
FileSize
1.6 KB

I also am running into this problem on a D6 pressflow site. I'm not sure how to check if a user has cookies enabled on their browser, but I'm also not sure there is a problem with going ahead and trying to save a session even if they do not.

This patch changes the session_api_available function to create an "initialized" cookie if $create is true (which is determined in the session_api_get_sid function). The patch also makes sure not to query the database for the "initialized" cookie.

jessehs’s picture

Just wanted to add that I think this issue is fundamentally related to this ongoing core issue: http://drupal.org/node/2946

There doesn't really seem to be a sure fire way to determine if a user's browser will accept a cookie without first trying to set one and seeing if it still exists after an additional page load. With Pressflow, this could be a huge performance hit, as it doesn't try to set a cookie for anonymous users.

jhedstrom’s picture

Status: Needs review » Needs work

I've been thinking about the approach in #1, and I think it may be too aggressive, since any module calling session_api_get_sid() will effectively set cookies on every page.

I propose, rather, and additional API function (perhaps session_api_set_cookie()) that simple initializes the cookie in the same way the patch in #1 does.

This would give modules much finer control over which pages initialize cookies, and which do not.

jessehs’s picture

Here is a patch suggested in #3. The function name is "session_api_initialize_cookie."

jhedstrom’s picture

Version: 6.x-1.4 » 6.x-1.x-dev
Status: Needs work » Patch (to be ported)

Committed to 6.x. Thanks!

jhedstrom’s picture

Version: 6.x-1.x-dev » 7.x-1.x-dev
Roi Danton’s picture

I had a similar issue that session ID cookie is not set when there is no cookie already. Using flag module and D7:

PDOException: SQLSTATE[22003]: Numeric value out of range: 1264 Out of range value for column 'sid' at row 1: INSERT INTO {flag_content} (fid, content_type, content_id, uid, sid, timestamp) VALUES (:db_insert_placeholder_0, :db_insert_placeholder_1, :db_insert_placeholder_2, :db_insert_placeholder_3, :db_insert_placeholder_4, :db_insert_placeholder_5); Array ( [:db_insert_placeholder_0] => 2 [:db_insert_placeholder_1] => node [:db_insert_placeholder_2] => 5 [:db_insert_placeholder_3] => 0 [:db_insert_placeholder_4] => -1 [:db_insert_placeholder_5] => 1326447147 ) in flag_flag->_flag() (Zeile 724 von /www/htdocs/.../drupal7/sites/all/modules/flag/flag.inc).

The patch in #1 didn't work for me, since

    else if (!$create) {
      // Return a negative value here, since it won't collide with any
      // session_api IDs.
    	return -1;
    }

was always triggered in session_api_get_sid(). So I set $create always to TRUE:

function session_api_get_sid($create = TRUE) {
  static $sid;
  $create = TRUE;
  if ($create) {

which fixes the problem. And b/c there is already

a check if we already have an active session

in session_api_get_sid() the existing cookie is used when there is one. So everything works as expected. Can you tell me which are the possible drawbacks of this method?

a.ross’s picture

smartango’s picture

@Roi the drawback given in comment
http://drupal.org/node/1619114#comment-6309018

- call flag_get_uid(0) [ which call flag_set_sid($uid,FALSE) ] returns 0 and set static $sids[0] to 0
- call flag_set_uid(0) [ which has $create = TRUE as default ] return 0 never start session [WRONG]

maintaining a static $sids array in flag_set_sid make it never start a session

anyway I cant understand how in patch in #4 this function:

function session_api_available($create = TRUE) {
  if ($create && !isset($_COOKIE['session_api_session'])) {
    $_COOKIE['session_api_session'] = 'initialized';
  }
   return !empty($_COOKIE);
}

called as session_api_available() could ever return false when browser do not support cookies or not. In php if you set a key of an array empty($arrayname) return FALSE, thus this returns TRUE, for any user agent.

If you want TRUE, just use TRUE, don't call a function.

http://php.net/manual/en/reserved.variables.cookies.php
http://www.php.net/manual/en/function.setcookie.php

way of retrieve and set cookies with php

nlisgo’s picture

smartango thanks so much for the explanation and the links.

The link http://www.php.net/manual/en/function.setcookie.php is particularly significantly. We simply cannot tell until the next page whether the browser supports cookies.

For those who need to action something on the first time a user hits the page then either be prepared to be disappointed or rethink your solution.

nlisgo’s picture

My work around was to include a javascript file if session_api_available did not return TRUE. In that javascript file a perform an ajax call on the same page so that the cookie support should be known at that point and I can use rules to set the flag for anonymous users.

smartango’s picture

nlisgo I am not following actively this issue, but I would give a comment. Using ajax (with post) is a way to invalid the cached page, this could be done server side in some way too, I think, if server reply with invalid to header request of browser it will download the page again with cookie setted, then you can test (in the next call) if browser accept cookies. (of course the javascript solution is more elegant)

But the problem, I think, is to have an "all cached" site that has cookie support. That is not possible ... or it is? maybe if the relative parts travel on ajax request and javascript client side rendering, the most could be cached, while the user related data not. This is already known, but is not this solution. I suppose is due to the policy of not relying on javascript support for web application (server side application), policy that is becoming outdate, anyway there is the fork option that will not hurt anyone

a.ross’s picture

Title: If a user has no cookies session api will never create one? » Make sure Session API is available on the first page load
Category: bug » feature
Status: Patch (to be ported) » Needs work

I guess this is more of a feature request as HTTP is stateless and sessions are (therefore) managed through cookies. And cookies, as we know, may not be supported by the client.

Basically there are 2 conceptual ways to do this:

  • Create the illusion that Session API is available on the first page load. Possible by using JS as mentioned.
  • Make sure Session API is available on the first actual HTTP request. I don't think this can be done without ugly, unreliable hacks.

As for the latter option, I don't think that's feasible. And as for the former, I'm not sure what the drawbacks of that are.