Hi everybody.

I have a commerce site that is only for adult users. All users have a cookie "accepted_welcome" with value and expiration set to 0.

All Anonymous users that has the cookie set to 0 will be redirected to a "welcome" page where they have to submit a form accepting he/she is more than 18 years old. When the form is submited, the cookie is set from 0 to 1 and the user is redirected to the page he was trying to visit.

As good as it is, of course this is not working with Boost active.

So after reading every issue for Druapl 7 I came up with a solution that works, but I don't really know if this is a good solution or if I'm missing something. It works, but I really haven't tested it too much (will do it in the next days). Any comments or help would be very appreciated.

So I started using hook_boot() because in the Drupal help it says that it runs even on cached pages (wich we know it doesn't).

function MYMODULE_boot() {
  global $user;
  if ($user->uid == 0) {
    // Check for our custom COOKIE.
    $cookie_is_set = (isset($_COOKIE['accepted_welcome'])) ? TRUE : FALSE;
    $cookie_is_off = ($cookie_is_set && $_COOKIE['accepted_welcome'] == 0) ? TRUE : FALSE;

    if (!$cookie_is_set || $cookie_is_off) {
      // TODO: Try to avoid calling drupal_bootstrap(), but for now is the only way to use drupal_get_destination().
      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
      drupal_goto('welcome', array( 'query' => drupal_get_destination() ));
    }
  }
}

This works, but as soon as a page is cached (by another anonymous that has actually submited the welcome form) this hook is not called anymore for that page because of the way Drupal boostrap do it's logic.

The solution I've found is modifying the logic for the setting and removal of the boost cookie using hook_boost_cookie_handler_callback_alter().

/**
 * Implements hook_boost_cookie_handler_callback_alter().
 */
function MYMODULE_boost_cookie_handler_callback_alter(&$callback) {
  $callback = 'MYMODULE_boost_cookie_handler';
}

Then I made a copy of boost_cookie_handler() from boost.module and modify it to manage my cookie. The only code changes were the ones refering to my cookie.

/**
 * Logic for the setting and removal of the boost cookie.
 * This is a modified copy from "boost.module" so it checks our custom cookie.
 */
function MYMODULE_boost_cookie_handler() {
  global $user;

  // Check if Drupal is started from index.php - could cause problems with other
  // contrib modules like ad module.
  if (strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === FALSE) {
    return;
  }

  $uid = isset($user->uid) ? $user->uid : 0;

  // Remove Boost cookie at logout if it still exists.
  if (isset($_COOKIE[BOOST_COOKIE]) && $uid == 0) {
    boost_set_cookie($uid, REQUEST_TIME - 86400);
  }
  // Remove Boost cookie if set to -1 & Request Method is a GET/HEAD.
  elseif (isset($_COOKIE[BOOST_COOKIE]) && $_COOKIE[BOOST_COOKIE] == '-1' && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) {
    boost_set_cookie($uid, REQUEST_TIME - 86400);
  }
  // Set Boost cookie if it doesn't exists and user is logged in.
  elseif (!isset($_COOKIE[BOOST_COOKIE]) && $uid != 0) {
    boost_set_cookie($uid);
  }

  /***** NEW CODE/ *****/
  // Check for our CUSTOM COOKIE (accepted_welcome).
  if ($uid == 0) {
    $cookie_is_set = (isset($_COOKIE['accepted_welcome'])) ? TRUE : FALSE;
    $cookie_is_off = ($cookie_is_set && $_COOKIE['accepted_welcome'] == 0) ? TRUE : FALSE;
    if (!$cookie_is_set || $cookie_is_off) {
      boost_set_cookie($uid);
    }
    else {
      boost_set_cookie($uid, REQUEST_TIME - 86400);
    }
  }
  /***** /NEW CODE *****/

  // Issue #1242416: Set a nocache cookie on a POST, remove it immediately after
  // (on GET) Only necessary for anon users, since we already do not cache for
  // logged in users. Also note that if we are processing a GET, it means that
  // we have already been through the htaccess rules, so the cookie has done
  // its job and can be removed.
  if ($uid == 0 && $_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'HEAD') {
    boost_set_cookie(-1);
  }
}

This way anonymous users that has not validated his/her age, will see an uncached version of the page.
When seeing the uncached version of the page hook_boot() will be executed as normal, so all of our top logic will be executed too.

What do you think? Thank in advance :)

Comments

bgm’s picture

Category: task » support

Hi,

It's an interesting solution. In general, as you mentioned:

* avoid logic to determine whether to generate the cache or not, depending on the user's state. A page either gets cached, or not, for all users.
* use the BOOST_COOKIE (DRUPAL_UID) to avoid going into the static cache (since it's checked in the .htaccess rewrite rules)

However, in your case, I'd be tempted to go for a javascript solution: add a bit of JS that checks, on page load, whether a "welcome" cookie has been accepted. If not, popup (colorbox or redirect) a page where the user can accept the terms and conditions, and set a welcome cookie.

Javascript could be disabled, but if that's an issue, you can use a noscript tag to insert a div that covers the screen and tells the user to go to the welcome page.

EndEd’s picture

Hi bgm, thanks for the quick response :)

Yes, my goal was not to prevent a page from caching, but to prevent showing the cached version of the page in some circustances to a specific user (other anonymous will still see the cached one). My example is a simplified one, though, as I also check in my hook_boot() for the current page because I don't want to redirect to the welcome in some pages (mainly login form, contact form and help pages).

The Javascript solution was the last thing I was going to do. I know the JS method works because in my site (for anonymous) the shopping cart is a placeholder that gets replaced after page load with an AJAX call (so the correct order and not a cached one is displayed). If the user deactivates JS then the placeholder has the link to the cart page.

As this site is an adult site I think I should drop the JS solution for now, because the page would load and then JS will execute. Also you can hide any noscript with common browsers (firebug, etc). Keeping it in a separated Drupal page makes more sense to me. IIRC the first version of this welcome thingy was in fact a modal that covered the whole page, but again it was easily hideable.

Anyway, thanks again. My fear was that the method I used was bad or had any conflict of some sort with how boost works.

bgm’s picture

Status: Active » Fixed

Another option could be to check for the "welcome" cookie in the htaccess, and if the user does not have it, redirect the user to another page.

Hard to say exactly without wrapping my head in the code and the specifics of the use-case, but seems you have a few options, including one which is working :)

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.