fixed caching in a couple of places:

- user.php was not reloaded if (session-)preferences changed eg. language via select-box in login, because we used Expires header, but did not force a different url
- (user|config|images).php now has etag on url, to force reload by browser as we use an Expires header (changed images still need Admin >> clear cache to rebuild image cache)
- preferences are now loaded via a cachable GET request
This commit is contained in:
Ralf Becker 2014-01-18 17:43:15 +00:00
parent 8276a2a448
commit 5a8b145b7f
8 changed files with 57 additions and 39 deletions

View File

@ -25,14 +25,13 @@ $GLOBALS['egw_info'] = array(
include '../header.inc.php';
// use an etag over config and link-registry
$config = config::clientConfigs();
$config = json_encode(config::clientConfigs());
$link_registry = egw_link::json_registry();
$etag = '"'.md5(serialize($config).$link_registry).'"';
$etag = '"'.md5($config.$link_registry).'"';
// headers to allow caching
// headers to allow caching, egw_framework specifies etag on url to force reload, even with Expires header
egw_session::cache_control(86400); // cache for one day
Header('Content-Type: text/javascript; charset=utf-8');
Header('Cache-Control: public, no-transform');
Header('Pragma: cache');
Header('ETag: '.$etag);
// if servers send a If-None-Match header, response with 304 Not Modified, if etag matches
@ -42,7 +41,7 @@ if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $
common::egw_exit();
}
$content = 'egw.set_configs('.json_encode($config).");\n";
$content = 'egw.set_configs('.$config.");\n";
$content .= 'egw.set_link_registry('.$link_registry.");\n";
// we run our own gzip compression, to set a correct Content-Length of the encoded content

View File

@ -24,15 +24,14 @@ $GLOBALS['egw_info'] = array(
include '../header.inc.php';
$content = common::image_map(preg_match('/^[a-z0-9_-]+$/i',$_GET['template']) ? $_GET['template'] : null, $_GET['svg']);
$content = json_encode(common::image_map(preg_match('/^[a-z0-9_-]+$/i',$_GET['template']) ? $_GET['template'] : null, $_GET['svg']));
// use an etag over the image mapp
$etag = '"'.md5(serialize($content)).'"';
$etag = '"'.md5($content).'"';
// headers to allow caching
// headers to allow caching, egw_framework specifies etag on url to force reload, even with Expires header
egw_session::cache_control(86400); // cache for one day
Header('Content-Type: text/javascript; charset=utf-8');
Header('Cache-Control: public, no-transform');
Header('Pragma: cache');
Header('ETag: '.$etag);
// if servers send a If-None-Match header, response with 304 Not Modified, if etag matches
@ -42,7 +41,7 @@ if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $
common::egw_exit();
}
$content = 'egw.set_images('.json_encode($content).");\n";
$content = 'egw.set_images('.$content.");\n";
// we run our own gzip compression, to set a correct Content-Length of the encoded content
if (in_array('gzip', explode(',',$_SERVER['HTTP_ACCEPT_ENCODING'])) && function_exists('gzencode'))

View File

@ -1125,11 +1125,23 @@ abstract class egw_framework
$java_script .= $GLOBALS['egw_info']['flags']['java_script_thirst'] . "\n";
}
// add configuration, link-registry, images, user-data and -perferences for non-popup windows
// specifying etag in url to force reload, as we send expires header
if ($GLOBALS['egw_info']['flags']['js_link_registry'])
{
self::validate_file('/phpgwapi/config.php');
self::validate_file('/phpgwapi/images.php',array('template' => $GLOBALS['egw_info']['user']['preferences']['common']['template_set']));
self::validate_file('/phpgwapi/user.php',array('user' => $GLOBALS['egw_info']['user']['account_lid']));
self::validate_file('/phpgwapi/config.php', array(
'etag' => md5(json_encode(config::clientConfigs()).egw_link::json_registry()),
));
self::validate_file('/phpgwapi/images.php', array(
'template' => $GLOBALS['egw_info']['user']['preferences']['common']['template_set'],
'etag' => md5(json_encode(common::image_map($GLOBALS['egw_info']['user']['preferences']['common']['template_set']))),
));
self::validate_file('/phpgwapi/user.php', array(
'user' => $GLOBALS['egw_info']['user']['account_lid'],
'lang' => $GLOBALS['egw_info']['user']['preferences']['common']['lang'],
// add etag on url, so we can set an expires header
'etag' => md5(json_encode($GLOBALS['egw_info']['user']['preferences']['common']).
$GLOBALS['egw']->accounts->json($GLOBALS['egw_info']['user']['account_id'])),
));
}
$extra['url'] = $GLOBALS['egw_info']['server']['webserver_url'];
@ -1870,9 +1882,21 @@ abstract class egw_framework
if (preg_match('/^[a-z0-9_]+$/i', $app))
{
$response = egw_json_response::get();
$pref = $GLOBALS['egw_info']['user']['preferences'][$app];
if(!$pref) $pref = Array();
$response->script('window.egw.set_preferences('.json_encode($pref).', "'.$app.'");');
$pref = json_encode($GLOBALS['egw_info']['user']['preferences'][$app] ?
$GLOBALS['egw_info']['user']['preferences'][$app] : array());
// send etag header, if we are directly called (not via jsonq!)
if (strpos($_GET['menuaction'], __FUNCTION__) !== false)
{
$etag = '"'.$app.'-'.md5($pref).'"';
if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && $_SERVER['HTTP_IF_NONE_MATCH'] == $etag)
{
header("HTTP/1.1 304 Not Modified");
common::egw_exit();
}
header('ETag: '.$etag);
}
$response->script('window.egw.set_preferences('.$pref.', "'.$app.'");');
}
}

