static cache: get user login information by cookie / js

Author Message

Georg Franz

Tuesday 28 June 2005 6:16:28 am

Hi folks,

I use the static cache feature, so no PHP is available on the hmtl-pages.

Is there an easy possibility to get the info by javascript if the current visitor is looged in?

Example: I want to show the login box if the user isn't logged in or show the link to a page where the user sees his user info.

Björn gave me the tip yesterday to try it with javascript and I wonder if such an info (I only need "yes" or "no") is already available some how ...

Or is the only way to alter the login.php / logout.php and set a cookie there?

Best wishes,
Georg.

--
http://www.schicksal.com Horoskop website which uses eZ Publish since 2004

Geraint Edwards

Wednesday 29 June 2005 1:14:56 am

I should have read this post before asking my question w.r.t. your other thread re static cache (http://ez.no/community/forum/developer/static_cache_some_user_report_tips) since your question implies the answer is <b>totally</b> static.

I spent some time grapping with the issue of getting cookie information into a template file but with no success. One idea I did have, which may help here, was to embed a hidden IFRAME element which loads a custom php file which delivers the equivalent of cookie type information which can be accessed by javascript in the main page (there are no browser security issues since its all within the same domain) - the script in the main page can be called from an onload routine in the IFRAME to ensure that everything is loaded and the javascript engine initialised before the the scripts start.

There would be no template, translation or cache processing overhead in the IFRAME php call so it should be pretty fast.

What do you think?

Geraint

Georg Franz

Wednesday 29 June 2005 8:52:45 am

Hi Geraint,

I think your way is interesting but takes too much time to realize.

Altering the login.php and logout.php is much faster ;-) (yes, yes, yes, I know that it isn't a good idea to alter kernel files ...)

Maybe there could be developed a new way in future versions of ezp: Getting dynamic info (e.g. username) from a smallindex.php without touching the template engine.

Best wishes,
Georg.

--
http://www.schicksal.com Horoskop website which uses eZ Publish since 2004

Geraint Edwards

Wednesday 29 June 2005 9:10:14 am

It may not take as much time as you think - here is a solution that has the added benefit of being easily extendible to pass/manage other dynamic content/values:

Add the following to the bottom of your pagelayout.tpl

<iframe style="visibility:hidden;" src="/utils.php"></iframe>

Implement utils.php as follows:

<?php
//
// Created on: <28-June-2005>
//
// Copyright (C) Geraint Edwards. All rights reserved.
//
// This file may be distributed and/or modified under the terms of the
// "GNU General Public License" version 2 as published by the Free
// Software Foundation and appearing in the file LICENSE.GPL included in
// the packaging of this file.
//
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE.
//
// The "GNU General Public License" (GPL) is available at
// http://www.gnu.org/copyleft/gpl.html.
//

// send header information
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Cache-Control: no-cache, must-revalidate' );
header( 'Pragma: no-cache' );
header( 'Content-Type: text/html;' );
//header( 'Content-Type: application/x-javascript;' );

include_once( "lib/ezutils/classes/ezini.php" );
include_once( "lib/ezutils/classes/ezdebug.php" );
include_once( "lib/ezutils/classes/ezdebugsetting.php" );

$debugINI =& eZINI::instance( 'debug.ini' );
eZDebugSetting::setDebugINI( $debugINI );

$ini =& eZINI::instance();

print "<html><head></head>";

if( include_once( "kernel/classes/datatypes/ezuser/ezuser.php" ) )
{
	$currentUser =& eZUser::currentUser();

	$user =& eZUser::currentUser();
	$userID = $user->attribute( 'contentobject_id' );
	$userObject = $user->attribute( 'contentobject' );
	$userName = $userObject->name();

	print "<script language='JavaScript' type='text/javascript'>";
	if  ($currentUser->ContentObjectID== $ini->variable('UserSettings', 'AnonymousUserID' ) )
	{	
		print "var loggedIn=false;";
		print "var userName='';";
	}	
	else {
		print "var loggedIn=true;";
		print "var userName='".$currentUser->Login."';";
	}
	print "if (window.parent &&  window.parent.setupUserLoggedIn!=null) window.parent.setupUserLoggedIn(loggedIn, userName);";
}

print "</script></body></html>";

Then use a login.tpl along the following lines:

{section show=$first}
<ul>
{/section}
<script>
{literal}
function setupUserLoggedIn(loggedIn, UserName)
{
  if (loggedIn) {
     document.getElementById("userNotLoggedIn").style.display="none";
     document.getElementById("loginusername").innerHTML=UserName;
     document.getElementById("userLoggedIn").style.display="inline";
  }
  else {
     document.getElementById("userLoggedIn").style.display="none";
     document.getElementById("loginusername").innerHTML="";
     document.getElementById("userNotLoggedIn").style.display="inline";
  }
}
{/literal}
</script>
<li class="toolbar-item {$placement}">
<span id="userNotLoggedIn" style="display:none"><a href={"/user/login"|ezurl}>{"Login"|i18n("design/standard/toolbar")}</a>&nbsp;</span>
<span id="userLoggedIn" style="display:inline"><a
href={"/user/logout"|ezurl}>{"Logout"|i18n("design/standard/toolbar")}(<span id="loginusername"></span>)</a>&nbsp;</span>
</li>
{section show=$last}
</ul>
{/section}

This solution can be improved to force a fresh request to utils.php by adding a random query string to the src for the IFrame, otherwise there is a risk that a badly configured proxy or web browser cache could result in the wrong user data being obtained. The only risk is that someone else's username would be revealed - they can't do too much with a username alone!

Geraint Edwards

Friday 01 July 2005 2:34:56 am

I thought of a neat trick using mod_rewrite. If you set a cookie (during login or via a hidden IFrame) you can get the webserver to bypass the static cache for admin users.

Just add the following line before the RewriteCond clauses that rewrite the request to the static cache files:

RewriteCond %{HTTP_COOKIE} !<i>adminuser</i>=<i>true</i>

Georg Franz

Friday 01 July 2005 10:13:56 am

Hi Geraint,

good idea + well done! I will try your code soon :-)

