1
0
mirror of https://github.com/e107inc/e107.git synced 2025-08-08 07:36:32 +02:00

Great Javascript server & browser cache control - more performance, less server CPU and site traffic

This commit is contained in:
secretr
2009-10-02 13:46:26 +00:00
parent 38431a75f8
commit 917ffedade
3 changed files with 282 additions and 170 deletions

View File

@@ -1,137 +1,168 @@
<?php <?php
/* /*
* e107 website system * e107 website system
* *
* Copyright (c) 2001-2008 e107 Developers (e107.org) * Copyright (c) 2001-2008 e107 Developers (e107.org)
* Released under the terms and conditions of the * Released under the terms and conditions of the
* GNU General Public License (http://gnu.org). * GNU General Public License (http://gnu.org).
* *
* Javascript files consolidation script (gzip compression) * Javascript files consolidation script (gzip compression)
* *
* $Source: /cvs_backup/e107_0.8/e107_files/e_jslib.php,v $ * $Source: /cvs_backup/e107_0.8/e107_files/e_jslib.php,v $
* $Revision: 1.4 $ * $Revision: 1.5 $
* $Date: 2009-09-29 17:40:56 $ * $Date: 2009-10-02 13:46:26 $
* $Author: secretr $ * $Author: secretr $
* *
*/ */
// prevent notices/warnings to break JS source // prevent notices/warnings to break JS source
error_reporting(0); error_reporting(0);
//output cache if available before calling the api //output cache if available before calling the api
e_jslib_cache_out(); e_jslib_cache_out();
//v0.8 - we need THEME defines here (do we?) - WE DON'T //v0.8 - we need THEME defines here (do we?) - WE DON'T
//$_E107 = array('no_forceuserupdate' => 1, 'no_online' => 1, 'no_menus' => 1, 'no_prunetmp' => 1); //$_E107 = array('no_forceuserupdate' => 1, 'no_online' => 1, 'no_menus' => 1, 'no_prunetmp' => 1);
$_E107['minimal'] = true; $_E107['minimal'] = true;
//admin or front-end call //admin or front-end call
if(strpos($_SERVER['QUERY_STRING'], '_admin') !== FALSE) if (strpos($_SERVER['QUERY_STRING'], '_admin') !== FALSE)
{ {
define('ADMIN_AREA', true); //force admin area define('ADMIN_AREA', true); //force admin area
} }
else else
{ {
define('USER_AREA', true); //force user area define('USER_AREA', true); //force user area
} }
//call jslib handler, render content //call jslib handler, render content
require_once("../class2.php"); require_once ("../class2.php");
require_once(e_HANDLER.'jslib_handler.php'); require_once (e_HANDLER.'jslib_handler.php');
$jslib = new e_jslib(); $jslib = new e_jslib();
$jslib->core_run(); $jslib->core_run();
exit; exit;
//
// FUNCTIONS required for retrieveing cache without e107 API
//
/** /**
* FUNCTIONS required for retrieveing cache without e107 API * Output cache file contents if available (doesn't require e107 API)
* *
*/ * @return void
*/
/** function e_jslib_cache_out()
* Output cache file contents if available (doesn't require e107 API) {
* $encoding = e_jslib_browser_enc(); //NOTE - should be called first
*/ $cacheFile = e_jslib_is_cache($encoding);
function e_jslib_cache_out() {
$encoding = e_jslib_browser_enc(); if ($cacheFile)
$cacheFile = e_jslib_is_cache($encoding); {
if (function_exists('date_default_timezone_set'))
if($cacheFile) { {
while (@ob_end_clean()); // kill all output buffering for better performance date_default_timezone_set('UTC');
}
header("Last-modified: " . gmdate("D, d M Y H:i:s",mktime(0,0,0,15,2,2004)) . " GMT");
header('Content-type: text/javascript', TRUE);
if($encoding)
header('Content-Encoding: '.$encoding);
echo @file_get_contents($cacheFile);
//TODO - log
//@file_put_contents('cache/e_jslib_log', "----------\ncache used - ".$cacheFile."\n\n", FILE_APPEND);
exit;
}
}
/**
* Check jslib cache (doesn't require e107 API)
*
* @param string $encoding browser accepted encoding
* @return mixed cache filename on success or false otherwise
*/
function e_jslib_is_cache($encoding) {
$cacheFile = e_jslib_cache_file($encoding);
$mAge = 24 * 60;
if(is_file($cacheFile) && is_readable($cacheFile)) { // last modification time
$lmodified = filemtime($cacheFile);
// not modified - send 304 and exit
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lmodified)
{
header("HTTP/1.1 304 Not Modified", true);
exit;
}
// send last modified date
header('Cache-Control: must-revalidate');
header('Last-modified: '.gmdate('r', $lmodified), true);
// send content type and encoding
header('Content-type: text/javascript', true);
if ($encoding)
{
header('Content-Encoding: '.$encoding, true);
}
// Expire header - 1 year
$time = time()+ 365 * 86400;
header('Expires: '.gmdate('r', $time), true);
//kill any output buffering - better performance
while (@ob_end_clean());
echo @file_get_contents($cacheFile);
//TODO - debug
//@file_put_contents('cache/e_jslib_log', "----------\ncache used - ".$cacheFile."\n\n", FILE_APPEND);
exit;
}
}
if ((@filemtime($cacheFile) + ($mAge * 60)) < time()) { /**
unlink($cacheFile); * Check jslib cache (doesn't require e107 API)
return false; *
} * @param string $encoding browser accepted encoding
* @return string cache filename on success or empty string otherwise
return $cacheFile; */
} function e_jslib_is_cache($encoding)
{
return false; $cacheFile = e_jslib_cache_filename($encoding);
} if (is_file($cacheFile) && is_readable($cacheFile))
{
/** return $cacheFile;
* Detect browser accepted encoding (doesn't require e107 API) }
*
* @return string encoding return '';
*/ }
function e_jslib_browser_enc() {
/**
//double-compression fix - thanks Topper * Detect browser accepted encoding (doesn't require e107 API)
if( headers_sent() || ini_get('zlib.output_compression') || !isset($_SERVER["HTTP_ACCEPT_ENCODING"]) ){ * It'll always return empty string if '_nogzip' found in QUERY_STRING
*
$encoding = ''; * @return string encoding
} elseif ( strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'x-gzip') !== false ){ */
function e_jslib_browser_enc()
$encoding = 'x-gzip'; {
} elseif ( strpos($_SERVER["HTTP_ACCEPT_ENCODING"],'gzip') !== false ){ //NEW - option to disable completely gzip compression
if(strpos($_SERVER['QUERY_STRING'], '_nogzip') !== false)
$encoding = 'gzip'; {
} else { return '';
}
$encoding = ''; //double-compression fix - thanks Topper
} if (headers_sent() || ini_get('zlib.output_compression') || !isset($_SERVER["HTTP_ACCEPT_ENCODING"]))
{
return $encoding; $encoding = '';
} }
elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'x-gzip') !== false)
/** {
* Creates cache filename (doesn't require e107 API) $encoding = 'x-gzip';
* }
* @param string $encoding elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false)
* @return string cache filename {
*/ $encoding = 'gzip';
function e_jslib_cache_file($encoding='') { }
else
$cacheDir = './cache/'; {
$hash = $_SERVER['QUERY_STRING'] ? md5($_SERVER['QUERY_STRING']) : 'nomd5'; $encoding = '';
$cacheFile = $cacheDir.'S_e_jslib'.($encoding ? '_'.$encoding : '').'_'.$hash.'.cache.php'; }
return $cacheFile; return $encoding;
} }
/**
* Creates cache filename (doesn't require e107 API)
*
* @param string $encoding
* @return string cache filename
*/
function e_jslib_cache_filename($encoding = '')
{
$cacheDir = './cache/';
$hash = $_SERVER['QUERY_STRING'] && $_SERVER['QUERY_STRING'] !== '_nogzip' ? md5(str_replace('_nogzip', '', $_SERVER['QUERY_STRING'])) : 'nomd5';
$cacheFile = $cacheDir.'S_e_jslib'.($encoding ? '_'.$encoding : '').'_'.$hash.'.cache.php';
return $cacheFile;
}
?> ?>

