' . implode("\n", array_slice(explode("\n", @file_get_contents($file)), 2)) . '';
}
break;
case 'admin/settings/performance/boost':
return '
' . t('') . '
'; // TODO: add help text.
}
//hack to get drupal_get_messages before they are destroyed.
$GLOBALS['_boost_message_count'] = count(drupal_get_messages(NULL, FALSE));
}
/**
* Implementation of hook_views_pre_render().
*
* This is called right before the render process. Used to grab the NID's listed
* in this view, and set the view node relationship in the database.
*
* @param &$view
* reference to the view being worked on
*/
function boost_views_pre_render(&$view) {
if (!is_null($view) && $GLOBALS['_boost_cache_this']) {
foreach ($view->result as $item) {
$node = node_load($item->nid);
$GLOBALS['_boost_relationships'][] = array('child_page_callback' => 'node', 'child_page_type' => $node->type, 'child_page_id' => $item->nid);
}
}
}
/**
* Implementation of hook_init(). Performs page setup tasks if page not cached.
*/
function boost_init() {
// Disable all caches when nocache is set
if (isset($_GET['nocache'])) {
$GLOBALS['conf']['cache'] = CACHE_DISABLED;
$GLOBALS['_boost_cache_this'] = FALSE;
return;
}
global $user, $base_path;
//set variables
$GLOBALS['_boost_path'] = $_REQUEST['q'];
// Make the proper filename for our query
$GLOBALS['_boost_query'] = BOOST_CHAR;
foreach ($_GET as $key => $val) {
if ($key != 'q' && $key != 'destination') {
$GLOBALS['_boost_query'] .= (($GLOBALS['_boost_query'] == BOOST_CHAR) ? '' : '&') . $key . '=' . $val;
}
}
if (!empty($user->uid)) {
boost_set_cookie($user);
if (BOOST_DISABLE_CLEAN_URL) {
$GLOBALS['conf']['clean_url'] = 0;
db_query('TRUNCATE {cache_filter}');
db_query('TRUNCATE {cache_menu}');
cache_clear_all('*', 'cache_menu');
cache_clear_all('*', 'cache_filter');
}
}
// Make sure the page is/should be cached according to our current configuration
if ( strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === FALSE
|| variable_get('site_offline', 0)
|| $_SERVER['REQUEST_METHOD'] != 'GET'
|| $_SERVER['SERVER_SOFTWARE'] === 'PHP CLI'
|| !BOOST_ENABLED
|| !boost_is_cacheable($GLOBALS['_boost_path'])
) {
$GLOBALS['_boost_cache_this'] = FALSE;
return;
}
// We only generate cached pages for anonymous visitors.
if (empty($user->uid)) {
if (BOOST_ENABLED != CACHE_AGGRESSIVE) {
$GLOBALS['conf']['cache'] = CACHE_DISABLED;
}
$GLOBALS['_boost_cache_this'] = TRUE;
register_shutdown_function('_boost_ob_handler');
ob_start();
}
}
/**
* Implementation of hook_exit(). Performs cleanup tasks.
*
* For POST requests by anonymous visitors, this adds a dummy query string
* to any URL being redirected to using drupal_goto().
*
* This is pretty much a hack that assumes a bit too much familiarity with
* what happens under the hood of the Drupal core function drupal_goto().
*
* It's necessary, though, in order for any session messages set on form
* submission to actually show up on the next page if that page has been
* cached by Boost.
*/
function boost_exit($destination = NULL) {
// Check that hook_exit() was invoked by drupal_goto() for a POST request:
if (!empty($destination) && $_SERVER['REQUEST_METHOD'] == 'POST') {
// Check that we're dealing with an anonymous visitor. and that some
// session messages have actually been set during this page request:
global $user;
if (empty($user->uid) && ($messages = drupal_set_message())) {
// FIXME: call any remaining exit hooks since we're about to terminate?
$query_parts = parse_url($destination);
// Add a nocache parameter to query. Such pages will never be cached
$query_parts['query'] .= (empty($query_parts['query']) ? '' : '&') . 'nocache=1';
// Rebuild the URL with the new query string. Do not use url() since
// destination has presumably already been run through url().
$destination = boost_glue_url($query_parts);
// Do what drupal_goto() would do if we were to return to it:
exit(header('Location: ' . $destination));
}
}
}
/**
* Implementation of hook_menu().
*/
function boost_menu() {
$items['admin/settings/performance/default'] = array(
'title' => 'Performance',
'type' => MENU_DEFAULT_LOCAL_TASK,
'file path' => drupal_get_path('module', 'system'),
);
$items['admin/settings/performance/boost'] = array(
'title' => 'Boost Settings',
'description' => 'Advanced boost configuration.',
'page callback' => 'drupal_get_form',
'page arguments' => array('boost_admin_boost_performance_page'),
'access arguments' => array('administer site configuration'),
'weight' => 10,
'type' => MENU_LOCAL_TASK,
'file' => 'boost.admin.inc',
);
$items['admin/settings/performance/boost-rules'] = array(
'title' => 'Boost htaccess rules generation',
'description' => 'htaccess boost rules.',
'page callback' => 'drupal_get_form',
'page arguments' => array('boost_admin_htaccess_page'),
'access arguments' => array('administer site configuration'),
'weight' => 12,
'type' => MENU_LOCAL_TASK,
'file' => 'boost.admin.inc',
);
$items['boost_stats.php'] = array(
'page callback' => 'boost_stats_ajax_callback',
'type' => MENU_CALLBACK,
'access callback' => 1,
'access arguments' => array('access content'),
'file path' => drupal_get_path('module', 'boost'),
'file' => 'stats/boost_stats.ajax.inc',
);
$items['boost-crawler'] = array(
'page callback' => 'boost_crawler_run',
'type' => MENU_CALLBACK,
'access callback' => 1,
'access arguments' => array('access content'),
'file path' => drupal_get_path('module', 'boost'),
);
return $items;
}
/**
* Implementation of hook_form_alter(). Performs alterations before a form
* is rendered.
*/
function boost_form_alter(&$form, $form_state, $form_id) {
switch ($form_id) {
// Alter Drupal's system performance settings form by hiding the default
// cache enabled/disabled control (which will now always default to
// CACHE_DISABLED), and inject our own settings in its stead.
case 'system_performance_settings':
module_load_include('inc', 'boost', 'boost.admin');
$form['page_cache'] = boost_admin_performance_page($form['page_cache']);
$form['#submit'][] = 'boost_admin_performance_page_submit';
$form['clear_cache']['clear']['#submit'][0] = 'boost_admin_clear_cache_submit';
break;
// Alter Drupal's site maintenance settings form in order to ensure that
// the static page cache gets wiped if the administrator decides to take
// the site offline.
case 'system_site_maintenance_settings':
module_load_include('inc', 'boost', 'boost.admin');
$form['#submit'][] = 'boost_admin_site_offline_submit';
break;
// Alter Drupal's modules build form in order to ensure that
// the static page cache gets wiped if the administrator decides to
// change enabled modules
case 'system_modules':
module_load_include('inc', 'boost', 'boost.admin');
$form['#submit'][] = 'boost_admin_modules_submit';
break;
// Alter Drupal's theme build form in order to ensure that
// the static page cache gets wiped if the administrator decides to
// change theme
case 'system_themes_form':
module_load_include('inc', 'boost', 'boost.admin');
$form['#submit'][] = 'boost_admin_themes_submit';
// Added below due to this bug: http://drupal.org/node/276615
if ( variable_get('preprocess_css', FALSE)==TRUE
&& floatval(VERSION) <= 6.13
&& boost_cache_clear_all()
) {
drupal_set_message(t('Boost: Static page cache cleared. See http://drupal.org/node/276615 for reason why (core bug that is fixed in 6.14+).'), 'warning');
}
break;
}
}
/**
* Implementation of hook_cron(). Performs periodic actions.
*/
function boost_cron() {
if (!BOOST_ENABLED) {
return;
}
$expire = TRUE;
if (BOOST_CHECK_BEFORE_CRON_EXPIRE) {
$expire = boost_has_site_changed(TRUE);
}
// Expire old content
if (!BOOST_LOOPBACK_BYPASS && variable_get('boost_expire_cron', TRUE) && $expire && boost_cache_db_expire()) {
if (BOOST_VERBOSE >= 5) {
watchdog('boost', 'Expired stale files from static page cache.', array(), WATCHDOG_NOTICE);
}
}
// Update Stats
if (module_exists('statistics') && variable_get('boost_block_show_stats', FALSE)) {
$block = module_invoke('statistics', 'block', 'view', 0);
variable_set('boost_statistics_html', $block['content']);
}
// Crawl Site
if (BOOST_CRAWL_ON_CRON && !variable_get('site_offline', 0)) {
boost_crawler_run((int)$expire);
}
}
/*
* Implementation of hook_flush_caches(). Deletes all static files.
*/
function boost_flush_caches() {
if (variable_get('cron_semaphore', FALSE)==FALSE && (variable_get('preprocess_css', FALSE)==TRUE || variable_get('preprocess_js', FALSE)==TRUE)) {
boost_cache_clear_all();
}
return;
}
/**
* Implementation of hook_comment(). Acts on comment modification.
*/
function boost_comment($comment, $op) {
if (!BOOST_ENABLED) return;
switch ($op) {
case 'insert':
case 'update':
// Expire the relevant node page from the static page cache to prevent serving stale content:
if (!empty($comment['nid'])) {
$node = node_load($comment['nid']);
boost_expire_node($node);
}
break;
case 'publish':
case 'unpublish':
case 'delete':
if (!empty($comment->nid)) {
$node = node_load($comment->nid);
boost_expire_node($node);
}
break;
}
}
/**
* Implementation of hook_nodeapi(). Acts on nodes defined by other modules.
*/
function boost_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
if (!BOOST_ENABLED) return;
switch ($op) {
case 'insert':
if (BOOST_FLUSH_VIEWS_INSERT && module_exists('views')) {
$GLOBALS['_boost_nid'] = $node->nid;
register_shutdown_function('_boost_view_insert');
}
case 'update':
case 'delete':
boost_expire_node($node);
break;
}
}
/**
* Shutdown function, gets called at the very end of node creation.
*
* Node is now created, thus views has access to the new node. Searches all
* cached views for newly created node. Expires the outdated views from the cache.
*/
function _boost_view_insert() {
$result = db_query("SELECT * FROM {boost_cache} WHERE base_dir = '%s' AND page_callback = 'view' AND expire > 0 AND expire <> 434966400", BOOST_FILE_PATH);
$data = array();
while ($boost = db_fetch_array($result)) {
$view = views_get_view($boost['page_type']);
$view->set_display($boost['page_id']);
$view->pre_execute();
$view->set_items_per_page(0);
$view->execute();
foreach ($view->result as $item) {
if ($item->nid == $GLOBALS['_boost_nid']) {
$hash = BOOST_FILE_PATH . 'view' . $boost['page_type'] . $boost['page_id'];
$data[$hash] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => 'view', 'page_type' => $boost['page_type'], 'page_id' => $boost['page_id']);
}
}
}
boost_cache_expire_router($data);
}
/**
* Implementation of hook_votingapi_insert().
*
* @param $votes
* array of votes
*/
function boost_votingapi_insert($votes) {
if (!BOOST_ENABLED) return;
foreach ($votes as $vote) {
$node = node_load($vote['content_id']);
boost_expire_node($node);
}
}
/**
* Implementation of hook_votingapi_delete().
*
* @param $votes
* array of votes
*/
function boost_votingapi_delete($votes) {
if (!BOOST_ENABLED) return;
foreach ($votes as $vote) {
$node = node_load($vote['content_id']);
boost_expire_node($node);
}
}
/**
* Expires a node from the cache.
*
* @param $node
* node object
*/
function boost_expire_node($node) {
if (empty($node->nid)) {
return FALSE;
}
// Expire all relevant node pages from the static page cache to prevent serving stale content:
if ($node->promote == 1) {
boost_cache_expire_derivative('');
}
boost_cache_expire_derivative('node/' . $node->nid);
// Get terms and flush their page
if (module_exists('taxonomy') && BOOST_FLUSH_NODE_TERMS) {
$tids = boost_taxonomy_node_get_tids($node->nid);
$filenames = array();
foreach ($tids as $tid) {
$filenames = array_merge($filenames, boost_get_db_term($tid));
}
foreach ($filenames as $filename) {
boost_cache_kill($filename['filename'], $filename['hash']);
}
}
if (BOOST_FLUSH_CCK_REFERENCES && module_exists('nodereference')) {
// Get CCK References and flush.
$nids = array();
$type = content_types($node->type);
foreach ($type['fields'] as $field) {
// Add referenced nodes to nids. This will clean up nodereferrer fields
// when the referencing node is updated.
if ($field['type'] == 'nodereference') {
$node_field = isset($node->$field['field_name']) ? $node->$field['field_name'] : array();
foreach ($node_field as $delta => $item) {
$nids[$item['nid']] = $item['nid'];
}
}
}
foreach ($nids as $nid) {
boost_cache_expire_derivative('node/' . $nid);
}
// Get CCK references pointing to this node and flush.
if (module_exists('nodereferrer')) {
$nids = nodereferrer_referrers($node->nid);
foreach ($nids as $nid) {
boost_cache_expire_derivative('node/' . $nid['nid']);
}
}
}
if (BOOST_FLUSH_VIEWS && module_exists('views')) {
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$data = array();
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback'], 'page_type' => $router_item['page_type'], 'page_id' => $router_item['page_id']);
$relationships = boost_cache_get_node_relationships($data);
boost_cache_expire_router($relationships);
}
}
/**
* Return taxonomy terms given a nid.
*
* Needed because of a weird bug with CCK & node_load()
* http://drupal.org/node/545922
*/
function boost_taxonomy_node_get_tids($nid) {
$vid = db_result(db_query('SELECT vid FROM {node} WHERE nid = %d', $nid));
$result = db_query(db_rewrite_sql('SELECT t.tid FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.vid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $vid);
$tids = array();
while ($term = db_result($result)) {
$tids[] = $term;
}
return $tids;
}
/**
* Implementation of hook_taxonomy(). Acts on taxonomy changes.
*/
function boost_taxonomy($op, $type, $term = NULL) {
if (!BOOST_ENABLED) return;
switch ($op) {
case 'insert':
case 'update':
case 'delete':
// TODO: Expire all relevant taxonomy pages from the static page cache to prevent serving stale content.
break;
}
}
/**
* Implementation of hook_user(). Acts on user account actions.
*/
function boost_user($op, &$edit, &$account, $category = NULL) {
if (!BOOST_ENABLED) return;
global $user;
switch ($op) {
case 'login':
// Set a special cookie to prevent authenticated users getting served
// pages from the static page cache.
boost_set_cookie($user);
break;
case 'logout':
boost_set_cookie($user, BOOST_TIME - 86400);
break;
case 'insert':
// TODO: create user-specific cache directory.
break;
case 'delete':
// Expire the relevant user page from the static page cache to prevent serving stale content:
if (!empty($account->uid)) {
boost_cache_expire_derivative('user/' . $account->uid);
}
// TODO: recursively delete user-specific cache directory.
break;
}
}
/**
* Implementation of hook_block().
*/
function boost_block($op = 'list', $delta = 0, $edit = array()) {
global $user;
switch ($op) {
case 'list':
return array(
'status' => array(
'info' => t('Boost: Pages cache status'),
'region' => 'right',
'weight' => 10,
'cache' => BLOCK_NO_CACHE,
),
'config' => array(
'info' => t('Boost: Pages cache configuration'),
'region' => 'right',
'weight' => 10,
'cache' => BLOCK_NO_CACHE,
),
'stats' => array(
'info' => t('Boost: AJAX core statistics'),
'region' => 'right',
'weight' => 10,
'cache' => BLOCK_NO_CACHE,
),
);
case 'configure':
if ($delta == 'stats') {
$form['boost_block_show_stats'] = array(
'#type' => 'checkbox',
'#title' => t('Display Statistics.'),
'#default_value' => variable_get('boost_block_show_stats', FALSE),
'#description' => t('If false, uses Javascript to hide the block via "parent().parent().hide()".'),
);
$form['boost_block_cache_stats_block'] = array(
'#type' => 'checkbox',
'#title' => t('Cache Statistics Block'),
'#default_value' => variable_get('boost_block_cache_stats_block', FALSE),
);
return $form;
}
case 'save':
if ($delta == 'stats') {
variable_set('boost_block_show_stats', $edit['boost_block_show_stats']);
variable_set('boost_block_cache_stats_block', $edit['boost_block_cache_stats_block']);
}
case 'view':
$block = array();
switch ($delta) {
case 'status':
// Don't show the block to anonymous users, nor on any pages that
// aren't even cacheable to begin with (e.g. admin/*).
if (!empty($user->uid) && boost_is_cacheable($GLOBALS['_boost_path'])) {
$output = t('This page is being served live to anonymous visitors, as it is not currently in the static page cache.');
if (boost_is_cached($GLOBALS['_boost_path'])) {
$filename = boost_file_path($GLOBALS['_boost_path']);
$ttl = boost_db_get_ttl($filename);
$generate = boost_get_generation_time($filename);
$output = '';
if (boost_has_site_changed()) {
$output .= t('Globally the site has changed.') . ' ';
}
$output .= t('This page is being served to anonymous visitors from the static page cache. Took %time seconds to generate this cached page.', array('%time' => round($generate, 3))) . ' ';
if ($ttl < 0) {
$output .= t('The cached copy expired %interval ago. ', array('%interval' => format_interval(abs($ttl))));
}
else {
$output .= t('The cached copy will expire in %interval.', array('%interval' => format_interval(abs($ttl))));
}
$output .= drupal_get_form('boost_block_flush_form');
}
$error = FALSE;
if (function_exists('error_get_last')) {
$error = error_get_last();
}
$drupal_msg = max(count(drupal_get_messages(NULL, FALSE)), $GLOBALS['_boost_message_count']);
if ((BOOST_HALT_ON_ERRORS && $error) || (BOOST_HALT_ON_MESSAGES && $drupal_msg != 0)) {
$output = t('There are php errors or drupal messages on this page, preventing boost from caching.') . ' ';
if (BOOST_HALT_ON_ERRORS && $error) {
$output .= t('ERROR: %error !link !performance', array('%error' => boost_print_r($error, TRUE), '!link' => l(t('Lookup Error Type'), 'http://php.net/errorfunc.constants'), '!performance' => l(t('Turn Off Error Checking'), 'admin/settings/performance')));
}
if (BOOST_HALT_ON_MESSAGES && $drupal_msg != 0) {
$output .= t('MESSAGES: %msg !performance', array('%msg' => $drupal_msg, '!performance' => l(t('Turn Off Error Checking'), 'admin/settings/performance')));
}
}
$block['subject'] = '';
$block['content'] = theme('boost_cache_status', isset($ttl) ? $ttl : -1, $output);
}
break;
case 'config':
// Don't show the block to anonymous users, nor on any pages that
// aren't even cacheable to begin with (e.g. admin/*).
if (!empty($user->uid) && boost_is_cacheable($GLOBALS['_boost_path'])) {
$block['subject'] = '';
$block['content'] = theme('boost_cache_status', -1, drupal_get_form('boost_block_db_settings_form'));
}
break;
case 'stats':
$filename = 'boost_stats.php';
$block = module_invoke('statistics', 'block', 'view', 0);
variable_set('boost_statistics_html', $block['content']);
if (!( strpos($_SERVER['SCRIPT_FILENAME'], 'index.php') === FALSE
|| variable_get('site_offline', 0)
|| $_SERVER['REQUEST_METHOD'] != 'GET'
|| $_SERVER['SERVER_SOFTWARE'] === 'PHP CLI'
|| !BOOST_ENABLED
|| isset($_GET['nocache'])
|| !boost_is_cacheable($GLOBALS['_boost_path'])
|| !empty($user->uid)
|| !module_exists('statistics')
)) {
$block = array();
$block['subject'] = 'Popular content';
$block['content'] = '
' . boost_stats_generate($filename);
}
elseif (!variable_get('boost_block_show_stats', FALSE)) {
$block['content'] .= '
';
drupal_add_js('$("#boost-stats").parent().parent().hide();', 'inline', 'footer');
}
break;
}
return $block;
}
}
function boost_block_flush_form() {
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$form['boost_clear']['page_callback'] = array(
'#type' => 'hidden',
'#value' => $router_item['page_callback'],
);
$form['boost_clear']['page_type'] = array(
'#type' => 'hidden',
'#value' => $router_item['page_type'],
);
$form['boost_clear']['page_id'] = array(
'#type' => 'hidden',
'#value' => $router_item['page_id'],
);
$form['boost_cache']['clear'] = array(
'#type' => 'submit',
'#value' => t('Flush Page'),
'#submit' => array('boost_block_form_flush_submit'),
);
return ($form);
}
function boost_block_form_flush_submit(&$form_state, $form) {
$data = array();
// Special front page handling
if ($form['values']['page_callback'] == 'node_page_default' && BOOST_CACHE_XML) {
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => 'node_feed');
}
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $form['values']['page_callback'], 'page_type' => $form['values']['page_type'], 'page_id' => $form['values']['page_id']);
boost_cache_expire_router($data, TRUE);
}
function boost_block_db_settings_form() {
// set info
$period = drupal_map_assoc(array(-1, 0, 60, 180, 300, 600, 900, 1800, 2700, 3600, 10800, 21600, 32400, 43200, 64800, 86400, 2*86400, 3*86400, 4*86400, 5*86400, 6*86400, 604800, 2*604800, 3*604800, 4*604800, 8*604800, 16*604800, 52*604800), 'format_interval');
$period[0] = '<' . t('none') . '>';
$period[-1] = t('default');
//$info = boost_get_db(boost_file_path($GLOBALS['_boost_path']));
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$settings = boost_get_settings_db($router_item);
$default = 0;
foreach ($settings as $key => $value) {
if ($value != NULL) {
$info = $value;
$default = $key;
break;
}
}
if (!isset($info)) {
$info['lifetime'] = -1;
$info['push'] = -1;
}
// create form
$form['boost_db_settings']['lifetime'] = array(
'#type' => 'select',
'#title' => t('Minimum cache lifetime'),
'#default_value' => $info['lifetime'],
'#options' => $period,
'#description' => t('Default: %default', array('%default' => format_interval(BOOST_CACHE_LIFETIME))),
);
$form['boost_db_settings']['push'] = array(
'#type' => 'select',
'#title' => t('Preemptive Cache'),
'#default_value' => $info['push'],
'#options' => array(
-1 => 'default',
0 => 'No',
1 => 'Yes',
),
);
$form['boost_db_settings']['selection'] = array(
'#type' => 'select',
'#title' => t('Scope'),
'#default_value' => $default,
'#options' => array(
0 => 'Page ID: ' . $router_item['page_id'],
1 => 'Content Type: ' . $router_item['page_type'],
2 => 'Content Container: ' . $router_item['page_callback'],
),
);
$form['boost_db_settings']['send'] = array(
'#type' => 'submit',
'#value' => t('Set Configuration'),
'#submit' => array('boost_block_db_settings_form_submit'),
);
$form['boost_db_rm_settings']['id'] = array(
'#type' => 'checkbox',
'#title' => t('Page ID'),
'#default_value' => $settings[0] != NULL ? FALSE : TRUE,
'#disabled' => $settings[0] != NULL ? FALSE : TRUE,
'#description' => $period[$settings[0]['lifetime']] . ' - ' . $router_item['page_id'],
);
$form['boost_db_rm_settings']['id_value'] = array(
'#type' => 'hidden',
'#title' => t('id_value'),
'#default_value' => $settings[0] != NULL ? $settings[0]['csid'] : FALSE,
'#disabled' => $settings[0] != NULL ? FALSE : TRUE,
);
$form['boost_db_rm_settings']['type'] = array(
'#type' => 'checkbox',
'#title' => t('Content Type'),
'#default_value' => $settings[1] != NULL ? FALSE : TRUE,
'#disabled' => $settings[1] != NULL ? FALSE : TRUE,
'#description' => $period[$settings[1]['lifetime']] . ' - ' . $router_item['page_type'],
);
$form['boost_db_rm_settings']['type_value'] = array(
'#type' => 'hidden',
'#title' => t('type_value'),
'#default_value' => $settings[1] != NULL ? $settings[1]['csid'] : FALSE,
'#disabled' => $settings[1] != NULL ? FALSE : TRUE,
);
$form['boost_db_rm_settings']['container'] = array(
'#type' => 'checkbox',
'#title' => t('Content Container'),
'#default_value' => $settings[2] != NULL ? FALSE : TRUE,
'#disabled' => $settings[2] != NULL ? FALSE : TRUE,
'#description' => $period[$settings[2]['lifetime']] . ' - ' . $router_item['page_callback'],
);
$form['boost_db_rm_settings']['container_value'] = array(
'#type' => 'hidden',
'#title' => t('container_value'),
'#default_value' => $settings[2] != NULL ? $settings[2]['csid'] : FALSE,
'#disabled' => $settings[2] != NULL ? FALSE : TRUE,
);
$form['boost_db_rm_settings']['send'] = array(
'#type' => 'submit',
'#value' => t('Delete Configuration'),
'#submit' => array('boost_block_db_rm_settings_form_submit'),
'#description' => t('Check the box to delete it'),
);
return $form;
}
/**
* Sets page specific settings in the boost cache database.
*/
function boost_block_db_settings_form_submit(&$form_state, $form) {
boost_set_db_page_settings($form['values']['lifetime'], $form['values']['push'], $form['values']['selection']);
}
/**
* Sets page specific settings in the boost cache database.
*/
function boost_block_db_rm_settings_form_submit(&$form_state, $form) {
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$data = array();
if (is_int($form['values']['id'])) {
boost_remove_settings_db($form['values']['id_value']);
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback'], 'page_type' => $router_item['page_type'], 'page_id' => $router_item['page_id']);
}
if (is_int($form['values']['type'])) {
boost_remove_settings_db($form['values']['type_value']);
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback'], 'page_type' => $router_item['page_type']);
}
if (is_int($form['values']['container'])) {
boost_remove_settings_db($form['values']['container_value']);
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback']);
}
boost_cache_expire_router($data);
}
/**
* Generate js/html for boost stat counter.
*
* NOTE HTML code could be added to the $buffer directly. Would prevent 2x
* counts on first view. Would be hard to do though.
*
* @param $filename
* Name of boost's statistics php file.
*/
function boost_stats_generate($filename) {
Global $base_path;
// is node & node count enabled.
if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == '' && variable_get('statistics_count_content_views', 0)) {
$nid = arg(1);;
}
else {
$nid = 'NULL';
}
// access log enabled.
if ((variable_get('statistics_enable_access_log', 0)) && (module_invoke('throttle', 'status') == 0)) {
$title = drupal_urlencode(strip_tags(drupal_get_title()));
$q = $_GET['q'];
}
else {
$title = 'NULL';
$q = 'NULL';
}
$page_js = array(
'boost' => array(
'nid' => $nid,
'q' => $q,
'title' => $title,
),
);
$site_js = <<';
return $page_ns;
}
/**
* Implementation of hook_theme().
*/
function boost_theme() {
return array(
'boost_cache_status' => array(
'arguments' => array('ttl' => NULL, 'text' => NULL),
),
);
}
function theme_boost_cache_status($ttl, $text) {
return '' . $text . ' ';
}
//////////////////////////////////////////////////////////////////////////////
// Output buffering callback
/**
* PHP output buffering callback for static page caching.
*/
function _boost_ob_handler() {
$buffer = ob_get_contents();
// Ensure we're in the correct working directory, since some web servers (e.g. Apache) mess this up here.
chdir(dirname($_SERVER['SCRIPT_FILENAME']));
// Very late cache canceling
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
if ( $GLOBALS['_boost_router_item']['page_callback'] == 'search404_page'
|| $GLOBALS['_boost_router_item']['page_callback'] == 'fivestar_vote'
) {
$GLOBALS['_boost_cache_this'] = FALSE;
}
// Check for PHP errors
if (function_exists('error_get_last')) {
if (BOOST_HALT_ON_ERRORS && $error = error_get_last()) {
switch ($error['type']) {
case E_NOTICE: //Ignore run-time notices
case E_USER_NOTICE: //Ignore user-generated notice message
//case E_DEPRECATED: //Ignore run-time notices
//case E_USER_DEPRECATED: //Ignore user-generated notice message
break;
default: //Do not cache page on all other errors
$GLOBALS['_boost_cache_this'] = FALSE;
if (BOOST_VERBOSE >= 3) {
watchdog('boost', 'There are php errors on this page, preventing boost from caching. ERROR: %error !link !performance', array('%error' => boost_print_r($error, TRUE), '!link' => l(t('Lookup Error Type'), 'http://php.net/errorfunc.constants'), '!performance' => l(t('Turn Off Error Checking'), 'admin/settings/performance/boost')), WATCHDOG_WARNING);
}
break;
}
}
}
// Check for drupal messages
if (BOOST_HALT_ON_MESSAGES && $GLOBALS['_boost_message_count'] != 0) {
$GLOBALS['_boost_cache_this'] = FALSE;
if (BOOST_VERBOSE >= 3) {
watchdog('boost', 'There are drupal messages on this page, preventing boost from caching. MESSAGES: %msg !performance', array('%msg' => $GLOBALS['_boost_message_count'], '!performance' => l(t('Turn Off Error Checking'), 'admin/settings/performance/boost')), WATCHDOG_WARNING);
}
}
// Check the currently set content type and the HTTP response code. only cache
// 'text/*' pages that were output with a 200 OK status. If it didn't get a
// 200 then remove that entry from the cache.
if (!empty($buffer)) {
$status = boost_get_http_status();
$types = boost_get_content_type();
if (stristr($types, 'text/javascript')) {
if ($status == 200 & $GLOBALS['_boost_cache_this']) {
if (BOOST_ASYNCHRONOUS_OUTPUT) {
boost_async_opp($buffer, FALSE, 'text/javascript');
}
boost_cache_set($GLOBALS['_boost_path'], $buffer, BOOST_JSON_EXTENSION);
}
elseif ($status == 404 || $status == 403) {
$filename = boost_file_path($GLOBALS['_boost_path'], TRUE, BOOST_JSON_EXTENSION);
if ($filename) {
$hash = md5($filename);
boost_cache_kill($filename, $hash, TRUE);
boost_remove_db($filename, $hash);
}
}
}
elseif (stristr($types, 'application/rss') || stristr($types, 'text/xml') || stristr($types, 'application/rss+xml')) {
if ($status == 200 && $GLOBALS['_boost_cache_this']) {
if (BOOST_ASYNCHRONOUS_OUTPUT) {
boost_async_opp($buffer, FALSE, 'text/xml');
}
boost_cache_set($GLOBALS['_boost_path'], $buffer, BOOST_XML_EXTENSION);
}
elseif ($status == 404 || $status == 403) {
$filename = boost_file_path($GLOBALS['_boost_path'], TRUE, BOOST_XML_EXTENSION);
if ($filename) {
$hash = md5($filename);
boost_cache_kill($filename, $hash, TRUE);
boost_remove_db($filename, $hash);
}
}
}
elseif (stristr($types, 'text/html')) {
if ($status == 200 && $GLOBALS['_boost_cache_this']) {
if (BOOST_ASYNCHRONOUS_OUTPUT) {
boost_async_opp($buffer, FALSE, 'text/html');
}
boost_cache_set($GLOBALS['_boost_path'], $buffer, BOOST_FILE_EXTENSION);
boost_cache_css_js_files($buffer);
}
elseif ($status == 404 || $status == 403) {
// Kill cache entry if it exists
$filename = boost_file_path($GLOBALS['_boost_path'], TRUE, BOOST_FILE_EXTENSION);
if ($filename) {
$hash = md5($filename);
boost_cache_kill($filename, $hash, TRUE);
boost_remove_db($filename, $hash);
}
}
}
}
}
/**
* Determines the MIME content type of the current page response based on
* the currently set Content-Type HTTP header.
*
* This should normally return the string 'text/html' unless another module
* has overridden the content type.
*/
function boost_get_content_type() {
$headers = explode("content-type: ", strtolower(drupal_get_headers()));
$types = array();
foreach ($headers as $header) {
$types[] = array_shift(explode('; charset=', array_shift(explode('\n', $header))));
}
return array_pop(array_filter($types));
}
/**
* Determines the HTTP response code that the current page request will be
* returning by examining the HTTP headers that have been output so far.
*/
function boost_get_http_status() {
$headers = explode("\n", drupal_get_headers());
preg_match('!^.*\s+(\d+)!', array_pop($headers), $matches);
if (isset($matches[1])) {
return $matches[1];
}
else {
return 200;
}
}
//////////////////////////////////////////////////////////////////////////////
// Boost API implementation
/**
* Determines whether a given url can be cached or not by boost.
*
* To avoid potentially troublesome situations, the user login page is never
* cached, nor are any admin pages.
*
* @param $path
* Current URL
*
* $path = $GLOBALS['_boost_path'] most of the time
* uses $GLOBALS['_boost_query'] as well
*/
function boost_is_cacheable($path) {
$path = (empty($path)) ? variable_get('site_frontpage', 'node') : $path;
$normal_path = drupal_get_normal_path($path); // normalize path
$full = $normal_path . '-' . $GLOBALS['_boost_query'];
// Never cache
// the user login/registration/password pages
// any admin pages
// comment reply pages
// node add page
// URL variables that contain / or \
// if incoming URL contains '..' or null bytes
// Limit the maximum directory nesting depth of the path
if ( $normal_path == 'user'
|| preg_match('!^user/(login|register|password)!', $normal_path)
|| preg_match('!^admin!', $normal_path)
|| preg_match('!comment/reply$!', $normal_path)
|| preg_match('!^node/add!', $normal_path)
|| strpos($GLOBALS['_boost_query'], '/')
|| strpos($GLOBALS['_boost_query'], '\\')
|| strpos($full, '..') !== FALSE
|| strpos($full, "\0") !== FALSE
|| count(explode('/', $path)) > BOOST_MAX_PATH_DEPTH
) {
return FALSE;
}
if (!BOOST_CACHE_XML && (preg_match('!/feed$!', $normal_path) || preg_match('!\.xml$!', $normal_path))) {
return FALSE;
}
if (!BOOST_CACHE_QUERY && $GLOBALS['_boost_query'] != BOOST_CHAR) {
return FALSE;
}
// Don't cache path if it can't be served by apache.
if (BOOST_ONLY_ASCII_PATH) {
if (preg_match('@[^/a-z0-9_\-&=,\.:]@i', $path)) {
return FALSE;
}
}
// Check for reserved characters if on windows
// http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words
// " * : < > |
$chars = '"*:<>|';
if (stristr(PHP_OS, 'WIN') && preg_match("/[" . $chars . "]/", $full)) {
return FALSE;
}
// Invoke hook_boost_is_cacheable($path)
foreach (module_implements('boost_preprocess') as $module) {
if (($result = module_invoke($module, 'boost_preprocess', $path)) != NULL) {
if (!$result) {
return FALSE;
}
}
}
// See http://api.drupal.org/api/function/block_list/6
// Match the user's cacheability settings against the path
if (BOOST_CACHEABILITY_PAGES) {
if (BOOST_CACHEABILITY_OPTION < 2) {
$page_match = drupal_match_path($path, BOOST_CACHEABILITY_PAGES);
if ($path != $_GET['q']) {
$page_match = $page_match || drupal_match_path($_GET['q'], BOOST_CACHEABILITY_PAGES);
}
// When BOOST_CACHEABILITY_OPTION has a value of 0, boost will cache
// all pages except those listed in BOOST_CACHEABILITY_PAGES. When set
// to 1, boost will cache only on those pages listed in BOOST_CACHEABILITY_PAGES.
$page_match = !(BOOST_CACHEABILITY_OPTION xor $page_match);
}
else {
$page_match = drupal_eval(BOOST_CACHEABILITY_PAGES);
}
}
else {
$page_match = TRUE;
}
return $page_match;
}
/**
* This hook is run inorder to determine if a page should be cached.
* Runs in boost_init().
*
* @return FALSE to not cache the page, TRUE to cache the page.
* Returning a FALSE is absolute, Returning TRUE is more like an ignore,
* doesn't guarntee it will be cached; some other setting could make the
* is_boost_cacheable() call return FALSE to boost_init()
*
*/
function hook_boost_is_cacheable($path) {
return TRUE;
}
/**
* Determines whether a given Drupal page is currently cached or not.
*
* @param $path
* Current URL
*/
function boost_is_cached($path) {
// no more need to check if path is empty cause it is done on the input of this function before calling it
// no more need to use drupal_get_normal_path - we do not need the internal path (node/56) - we are fine with aliases
return file_exists(boost_file_path($path));
}
/**
* Deletes all files currently in the cache.
*/
function boost_cache_clear_all() {
if (variable_get('boost_ignore_flush', 0) == 0) {
boost_cache_clear_all_db();
boost_cache_delete(TRUE);
if (BOOST_VERBOSE >= 5) {
watchdog('boost', 'Flushed ALL files from static page cache.', array(), WATCHDOG_NOTICE);
}
return TRUE;
}
return FALSE;
}
/**
* Deletes all expired static files currently in the cache.
* OLD FUNCTION
*/
function boost_cache_expire_all() {
boost_cache_delete(FALSE);
return TRUE;
}
/**
* Resets all entries in database.
*/
function boost_cache_clear_all_db() {
db_query("UPDATE {boost_cache} SET expire = %d WHERE base_dir = '%s'", 0, BOOST_FILE_PATH);
}
/**
* Deletes files in the cache.
*
* @param $flush
* If true clear the entire cache directory.
*/
function boost_cache_delete($flush = FALSE) {
clearstatcache();
//recreate dirs
_boost_mkdir_p(BOOST_FILE_PATH);
_boost_mkdir_p(BOOST_GZIP_FILE_PATH);
//add in .boost root id file
file_put_contents(BOOST_FILE_PATH . '/' . BOOST_ROOT_FILE, BOOST_FILE_PATH);
file_put_contents(BOOST_GZIP_FILE_PATH . '/' . BOOST_ROOT_FILE, BOOST_GZIP_FILE_PATH);
//Flush Cache
if (file_exists(BOOST_FILE_PATH)) {
_boost_rmdir_rf(BOOST_FILE_PATH, $flush, TRUE);
}
if (file_exists(BOOST_GZIP_FILE_PATH)) {
_boost_rmdir_rf(BOOST_GZIP_FILE_PATH, $flush, TRUE);
}
//recreate dirs
_boost_mkdir_p(BOOST_FILE_PATH);
_boost_mkdir_p(BOOST_GZIP_FILE_PATH);
//add in .boost root id file
file_put_contents(BOOST_FILE_PATH . '/' . BOOST_ROOT_FILE, BOOST_FILE_PATH);
file_put_contents(BOOST_GZIP_FILE_PATH . '/' . BOOST_ROOT_FILE, BOOST_GZIP_FILE_PATH);
}
/**
* Finds all possible paths/redirects/aliases given the root path.
*
* @param $path
* Current URL
*/
function boost_cache_expire_derivative($path) {
global $base_path;
$paths = array();
// Given path
$paths[] = $path;
// Special front page feed handling
if (BOOST_CACHE_XML && ($path = '' || $path = '')) {
$paths[] = 'rss.xml';
}
// Path alias
$path_alias = url($path, array('absolute' => FALSE));
if ($base_path != '/') {
$path_alias = implode('/', array_diff_assoc(array_filter(explode('/', $path_alias)), array_filter(explode('/', $base_path))));
}
$paths[] = $path_alias;
// Path redirects
if (module_exists('path_redirect')) {
$path_redirects = boost_path_redirect_load(array('redirect' => $path));
if (isset($path_redirects)) {
foreach ($path_redirects as $path_redirect) {
$paths[] = $path_redirect['path'];
}
}
}
boost_cache_expire($paths);
}
/**
* Expires the static file cache for the given paths
*
* @param $paths
* Array of URL's
*/
function boost_cache_expire($paths) {
$hashes = array();
// Get all cache files directly associated with this path
foreach (array_unique($paths) as $path) {
// With URL Variables
$html = boost_file_path($path, TRUE, BOOST_FILE_EXTENSION);
if ($html === FALSE) {
continue;
}
$xml = boost_file_path($path, TRUE, BOOST_XML_EXTENSION);
$json = boost_file_path($path, TRUE, BOOST_JSON_EXTENSION);
// Hash the paths
$hashes[] = md5($html);
$hashes[] = md5($xml);
$hashes[] = md5($json);
// Without URL Variables
$html = boost_file_path($path, FALSE, BOOST_FILE_EXTENSION);
$xml = boost_file_path($path, FALSE, BOOST_XML_EXTENSION);
$json = boost_file_path($path, FALSE, BOOST_JSON_EXTENSION);
// Hash the paths
$hashes[] = md5($html);
$hashes[] = md5($xml);
$hashes[] = md5($json);
}
// Input has been MD5-ed should be ok to do this; do not do if not MD5-ed
$sql = implode("' OR hash = '", array_unique($hashes));
$result = db_query("SELECT * FROM {boost_cache} WHERE hash = '" . $sql . "'");
// Eliminate duplicates
$data = array();
while ($info = db_fetch_array($result)) {
$hash = BOOST_FILE_PATH . $info['page_callback'] . $info['page_type'] . $info['page_id'];
$data[$hash] = $info;
}
// Expire all files that match up
boost_cache_expire_router($data);
}
/**
* Expires the static file cache for the given paths
*
* @param $router_items
* Array of $router_item array "objects"
* ['page_callback']
* ['page_type']
* ['page_id']
* ['base_dir']
* @param $force_flush
* Override BOOST_EXPIRE_NO_FLUSH setting
*/
function boost_cache_expire_router($router_items, $force_flush = FALSE) {
// Get filenames & hash from db
if (!is_array($router_items)) {
return FALSE;
}
$count = 0;
foreach ($router_items as $dblookup) {
if (isset($dblookup['base_dir'])) {
if (isset($dblookup['page_id'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE base_dir = '%s' AND page_callback = '%s' AND page_type = '%s' AND page_id = '%s'", $dblookup['base_dir'], $dblookup['page_callback'], $dblookup['page_type'], $dblookup['page_id']);
db_query("DELETE FROM {boost_cache_relationships} WHERE base_dir = '%s' AND page_callback = '%s' AND page_type = '%s' AND page_id = '%s'", $dblookup['base_dir'], $dblookup['page_callback'], $dblookup['page_type'], $dblookup['page_id']);
}
elseif (isset($dblookup['page_type'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE base_dir = '%s' AND page_callback = '%s' AND page_type = '%s'", $dblookup['base_dir'], $dblookup['page_callback'], $dblookup['page_type']);
db_query("DELETE FROM {boost_cache_relationships} WHERE base_dir = '%s' AND page_callback = '%s' AND page_type = '%s'", $dblookup['base_dir'], $dblookup['page_callback'], $dblookup['page_type']);
}
elseif (isset($dblookup['page_callback'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE base_dir = '%s' AND page_callback = '%s'", $dblookup['base_dir'], $dblookup['page_callback']);
db_query("DELETE FROM {boost_cache_relationships} WHERE base_dir = '%s' AND page_callback = '%s'", $dblookup['base_dir'], $dblookup['page_callback']);
}
else {
continue;
}
}
else {
if (isset($dblookup['page_id'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE page_callback = '%s' AND page_type = '%s' AND page_id = '%s'", $dblookup['page_callback'], $dblookup['page_type'], $dblookup['page_id']);
db_query("DELETE FROM {boost_cache_relationships} WHERE page_callback = '%s' AND page_type = '%s' AND page_id = '%s'", $dblookup['page_callback'], $dblookup['page_type'], $dblookup['page_id']);
}
elseif (isset($dblookup['page_type'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE page_callback = '%s' AND page_type = '%s'", $dblookup['page_callback'], $dblookup['page_type']);
db_query("DELETE FROM {boost_cache_relationships} WHERE page_callback = '%s' AND page_type = '%s'", $dblookup['page_callback'], $dblookup['page_type']);
}
elseif (isset($dblookup['page_callback'])) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE page_callback = '%s'", $dblookup['page_callback']);
db_query("DELETE FROM {boost_cache_relationships} WHERE page_callback = '%s'", $dblookup['page_callback']);
}
else {
continue;
}
}
while ($info = db_fetch_array($result)) {
// Flush matching files
boost_cache_kill($info['filename'], $info['hash'], $force_flush, $info['base_dir']);
$count++;
}
}
return $count;
}
/**
* Deletes cached page from file system
*
* @param $filename
* Name of cached file.
* @param $hash
* Primary key in database; filename hash
* @param $force_flush
* Override BOOST_EXPIRE_NO_FLUSH setting
* @param $base_dir
* Base directory of site
*/
function boost_cache_kill($filename, $hash = '', $force_flush = FALSE, $base_dir = '') {
// If not ignoring file removal
// AND site is multisite and cache path matches filename
// OR full base url matches filename
if (variable_get('boost_ignore_flush', 0) < 3 && ((BOOST_FLUSH_ALL_MULTISITE && strstr($filename, BOOST_ROOT_CACHE_DIR)) || strstr($filename, BOOST_FILE_PATH))) {
if ($hash == '') {
$hash = md5($filename);
}
if ($hash != '') {
if (!$force_flush && BOOST_EXPIRE_NO_FLUSH) {
db_query("UPDATE {boost_cache} SET expire = 434966400 WHERE hash = '%s'", $hash);
}
else {
db_query("UPDATE {boost_cache} SET expire = 0 WHERE hash = '%s'", $hash);
if (file_exists($filename)) {
@unlink($filename);
}
$base_dir = $base_dir == '' ? BOOST_FILE_PATH : $base_dir;
$gz_filename = str_replace($base_dir, BOOST_GZIP_FILE_PATH, $filename) . BOOST_GZIP_EXTENSION;
if (file_exists($gz_filename)) {
@unlink($gz_filename);
}
}
}
}
}
/**
* Flushes all expired pages from database
*
* TODO del empty dirs if enabled
*/
function boost_cache_db_expire() {
if (variable_get('boost_ignore_flush', 0) < 2) {
if (BOOST_FLUSH_ALL_MULTISITE) {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE expire BETWEEN 1 AND %d", BOOST_TIME);
}
else {
$result = db_query("SELECT filename, hash, base_dir FROM {boost_cache} WHERE base_dir = '%s' AND expire BETWEEN 1 AND %d", BOOST_FILE_PATH, BOOST_TIME);
}
while ($boost = db_fetch_array($result)) {
boost_cache_kill($boost['filename'], $boost['hash'], TRUE, $boost['base_dir']);
}
if (BOOST_FLUSH_DIR) {
// TO-DO: del empty dirs.
}
return TRUE;
}
return FALSE;
}
/**
* Returns the cached contents of the specified page, if available.
*
* @param $path
* Current URL
*/
function boost_cache_get($path) {
if (($filename = boost_file_path($path))) {
if (file_exists($filename) && is_readable($filename)) {
return file_get_contents($filename);
}
}
return NULL;
}
/**
* Edit document before it is put into the boost cache.
*
* This hook is run at right before the page is cached by boost.
*
* $GLOBALS['_boost_cache_this'] and $GLOBALS['_boost_router_item'] are useful.
* set $GLOBALS['_boost_cache_this'] = FALSE if you wish to not cache this page.
*
* @param $path
* URL path of the document
* @param $data
* String containing the data
* @param $extension
* file extension type. Use to detect what type of document your operating on.
* @return
* $data string containing the document
*/
function hook_boost_preprocess($path, $data, $extension) {
return $data;
}
/**
* Replaces/Sets the cached contents of the specified page, if stale.
*
* @param $path
* Current URL
* @param $data
* URL's contents
* @param $extension
* File extension for this mime type
*/
function boost_cache_set($path, $data, $extension = BOOST_FILE_EXTENSION) {
if (empty($data)) {
return FALSE;
}
$cached_at = date('Y-m-d H:i:s', BOOST_TIME);
// Code commenting style based on what is being cached.
// Append the Boost footer with the relevant timestamps
switch ($extension) {
case BOOST_FILE_EXTENSION:
$comment_start = '\n";
$expire = BOOST_CACHE_LIFETIME;
$expires_at = date('Y-m-d H:i:s', BOOST_TIME + $expire);
$comment = $comment_start . str_replace(array('%cached_at', '%expires_at'), array($cached_at, $expires_at), BOOST_BANNER) . $comment_end;
//$data = _boost_inject_code(rtrim($data), "\n" . $comment);
$data = rtrim($data) . "\n" . $comment;
break;
case BOOST_XML_EXTENSION:
$comment_start = '\n";
$expire = BOOST_CACHE_XML_LIFETIME;
$expires_at = date('Y-m-d H:i:s', BOOST_TIME + $expire);
$comment = $comment_start . str_replace(array('%cached_at', '%expires_at'), array($cached_at, $expires_at), BOOST_BANNER) . $comment_end;
$data = rtrim($data) . "\n" . $comment;
break;
case BOOST_JSON_EXTENSION:
$comment_start = '/* ';
$comment_end = " */\n";
$expire = BOOST_CACHE_JSON_LIFETIME;
$expires_at = date('Y-m-d H:i:s', BOOST_TIME + $expire);
$comment = $comment_start . str_replace(array('%cached_at', '%expires_at'), array($cached_at, $expires_at), BOOST_BANNER) . $comment_end;
$data = rtrim($data) . "\n" . $comment;
break;
}
// Invoke hook_boost_preprocess($path, $data, $extension)
foreach (module_implements('boost_preprocess') as $module) {
if (($result = module_invoke($module, 'boost_preprocess', $path, $data, $extension)) != NULL) {
$data = $result;
}
}
// Execute the pre-process function if one has been defined
if (function_exists(BOOST_PRE_PROCESS_FUNCTION)) {
$data = call_user_func(BOOST_PRE_PROCESS_FUNCTION, $path, $data, $extension);
}
db_set_active();
// Final check, make sure this page should be cached. Allow for the preprocess
// function to have a final say in if this page should be cached.
if (!$GLOBALS['_boost_cache_this'] || empty($data)) {
return FALSE;
}
// Create or update the static files as needed
if (($filename = boost_file_path($path, TRUE, $extension)) && (BOOST_OVERWRITE_FILE || !file_exists($filename) || boost_db_is_expired($filename))) {
// Special handling of the front page for aggressive gzip test
if ($path == '' && BOOST_AGGRESSIVE_GZIP && $extension == BOOST_FILE_EXTENSION) {
_boost_generate_gzip_test_file();
boost_cache_write($filename, _boost_inject_code($data, '' . "\n"));
}
else {
boost_cache_write($filename, $data);
}
if (BOOST_GZIP) {
boost_cache_write(str_replace(BOOST_FILE_PATH, BOOST_GZIP_FILE_PATH, $filename) . BOOST_GZIP_EXTENSION, gzencode($data, 9));
}
boost_db_prep($filename, $extension, BOOST_TIME + $expire);
boost_cache_set_node_relationships($GLOBALS['_boost_relationships']);
return TRUE;
}
else {
return FALSE;
}
}
/**
* Creates a parent child relationship for pages like views.
*
* @param $relationships
* Array of $router_item array "objects"
* Required
* ['child_page_callback']
* ['child_page_type']
* ['child_page_id']
* Optional
* ['base_dir']
* ['page_callback']
* ['page_type']
* ['page_id']
*
* If Optional is not set it will use values in $GLOBALS['_boost_router_item']
*/
function boost_cache_set_node_relationships($relationships) {
global $base_root;
$url = $base_root . request_uri();
$hash_url = md5($url);
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
if (!is_array($relationships)) {
return FALSE;
}
foreach ($relationships as $data) {
// If one of the required items is not set, skip this entry
if (!isset($data['child_page_callback']) || !isset($data['child_page_type']) || !isset($data['child_page_id'])) {
continue;
}
// Set the optional parameters
$data['base_dir'] = isset($data['base_dir']) ? $data['base_dir'] : BOOST_FILE_PATH;
$data['page_callback'] = isset($data['page_callback']) ? $data['page_callback'] : $router_item['page_callback'];
$data['page_type'] = isset($data['page_type']) ? $data['page_type'] : $router_item['page_type'];
$data['page_id'] = isset($data['page_id']) ? $data['page_id'] : $router_item['page_id'];
// Skip if this is referencing its self.
if ($data['page_callback'] == $data['child_page_callback'] && $data['page_type'] == $data['child_page_type'] && $data['page_id'] == $data['child_page_id']) {
continue;
}
// Create the primary key
$hash = md5($data['base_dir'] . $data['page_callback'] . $data['page_type'] . $data['page_id'] . $data['child_page_callback'] . $data['child_page_type'] . $data['child_page_id']);
// Insert data into database
db_query("UPDATE {boost_cache_relationships} SET base_dir = '%s', page_callback = '%s', page_type = '%s', page_id = '%s', child_page_callback = '%s', child_page_type = '%s', child_page_id = '%s', hash_url = '%s', timestamp = '%d' WHERE hash = '%s'", $data['base_dir'], $data['page_callback'], $data['page_type'], $data['page_id'], $data['child_page_callback'], $data['child_page_type'], $data['child_page_id'], $hash_url, BOOST_TIME, $hash);
if (!db_affected_rows()) {
@db_query("INSERT INTO {boost_cache_relationships} (hash, base_dir, page_callback, page_type, page_id, child_page_callback, child_page_type, child_page_id, hash_url, timestamp) VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d)", $hash, $data['base_dir'], $data['page_callback'], $data['page_type'], $data['page_id'], $data['child_page_callback'], $data['child_page_type'], $data['child_page_id'], $hash_url, BOOST_TIME);
}
}
boost_cache_prune_node_relationship($hash_url);
unset($GLOBALS['_boost_relationships']);
return TRUE;
}
/**
* Creates a parent child relationship for pages like views.
*
* @param $relationships
* Array of $router_item array "objects"
* Required
* ['page_callback']
* ['page_type']
* ['page_id']
* Optional
* ['base_dir']
*/
function boost_cache_get_node_relationships($relationships) {
if (!is_array($relationships)) {
return FALSE;
}
$results = array();
foreach ($relationships as $data) {
// If one of the required items is not set, skip this entry
if (!isset($data['page_callback']) || !isset($data['page_type']) || !isset($data['page_id'])) {
continue;
}
$data['base_dir'] = isset($data['base_dir']) ? $data['base_dir'] : BOOST_FILE_PATH;
$result = db_query("SELECT page_callback, page_type, page_id FROM {boost_cache_relationships} WHERE child_page_id = '%s' AND child_page_type = '%s' AND child_page_callback = '%s' AND base_dir = '%s'", $data['page_id'], $data['page_type'], $data['page_callback'], $data['base_dir']);
while ($info = db_fetch_array($result)) {
$hash = $info['page_callback'] . '-' . $info['page_type'] . '-' . $info['page_id'];
$results[$hash] = $info;
}
}
return $results;
}
/**
* Given hash of url delete any old relationships.
*
* @param $hash_url
*/
function boost_cache_prune_node_relationship($hash_url) {
// Grab all entires related to this URL; find ones that don't match the latest
// timestamp and remove them.
$records = array();
$result = db_query("SELECT hash, timestamp FROM {boost_cache_relationships} WHERE hash_url = '%s' ORDER BY timestamp DESC", $hash_url);
while ($info = db_fetch_array($result)) {
if ($info['timestamp'] < BOOST_TIME) {
db_query("DELETE FROM {boost_cache_relationships} WHERE hash = '%s'", $info['hash']);
}
}
return $records;
}
/**
* Figure out what is going in the database & put it in
*
* @param $filename
* Name of cached file; primary key in database
* @param $extension
* Filename extension: Used for content types.
* @param $expire
* Cache expiration time in seconds (UNIX time).
*/
function boost_db_prep($filename, $extension, $expire) {
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$timer = timer_read('page');
$timer_average = $timer;
$lifetime = -1;
$push = -1;
$settings = boost_get_settings_db($router_item);
foreach ($settings as $value) {
if ($value != NULL) {
$boost_settings_db = $value;
break;
}
}
$boost_db = boost_get_db($filename);
//get time data from actual entry, if this page has been cached before.
if ($boost_db) {
// $expire = $boost_db['lifetime'] != -1 ? $boost_db['lifetime'] + BOOST_TIME : $expire;
// $lifetime = $boost_db['lifetime'];
// $push = $boost_db['push'];
$timer_average = ($boost_db['timer_average'] + $timer)/2;
}
//get data from settings table, if this page has not been put into the cache.
if (isset($boost_settings_db)) {
$expire = $boost_settings_db['lifetime'] != -1 ? $boost_settings_db['lifetime'] + BOOST_TIME : $expire;
$lifetime = $boost_settings_db['lifetime'];
$push = $boost_settings_db['push'];
}
boost_put_db($filename, $expire, $lifetime, $push, $router_item, $timer, $timer_average, $extension);
}
/**
* Puts boost info into database.
*
* @param $filename
* Name of cached file; hash of this is primary key in database
* @param $expire
* Expiration time
* @param $lifetime
* Default lifetime
* @param $push
* Pre-cache this file
* @param $router_item
* Array containing page_callback, page_type & page_id.
* @param $timer
* Time it took drupal to build this page.
* @param $timer_average
* Average time Drupal has spent building this page.
* @param $extension
* Filename extension: Used for content types.
*/
function boost_put_db($filename, $expire, $lifetime, $push, $router_item, $timer, $timer_average, $extension) {
global $base_root;
$url = $base_root . request_uri();
$hash = md5($filename);
$hash_url = md5($url);
db_query("UPDATE {boost_cache} SET expire = %d, lifetime = %d, push = %d, page_callback = '%s', page_type = '%s', timer = %d, timer_average = %d, base_dir = '%s', page_id = '%s', extension = '%s', url = '%s', filename = '%s', hash_url = '%s' WHERE hash = '%s'", $expire, $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], $timer, $timer_average, BOOST_FILE_PATH, $router_item['page_id'], $extension, $url, $filename, $hash_url, $hash);
if (!db_affected_rows()) {
db_query("INSERT INTO {boost_cache} (hash, hash_url, filename, expire, lifetime, push, page_callback, page_type, timer, timer_average, base_dir, page_id, extension, url) VALUES ('%s', '%s', '%s', %d, %d, %d, '%s', '%s', %d, %d, '%s', '%s', '%s', '%s')", $hash, $hash_url, $filename, $expire, $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], $timer, $timer_average, BOOST_FILE_PATH, $router_item['page_id'], $extension, $url);
}
}
/**
* Removes info from database. Use on 404 or 403.
*
* @param $hash
* md5 of filename
*/
function boost_remove_db($hash) {
db_query("DELETE FROM {boost_cache} WHERE hash = '%s'", $hash);
}
/**
* Puts boost info into database.
*
* @param $expire
* Expiration time
* @param $lifetime
* Default lifetime
* @param $push
* Pre-cache this file
* @param $router_item
* Array containing page_callback, page_type & page_id.
*/
function boost_put_settings_db($lifetime, $push, $router_item, $scope) {
switch ($scope) {
case 0:
db_query("UPDATE {boost_cache_settings} SET lifetime = %d, push = %d WHERE page_callback = '%s' AND page_type = '%s' AND base_dir = '%s' AND page_id = '%s'", $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH, $router_item['page_id']);
if (!db_affected_rows()) {
@db_query("INSERT INTO {boost_cache_settings} (csid, lifetime, push, page_callback, page_type, base_dir, page_id) VALUES (NULL, %d, %d, '%s', '%s', '%s', '%s')", $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH, $router_item['page_id']);
}
break;
case 1:
db_query("UPDATE {boost_cache_settings} SET lifetime = %d, push = %d WHERE page_callback = '%s' AND page_type = '%s' AND base_dir = '%s' AND page_id = '0'", $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH);
if (!db_affected_rows()) {
@db_query("INSERT INTO {boost_cache_settings} (csid, lifetime, push, page_callback, page_type, base_dir, page_id) VALUES (NULL, %d, %d, '%s', '%s', '%s', '%s')", $lifetime, $push, $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH, 0);
}
break;
case 2:
db_query("UPDATE {boost_cache_settings} SET lifetime = %d, push = %d WHERE page_callback = '%s' AND page_type = '0' AND base_dir = '%s' AND page_id = '0'", $lifetime, $push, $router_item['page_callback'], BOOST_FILE_PATH);
if (!db_affected_rows()) {
@db_query("INSERT INTO {boost_cache_settings} (csid, lifetime, push, page_callback, page_type, base_dir, page_id) VALUES (NULL, %d, %d, '%s', '%s', '%s', '%s')", $lifetime, $push, $router_item['page_callback'], '0', BOOST_FILE_PATH, 0);
}
break;
}
}
/**
* Removes info from boost database.
*
* @param $csid
* Cache Settings primary ID
*/
function boost_remove_settings_db($csid) {
db_query("DELETE FROM {boost_cache_settings} WHERE csid = %d", $csid);
}
/**
* Sets per page configuration.
*
* @param $lifetime
* Default lifetime
* @param $push
* Pre-cache this file
* @param $scope
* At what level does this effect cache expiration
*/
function boost_set_db_page_settings($lifetime, $push, $scope) {
$GLOBALS['_boost_router_item'] = isset($GLOBALS['_boost_router_item']) ? $GLOBALS['_boost_router_item'] : _boost_get_menu_router();
$router_item = $GLOBALS['_boost_router_item'];
$filename = boost_file_path($GLOBALS['_boost_path']);
$info = boost_get_db($filename);
if (!$info) {
$info['expire'] = 0;
}
elseif ($lifetime == -1) {
$info['expire'] = $info['expire'] - $info['lifetime'] + BOOST_CACHE_LIFETIME;
}
elseif ($info['lifetime'] == -1) {
$info['expire'] = $info['expire'] - BOOST_CACHE_LIFETIME + $lifetime;
}
elseif ($info['lifetime'] != $lifetime) {
$info['expire'] = $info['expire'] - $info['lifetime'] + $lifetime;
}
// Clear old files so they acquire the new settings.
$data = array();
switch ($scope) {
case 0:
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback'], 'page_type' => $router_item['page_type'], 'page_id' => $router_item['page_id']);
break;
case 1:
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback'], 'page_type' => $router_item['page_type']);
break;
case 2:
$data[] = array('base_dir' => BOOST_FILE_PATH, 'page_callback' => $router_item['page_callback']);
break;
}
boost_cache_expire_router($data);
//boost_put_db($filename, $info['expire'], $lifetime, $push, $router_item);
boost_put_settings_db($lifetime, $push, $router_item, $scope);
}
/**
* Gets boost info from cache database.
*
* @param $filename
* Filename to be looked up in the database
*/
function boost_get_db($filename) {
$hash = md5($filename);
return db_fetch_array(db_query("SELECT * FROM {boost_cache} WHERE hash = '%s'", $hash));
}
/**
* Gets boost settings from cache settings database.
*
* @param $router_item
* Array containing page_callback, page_type & page_id.
*/
function boost_get_settings_db($router_item) {
$settings = array();
// Get a more exact match first
$settings[] = db_fetch_array(db_query_range("SELECT * FROM {boost_cache_settings} WHERE page_callback = '%s' AND page_type = '%s' AND base_dir = '%s' AND page_id = '%s'", $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH, $router_item['page_id'], 0, 1));
// Get for the content type
$settings[] = db_fetch_array(db_query_range("SELECT * FROM {boost_cache_settings} WHERE page_callback = '%s' AND page_type = '%s' AND base_dir = '%s' AND page_id = '%s'", $router_item['page_callback'], $router_item['page_type'], BOOST_FILE_PATH, 0, 0, 1));
// Finally get the content container (node, view, term, ect...)
$settings[] = db_fetch_array(db_query_range("SELECT * FROM {boost_cache_settings} WHERE page_callback = '%s' AND page_type = '%s' AND base_dir = '%s' AND page_id = '%s'", $router_item['page_callback'], 0, BOOST_FILE_PATH, 0, 0, 1));
return $settings;
}
/**
* Returns all cached pages associated with the taxonomy term.
*/
function boost_get_db_term($term) {
$filenames = array();
$result = db_query("SELECT filename, hash FROM {boost_cache} WHERE expire > 0 AND expire <> 434966400 AND page_id = '%s' AND page_callback = 'taxonomy'", $term);
while ($filename = db_fetch_array($result)) {
$filenames[] = $filename;
}
return $filenames;
}
/**
* Checks various timestamps in the database.
*
* @param $set_max
* bool Allow one to read and not set the max_timestamp.
*
* @return bool
* Returns TRUE if the site has changed since the last time this function was called.
*/
function boost_has_site_changed($set_max = FALSE) {
// Get timestamps from the database
$node_revisions = boost_get_time('node_revisions', 'timestamp');
//$history = boost_get_time('history', 'timestamp');
$files = boost_get_time('files', 'timestamp');
$comments = boost_get_time('comments', 'timestamp');
$node = boost_get_time('node', 'changed');
$last_comment_timestamp = boost_get_time('node_comment_statistics', 'last_comment_timestamp');
$voteapi_vote = boost_get_time('votingapi_vote', 'timestamp');
$max = max($node_revisions, $history, $files, $comments, $node, $last_comment_timestamp, $voteapi_vote);
if ($max != BOOST_MAX_TIMESTAMP) {
if ($set_max) {
variable_set('boost_max_timestamp', (int)$max);
}
return TRUE;
}
else {
return FALSE;
}
}
/**
* Checks various timestamps in the database.
*
* @param $table
* Database table name
* @param $column
* Column containing the time stamp
* @return int
* Returns largest time in the table.
*/
function boost_get_time($table, $column) {
if (db_result(db_query("SHOW TABLES LIKE '%s'", $table))) {
return (int)db_result(db_query_range("SELECT %s FROM {%s} ORDER BY %s DESC", $column, $table, $column, 0, 1));
}
else {
return 0;
}
}
/**
* Writes data to filename in an atomic operation thats compatible with older
* versions of php (php < 5.2.4 file_put_contents() doesn't lock correctly).
*
* @param $filename
* Name of file to be written
* @param $data
* Contents of file
*/
function boost_cache_write($filename, $data = '') {
if (!_boost_mkdir_p(dirname($filename))) {
if (BOOST_VERBOSE >= 3) {
watchdog('boost', 'Unable to create directory: %dir Group ID: %gid User ID: %uid Current script owner: %user ', array('%dir' => dirname($filename), '%gid' => getmygid(), '%uid' => getmyuid(), '%user' => get_current_user()), WATCHDOG_WARNING);
}
}
$tempfile = $filename . getmypid();
if (@file_put_contents($tempfile, $data) === FALSE) {
if (BOOST_VERBOSE >= 3) {
watchdog('boost', 'Unable to write temp file: %file Group ID: %gid User ID: %uid Current script owner: %user ', array('%file' => $tempfile, '%gid' => getmygid(), '%uid' => getmyuid(), '%user' => get_current_user()), WATCHDOG_WARNING);
}
return FALSE;
}
else {
if (is_numeric(BOOST_PERMISSIONS_FILE)) {
@chmod($tempfile, octdec(BOOST_PERMISSIONS_FILE));
}
// Erase old file
if (BOOST_OVERWRITE_FILE) {
@unlink($filename);
}
// Put temp file in its final location
if (@rename($tempfile, $filename) === FALSE) {
if (BOOST_VERBOSE >= 5) {
watchdog('boost', 'Unable to rename file: %temp to %file Group ID: %gid User ID: %uid Current script owner: %user ', array('%temp' => $tempfile, '%file' => $filename, '%gid' => getmygid(), '%uid' => getmyuid(), '%user' => get_current_user()), WATCHDOG_WARNING);
}
@unlink($tempfile);
return FALSE;
}
}
return TRUE;
}
/**
* Returns the full directory path to the static file cache directory.
*
* @param $host
* Host name. Example: example.com
* @param $absolute
* Give path from system root if true. If false give path from web root.
*/
function boost_cache_directory($host = NULL, $absolute = TRUE) {
global $base_url;
if ($base_url == "http://") {
if (BOOST_VERBOSE >= 1) {
watchdog('boost', 'base_url is not set in your settings.php file. Please read #7 in boosts INSTALL.txt file.', array(), WATCHDOG_NOTICE);
}
if (!BOOST_MULTISITE_SINGLE_DB) {
$base_url = $base_url . str_replace(BOOST_ROOT_CACHE_DIR . '/', '', variable_get('boost_file_path', boost_cache_directory(NULL, FALSE)));
}
}
$parts = parse_url($base_url);
$host = !empty($host) ? $host : $parts['host'];
$parts['path'] = isset($parts['path']) ? $parts['path'] : '/';
$subdir = implode('/', array_filter(explode('/', (!empty($base_path)) ? $base_path : $parts['path'])));
return implode('/', !$absolute ? array_filter(array(BOOST_ROOT_CACHE_DIR, BOOST_NORMAL_DIR, $host, $subdir)) : array_filter(array(getcwd(), BOOST_ROOT_CACHE_DIR, BOOST_NORMAL_DIR, $host, $subdir)));
}
/**
* Returns the static file path for a Drupal page.
*
* @param $path
* path to convert to boost's file naming convention
* @param $query
* add query to path
* @param $extension
* add extension to end of filename
*
* $path = $GLOBALS['_boost_path'] most of the time
*/
function boost_file_path($path, $query = TRUE, $extension = BOOST_FILE_EXTENSION) {
//handling of url variables
if ($GLOBALS['_boost_query'] != BOOST_CHAR) {
if ($query) {
$path .= $GLOBALS['_boost_query'];
}
else {
$path .= BOOST_CHAR;
}
}
else {
$path .= $GLOBALS['_boost_query'];
}
// Under no circumstances should the incoming path contain '..' or null
// bytes; we also limit the maximum directory nesting depth of the path
if ( strpos($path, '..') !== FALSE
|| strpos($path, "\0") !== FALSE
|| count(explode('/', $path)) > BOOST_MAX_PATH_DEPTH
) {
return FALSE;
}
return implode('/', array(BOOST_FILE_PATH, $path . (is_null($extension) ? '' : $extension)));
}
/**
* Returns the time it took to generate this cached page.
* @param $filename
* Name of cached file
*/
function boost_get_generation_time($filename) {
$boost_db = boost_get_db($filename);
return $boost_db['timer_average'] != 0 ? $boost_db['timer_average']/1000.0 : FALSE;
}
/**
* Returns the age of a cached file, measured in seconds since it was last
* updated.
* @param $filename
* Name of cached file
*/
function boost_file_get_age($filename) {
return BOOST_TIME - filemtime($filename);
}
function boost_db_get_age($filename) {
$boost_db = boost_get_db($filename);
return $boost_db['expire'] != 0 ? $boost_db['expire'] : FALSE;
}
/**
* Returns the remaining time-to-live for a cached file, measured in
* seconds.
* @param $filename
* Name of cached file
*/
function boost_file_get_ttl($filename) {
return BOOST_CACHE_LIFETIME - boost_file_get_age($filename);
}
function boost_db_get_ttl($filename) {
$boost_db = boost_get_db($filename);
return boost_db_get_age($filename) - BOOST_TIME;
}
/**
* Determines whether a cached file has expired, i.e. whether its age
* exceeds the maximum cache lifetime as defined by Drupal's system
* settings.
* @param $filename
* Name of cached file
*/
function boost_file_is_expired($filename) {
return boost_file_get_age($filename) > BOOST_CACHE_LIFETIME;
}
function boost_db_is_expired($filename) {
return boost_db_get_age($filename) < BOOST_TIME;
}
/**
* Sets a special cookie preventing authenticated users getting served pages
* from the static page cache.
*
* @param $user
* User Object
* @param $expires
* Expiration time
*/
function boost_set_cookie($user, $expires = NULL) {
if (!$expires) {
$expires = ini_get('session.cookie_lifetime');
$expires = (!empty($expires) && is_numeric($expires)) ? BOOST_TIME + (int)$expires : 0;
setcookie(BOOST_COOKIE, $user->uid, $expires, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure') == '1');
}
else {
setcookie(BOOST_COOKIE, FALSE, $expires, ini_get('session.cookie_path'), ini_get('session.cookie_domain'), ini_get('session.cookie_secure') == '1');
}
$GLOBALS['_boost_cache_this'] = FALSE;
}
/**
* Retrieve a specific URL redirect from the database.
* http://drupal.org/node/451790
*
* @param $where
* Array containing 'redirect' => $path
*/
function boost_path_redirect_load($where = array(), $args = array(), $sort = array()) {
$redirects = array();
if (is_numeric($where)) {
$where = array('rid' => $where);
}
foreach ($where as $key => $value) {
if (is_string($key)) {
$args[] = $value;
$where[$key] = $key .' = '. (is_numeric($value) ? '%d' : "'%s'");
}
}
if ($where && $args) {
$sql = "SELECT * FROM {path_redirect} WHERE ". implode(' AND ', $where);
if ($sort) {
$sql .= ' ORDER BY '. implode(' ,', $sort);
}
$result = db_query($sql, $args);
while ($redirect = db_fetch_array($result)) {
$redirects[] = $redirect;
}
return $redirects;
}
}
/**
* Cache css and or js files.
*
* Parse the html file so we get all css/js files. drupal_get_js/css isn't 100%.
*
* @param $buffer
* String containing documents html.
*/
function boost_cache_css_js_files($buffer) {
if (BOOST_CACHE_CSS) {
// Extract external css files from html document
$css_files = explode(' $value) {
// Extract css filename
$temp = explode(base_path(), array_pop(explode('//', array_pop(explode('href="', array_shift(explode('" />', $value)))))));
array_shift($temp);
$css_files[$key] = array_shift(explode('"', array_shift(explode('?', implode('/', $temp)))));
}
_boost_copy_css_files($css_files);
}
if (BOOST_CACHE_JS) {
$js_files = explode('
It works!