Two utility functions to avoid invalid CSRF, ajax request, etc, because for some reason the client session or login ended or changed.
Session/login validity is checked by monitoring specific cookie values.
The first function results in a jQuery dialog proposing to close or reload the page to the user. The second function simply shows an alert box (with some annoying side effects such as requesting the focus of the navigator).
In all cases, the popups are modal here to force the user to reload or close the page.
/** * Monitor if session expired; show jQuery dialog when it did expire. * * Call this somewhere in the page generation process (e.g., in the layout). * * @param int $timeout Time between checks in seconds. */ public static function MonitorSessionJQueryDialog($timeout=2) { Yii::app()->clientScript->registerCoreScript('jquery-ui'); $title=CJavaScript::encode(Yii::t('app','Session Expired')); $msg=CJavaScript::encode(CHtml::tag('div',array(),Yii::t('app','Your session expired and this page must be reloaded.'))); $btReload=CJavaScript::encode(Yii::t('app','Reload')); $btClose=CJavaScript::encode(Yii::t('app','Close')); $jsActionCode="var _ok=false;jQuery($msg).dialog({modal:true,closeOnEscape:false,title:$title,beforeclose:function(){return _ok;},buttons:{ $btClose :function(){_ok=true;jQuery(this).dialog('close');window.open(location.href, '_self').close(); }, $btReload:function(){_ok=true;jQuery(this).dialog('close');location.reload(true);}}});"; self::MonitorSession($timeout,$jsActionCode); } /** * Monitor if session expired, do some JavaScript action when it does expire. * * Call this somewhere in the page generation process (e.g., in the layout). * * @param int $timeout Time between checks in seconds. * @param string $jsActionCode JavaScript action code to do; defaults to alert * popup followad by page reload. */ public static function MonitorSession($timeoutSeconds=2,$jsActionCode=null) { $timeoutMs=$timeoutSeconds*1000; Yii::app()->clientScript->registerCoreScript('jquery'); $md5=md5("MonitorSession".Yii::app()->user->getId()); $name=md5(Yii::app()->id."uid"); if(!Yii::app()->request->cookies->contains('name')) { $cookie = new CHttpCookie($name, $md5); Yii::app()->request->cookies->add($name, $cookie); } else { Yii::app()->request->cookies[$name]->value=$md5; } if($jsActionCode===null) { $expiredMessage=CJavaScript::encode(Yii::t('app','Your session expired and this page must be reloaded.')); $jsActionCode=<<<EOJS alert($expiredMessage); location.reload(true); EOJS; } /* @var string $checkCode JavaScript code that checks the conditions (result in check).*/ $checkCode=""; if(!Yii::app()->user->getIsGuest()) { $stateCookieKey = Yii::app()->user->getStateKeyPrefix(); $checkCode.=<<<EOJS if($.cookie) { var id=$.cookie('$name'); var key=$.cookie('$stateCookieKey'); check|=(id===null||!id.match('$md5')); check|=(key===null); } EOJS; } if(Yii::app()->request->enableCsrfValidation) { $csrfTokenName = CJavaScript::encode(Yii::app()->request->csrfTokenName); $csrfTokenValueRegex= CJavaScript::encode('"'.Yii::app()->request->csrfToken.'"'); $checkCode.=<<<EOJS if($.cookie) { var csrf=$.cookie($csrfTokenName); check|=(csrf===null||!csrf.match($csrfTokenValueRegex)); } EOJS; } if($checkCode!=="") { $jsMonitorScript=<<<EOJS (function($) { "strict"; var timer; function checkSession() { var check=false; $checkCode if(check) { window.clearInterval(timer); $jsActionCode } } function startCheck(){ timer=window.setInterval(checkSession,$timeoutMs); } window.onbeforeunload=function(e){ window.clearInterval(timer); } window.setTimeout(startCheck,5000); })(jQuery); EOJS; Yii::app()->clientScript->registerScript(__FILE__."#MonitorSession", $jsMonitorScript,CClientScript::POS_READY); } }