View File

@ -15,12 +15,14 @@
/**
* preferences class used for setting application preferences
*
* the prefs are read into 5 arrays:
* $data the effective prefs used everywhere in phpgw, they are merged from the other 3 arrays
* $user the stored user prefs, only used for manipulating and storeing the user prefs
* $group the stored prefs of all group-memberships of current user, can NOT be deleted or stored directly!
* $default the default preferences, always used when the user has no own preference set
* $forced forced preferences set by the admin, they take precedence over user or default prefs
* preferences are read into following arrays:
* - $data effective prefs used everywhere in EGroupware
* Effective prefs are merged together in following precedence from:
* - $forced forced preferences set by the admin, they take precedence over user or default prefs
* - $session temporary prefs eg. language set on login just for session
* - $user the stored user prefs, only used for manipulating and storeing the user prefs
* - $group the stored prefs of all group-memberships of current user, can NOT be deleted or stored directly!
* - $default the default preferences, always used when the user has no own preference set
*
* To update the prefs of a certain group, not just the primary group of the user, you have to
* create a new instance of preferences class, with the given id of the group. This takes into

View File

@ -69,9 +69,9 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) {
/**
* Sends the assembled request to the server
* @param {boolean} [async=false] Overrides async provided in constructor to give an easy way to make simple async requests
* @returns undefined
* @param {string} method='POST' allow to eg. use a (cachable) 'GET' request instead of POST
*/
json_request.prototype.sendRequest = function(async) {
json_request.prototype.sendRequest = function(async,method) {
if(typeof async != "undefined")
{
this.async = async;
@ -95,7 +95,7 @@ egw.extend('json', egw.MODULE_WND_LOCAL, function(_app, _wnd) {
context: this,
data: request_obj,
dataType: 'json',
type: 'POST',
type: method || 'POST',
success: this.handleResponse,
error: function(_xmlhttp, _err) {
this.egw.debug('error', 'Ajax request to', this.url, ' failed:',

View File

@ -62,8 +62,8 @@ egw.extend('preferences', egw.MODULE_GLOBAL, function() {
if (typeof prefs[_app] == 'undefined')
{
var request = this.json('home.egw_framework.ajax_get_preference.template', [_app],null,null,false);
request.sendRequest();
var request = this.json('home.egw_framework.ajax_get_preference.template', [_app]);
request.sendRequest(false, 'GET'); // use synchronous (cachable) GET request
if (typeof prefs[_app] == 'undefined') prefs[_app] = {};
}
if(_name == "*") return prefs[_app];

View File

@ -32,14 +32,9 @@ include '../header.inc.php';
// use an etag with app, lang and a hash over the creation-times of all lang-files
$etag = '"'.$_GET['app'].'-'.$_GET['lang'].'-'.translation::etag($_GET['app'], $_GET['lang']).'"';
// tell browser/caches to cache for one day, we change url on real modifications
$expires = 864000; // 10days
// headers to allow caching of one month
// headers to allow caching, we specify etag on url to force reload, even with Expires header
egw_session::cache_control(864000); // cache for 10 days
Header('Content-Type: text/javascript; charset=utf-8');
Header('Cache-Control: public, no-transform, max-age='.$expires);
header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$expires) . ' GMT');
Header('Pragma: cache');
Header('ETag: '.$etag);
// if servers send a If-None-Match header, response with 304 Not Modified, if etag matches

View File

@ -29,10 +29,9 @@ $preferences = json_encode($GLOBALS['egw_info']['user']['preferences']['common']
$user = $GLOBALS['egw']->accounts->json($GLOBALS['egw_info']['user']['account_id']);
$etag = '"'.md5($preferences.$user).'"';
// headers to allow caching
// headers to allow caching, egw_framework specifies etag on url to force reload, even with Expires header
egw_session::cache_control(86400); // cache for 1 day
Header('Content-Type: text/javascript; charset=utf-8');
Header('Cache-Control: public, no-transform');
Header('Pragma: cache');
Header('ETag: '.$etag);
// if servers send a If-None-Match header, response with 304 Not Modified, if etag matches