View File

@@ -7,8 +7,8 @@
* GNU General Public License (http://gnu.org). * GNU General Public License (http://gnu.org).
* *
* $Source: /cvs_backup/e107_0.8/e107_handlers/js_manager.php,v $ * $Source: /cvs_backup/e107_0.8/e107_handlers/js_manager.php,v $
* $Revision: 1.3 $ * $Revision: 1.4 $
* $Date: 2009-10-01 15:05:41 $ * $Date: 2009-10-02 13:46:25 $
* $Author: secretr $ * $Author: secretr $
* *
*/ */
@@ -85,7 +85,12 @@ class e_jsmanager
* *
* @var integer * @var integer
*/ */
protected $_cache_id = 0; protected $_browser_cache_id = 0;
/**
* @var array
*/
protected $_lastModified = array();
/** /**
* Singleton instance * Singleton instance
@@ -496,21 +501,21 @@ class e_jsmanager
switch($mod) switch($mod)
{ {
case 'core': case 'core': //e_jslib
$this->renderFile($this->_e_jslib_core, $external, 'Core libraries'); $this->setLastModfied($mod, $this->renderFile($this->_e_jslib_core, $external, 'Core libraries'));
$this->_e_jslib_core = array(); $this->_e_jslib_core = array();
break; break;
case 'plugin': case 'plugin': //e_jslib
foreach($this->_e_jslib_plugin as $plugname => $paths) foreach($this->_e_jslib_plugin as $plugname => $paths)
{ {
$this->renderFile($paths, $external, $plugname.' libraries'); $this->setLastModfied($mod, $this->renderFile($paths, $external, $plugname.' libraries'));
} }
$this->_e_jslib_plugin = array(); $this->_e_jslib_plugin = array();
break; break;
case 'theme': case 'theme': //e_jslib
$this->renderFile($this->_e_jslib_theme, $external, 'Theme libraries'); $this->setLastModfied($mod, $this->renderFile($this->_e_jslib_theme, $external, 'Theme libraries'));
$this->_e_jslib_theme = array(); $this->_e_jslib_theme = array();
break; break;
@@ -576,7 +581,7 @@ class e_jsmanager
* @param string $label added as comment if non-empty * @param string $label added as comment if non-empty
* @return void * @return void
*/ */
public function renderFile($file_path_array, $external = false, $label = '') public function renderFile($file_path_array, $external = false, $label = '', $checkModified = true)
{ {
if(empty($file_path_array)) if(empty($file_path_array))
{ {
@@ -588,6 +593,8 @@ class e_jsmanager
{ {
echo "<!-- [JSManager] ".$label." -->\n"; echo "<!-- [JSManager] ".$label." -->\n";
} }
$lmodified = 0;
foreach ($file_path_array as $path) foreach ($file_path_array as $path)
{ {
if (substr($path, - 4) == '.php') if (substr($path, - 4) == '.php')
@@ -598,7 +605,10 @@ class e_jsmanager
echo "\n"; echo "\n";
continue; continue;
} }
include_once($tp->replaceConstants($path, ''));
$path = $tp->replaceConstants($path, '');
if($checkModified) $lmodified = max($lmodified, filemtime($path));
include_once($path);
echo "\n"; echo "\n";
} }
else else
@@ -609,10 +619,15 @@ class e_jsmanager
echo "\n"; echo "\n";
continue; continue;
} }
echo file_get_contents($tp->replaceConstants($path, ''));
$path = $tp->replaceConstants($path, '');
if($checkModified) $lmodified = max($lmodified, filemtime($path));
echo file_get_contents($path);
echo "\n"; echo "\n";
} }
} }
return $lmodified;
} }
/** /**
@@ -692,7 +707,7 @@ class e_jsmanager
*/ */
public function getCacheId() public function getCacheId()
{ {
return $this->_cache_id; return $this->_browser_cache_id;
} }
/** /**
@@ -702,7 +717,31 @@ class e_jsmanager
*/ */
public function setCacheId($cacheid) public function setCacheId($cacheid)
{ {
$this->_cache_id = $cacheid; $this->_browser_cache_id = intval($cacheid);
return $this; return $this;
} }
/**
* Set last modification timestamp for given namespace
*
* @param string $what
* @param integer $when [optional]
* @return e_jsmanager
*/
public function setLastModfied($what, $when = 0)
{
$this->_lastModified[$what] = $when;
return $this;
}
/**
* Get last modification timestamp for given namespace
*
* @param string $what
* @return integer
*/
public function getLastModfied($what)
{
return (isset($this->_lastModified[$what]) ? $this->_lastModified[$what] : 0);
}
} }