Kind regards,
Georg.

Best wishes,
Georg.

--
http://www.schicksal.com Horoskop website which uses eZ Publish since 2004

Kristof Coomans

Thursday 05 October 2006 11:57:30 pm

Hi guys

I tried a setup with <i>RewriteCond %{HTTP_COOKIE} !loggedin=true</i> and it works fine if you add this code in index.php, after the <i>while ( $moduleRunRequired ){ ... }</i> loop:

include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
$userID = eZUser::currentUserID();
$ini =& eZINI::instance();

if ( $userID == (int)$ini->variable( 'UserSettings', 'AnonymousUserID' ) || $userID == 0 )
{
    setcookie( 'loggedin', false, 0, eZSys::wwwDir() );
}
else
{
    setcookie( 'loggedin', 'true', 0, eZSys::wwwDir() );
    header( 'Etag: ' . $userID );
}

The Etag header prevents the browser from loading a cached response from when the user was logged in, after he has logged out.

There are probably better places to put this code but at least it works for now :-)

independent eZ Publish developer and service provider | http://blog.coomanskristof.be | http://ezpedia.org

Kristof Coomans

Monday 19 March 2007 11:38:03 am

On vhost based sites eZSys::wwwDir() can be empty and the cookie doesn't get set for the root of the site but for a subdir. The modified code that fixes this:

include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
$userID = eZUser::currentUserID();
$ini =& eZINI::instance();

$cookiePath = eZSys::wwwDir();
// On host based site accesses this can be empty, causing the cookie to be set for the current dir, 
// but we want it to be set for the whole eZ publish site
if ( $cookiePath == '' )
{
    $cookiePath = '/';
}

if ( $userID == (int)$ini->variable( 'UserSettings', 'AnonymousUserID' ) || $userID == 0 )
{
   setcookie( 'loggedin', false, 0, $cookiePath );
}
else
{
   setcookie( 'loggedin', 'true', 0, $cookiePath );
   header( 'Etag: ' . $userID );
}

independent eZ Publish developer and service provider | http://blog.coomanskristof.be | http://ezpedia.org

Kristof Coomans

Thursday 27 March 2008 1:03:52 am

This feature will be available in eZ Publish 4.1.0. See http://issues.ez.no/11139

independent eZ Publish developer and service provider | http://blog.coomanskristof.be | http://ezpedia.org

André R.

Friday 01 May 2009 2:24:52 am

Note: as mentioned in the issue, if you only check request for this cookie and cache it if the cookie is not present, then a logged in user might 'poison' the cache by rejecting the cookie.
So you should always check back end response where there will be a Set-Cookie: is_logged_in=true header as well as a Etag header with the user id of the user (this might change though, as it's not entirely correct use of etag) as well before storing cache / passing it to client.

This is quite easy to do in vcl (varnish), but might not be as simple to do in other caching solutions. But most of them do not cache if there are Set-Cookie headers in request anyway, so when this is fixed that won't be a problem:
http://issues.ez.no/IssueView.php?Id=14828&activeItem=1

eZ Online Editor 5: http://projects.ez.no/ezoe || eZJSCore (Ajax): http://projects.ez.no/ezjscore || eZ Publish EE http://ez.no/eZPublish/eZ-Publish-Enterprise-Subscription
@: http://twitter.com/andrerom

Powered by eZ Publish™ CMS Open Source Web Content Management. Copyright © 1999-2014 eZ Systems AS (except where otherwise noted). All rights reserved.