View File

@@ -7,8 +7,8 @@
* GNU General Public License (http://gnu.org). * GNU General Public License (http://gnu.org).
* *
* $Source: /cvs_backup/e107_0.8/e107_handlers/jslib_handler.php,v $ * $Source: /cvs_backup/e107_0.8/e107_handlers/jslib_handler.php,v $
* $Revision: 1.6 $ * $Revision: 1.7 $
* $Date: 2009-09-29 17:40:55 $ * $Date: 2009-10-02 13:46:25 $
* $Author: secretr $ * $Author: secretr $
* *
*/ */
@@ -26,13 +26,13 @@ class e_jslib
* Collect & output all available JS libraries (requires e107 API) * Collect & output all available JS libraries (requires e107 API)
* FIXME * FIXME
* - cache jslib in a pref on plugin/theme install only (plugin.xml, theme.xml) * - cache jslib in a pref on plugin/theme install only (plugin.xml, theme.xml)
* - the structure of the cached pref array? * - [done - e_jslib_*] the structure of the cached pref array?
* - kill all dupps * - [done - js manager] kill all dupps
* - jslib settings - Administration area (compression on/off, admin log on/off * - jslib settings - Administration area (compression on/off, admin log on/off
* manual control for included JS - really not sure about this, * manual control for included JS - really not sure about this,
* Force Browser Cache refresh - timestamp added to the url hash) * Force Browser Cache refresh - timestamp added to the url hash)
* - how and when to add JS lans for core libraries? * - how and when to add JS lans for core libraries?
* - separate methods for collecting & storing JS files (to be used in install/update routines) and output the JS content * - [done - js manager] separate methods for collecting & storing JS files (to be used in install/update routines) and output the JS content
*/ */
function core_run() function core_run()
{ {
@@ -40,18 +40,54 @@ class e_jslib
ob_start(); ob_start();
ob_implicit_flush(0); ob_implicit_flush(0);
header("Last-modified: " . gmdate("D, d M Y H:i:s",mktime(0,0,0,15,2,2004)) . " GMT");
header('Content-type: text/javascript', TRUE);
$e_jsmanager = e107::getJs(); $e_jsmanager = e107::getJs();
$lmodified = array();
$e_jsmanager->renderJs('core', null, false); $e_jsmanager->renderJs('core', null, false);
$lmodified[] = $e_jsmanager->getLastModfied('core');
$e_jsmanager->renderJs('plugin', null, false); $e_jsmanager->renderJs('plugin', null, false);
$lmodified[] = $e_jsmanager->getLastModfied('plugin');
$e_jsmanager->renderJs('theme', null, false); $e_jsmanager->renderJs('theme', null, false);
$lmodified[] = $e_jsmanager->getLastModfied('theme');
$lmodified[] = $e_jsmanager->getCacheId(); //e107::getPref('e_jslib_browser_cache', 0)
// last modification time for loaded files
$lmodified = max($lmodified);
if (function_exists('date_default_timezone_set'))
{
date_default_timezone_set('UTC');
}
// If-Modified check only if cache disabled
// if cache is enabled, cache file modification date is set to $lmodified
if(!e107::getPref('syscachestatus'))
{
// not modified - send 304 and exit
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $lmodified)
{
header("HTTP/1.1 304 Not Modified", true);
exit;
}
}
// send last modified date
header('Cache-Control: must-revalidate');
header('Last-modified: '.gmdate('r', $lmodified), true);
// send content type
header('Content-type: text/javascript', true);
// Expire header - 1 year
$time = time()+ 365 * 86400;
header('Expires: '.gmdate('r', $time), true);
//Output //Output
$this->content_out(); $this->content_out($lmodified);
/* /*
//array - uses the same format as $core_jslib //array - uses the same format as $core_jslib
if (!isset($THEME_CORE_JSLIB) || ! is_array($THEME_CORE_JSLIB)) if (!isset($THEME_CORE_JSLIB) || ! is_array($THEME_CORE_JSLIB))
@@ -152,7 +188,7 @@ class e_jslib
* Output buffered content (requires e107 API) * Output buffered content (requires e107 API)
* *
*/ */
function content_out() function content_out($lmodified)
{ {
global $pref, $admin_log; global $pref, $admin_log;
@@ -172,7 +208,7 @@ class e_jslib
$gzdata .= pack("V", $crc) . pack("V", $size); $gzdata .= pack("V", $crc) . pack("V", $size);
$gsize = strlen($gzdata); $gsize = strlen($gzdata);
$this->set_cache($gzdata, $encoding); $this->set_cache($gzdata, $encoding, $lmodified);
header('Content-Encoding: ' . $encoding); header('Content-Encoding: ' . $encoding);
//header('Content-Length: '.$gsize); //header('Content-Length: '.$gsize);
@@ -184,7 +220,7 @@ class e_jslib
else else
{ {
//header('Content-Length: '.strlen($contents)); //header('Content-Length: '.strlen($contents));
$this->set_cache($contents); $this->set_cache($contents, '', $lmodified);
print($contents); print($contents);
//TODO - log/debug //TODO - log/debug
//@file_put_contents('cache/e_jslib_log', "----------\nno cache used - raw\n\n", FILE_APPEND); //@file_put_contents('cache/e_jslib_log', "----------\nno cache used - raw\n\n", FILE_APPEND);
@@ -198,17 +234,17 @@ class e_jslib
* *
* @param string $contents * @param string $contents
* @param string $encoding browser accepted encoding * @param string $encoding browser accepted encoding
* @param integer $lmodified last modfied time
*/ */
function set_cache($contents, $encoding = '') function set_cache($contents, $encoding = '', $lmodified = 0)
{ {
global $pref; if (e107::getPref('syscachestatus'))
if (varsettrue($pref['syscachestatus']))
{ {
$cacheFile = $this->cache_file($encoding); $cacheFile = $this->cache_filename($encoding);
if(!$lmodified) $lmodified = time();
@file_put_contents($cacheFile, $contents); @file_put_contents($cacheFile, $contents);
@chmod($cacheFile, 0775); @chmod($cacheFile, 0775);
@touch($cacheFile); @touch($cacheFile, $lmodified);
} }
} }
@@ -219,37 +255,43 @@ class e_jslib
*/ */
function browser_enc() function browser_enc()
{ {
//double-compression fix (thanks Topper), remove possible php warning //NEW - option to disable completely gzip compression
if ( headers_sent() || ini_get('zlib.output_compression') || !isset($_SERVER["HTTP_ACCEPT_ENCODING"]) ) if(strpos($_SERVER['QUERY_STRING'], '_nogzip'))
{ {
$encoding = ''; return '';
} }
elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'x-gzip') !== false) //double-compression fix - thanks Topper
{ if (headers_sent() || ini_get('zlib.output_compression') || !isset($_SERVER["HTTP_ACCEPT_ENCODING"]))
$encoding = 'x-gzip'; {
} $encoding = '';
elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false) }
{ elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'x-gzip') !== false)
$encoding = 'gzip'; {
} $encoding = 'x-gzip';
else }
{ elseif (strpos($_SERVER["HTTP_ACCEPT_ENCODING"], 'gzip') !== false)
$encoding = ''; {
} $encoding = 'gzip';
return $encoding; }
else
{
$encoding = '';
}
return $encoding;
} }
/** /**
* Create cache filename (doesn't require e107 API) * Create cache filename (doesn't require e107 API)
* *
* @param string $encoding * @param string $encoding
* @param string $cacheStr * @param string $cacheStr defaults to 'S_e_jslib'
* @return string cache filename * @return string cache filename
*/ */
function cache_file($encoding = '', $cacheStr = 'S_e_jslib') function cache_filename($encoding = '', $cacheStr = 'S_e_jslib')
{ {
$cacheDir = 'cache/'; $cacheDir = 'cache/';
$hash = $_SERVER['QUERY_STRING'] ? md5($_SERVER['QUERY_STRING']) : 'nomd5'; $hash = $_SERVER['QUERY_STRING'] && $_SERVER['QUERY_STRING'] !== '_nogzip' ? md5(str_replace('_nogzip', '', $_SERVER['QUERY_STRING'])) : 'nomd5';
$cacheFile = $cacheDir . $cacheStr . ($encoding ? '_' . $encoding : '') . '_' . $hash . '.cache.php'; $cacheFile = $cacheDir . $cacheStr . ($encoding ? '_' . $encoding : '') . '_' . $hash . '.cache.php';
return $cacheFile; return $cacheFile;