advagg.cache.inc in Advanced CSS/JS Aggregation 7.2
Advanced CSS/JS aggregation module.
Functions used for clearing caches and killing files.
File
advagg.cache.incView source
<?php
/**
* @file
* Advanced CSS/JS aggregation module.
*
* Functions used for clearing caches and killing files.
*/
/**
* Uses the database to scan CSS/JS files for changes.
*
* @return array
* Array of files that have changed.
*/
function advagg_scan_for_changes() {
// Get all files stored in the database and filesystem.
$files_that_have_changed = array();
$result = db_select('advagg_files', 'af')
->fields('af')
->execute();
if (!empty($result)) {
module_load_include('inc', 'advagg', 'advagg');
$filenames = array();
$data = array();
foreach ($result as $row) {
$filenames[] = $row->filename;
$data[$row->filename] = (array) $row;
}
// Get filesystem data.
$files_info = advagg_get_info_on_files($filenames, TRUE);
foreach ($files_info as $info) {
if (!isset($data[$info['data']])) {
continue;
}
$row = $data[$info['data']];
// Select the keys to compare.
$keys_to_compare = array(
'filesize',
'content_hash',
'linecount',
);
$changed = array();
foreach ($keys_to_compare as $key) {
if ($row[$key] != $info[$key]) {
$changed[] = $key . ' db:' . $row[$key] . ' file:' . $info[$key];
break;
}
}
// Compare mtime if it is not zero.
if (empty($info['split']) && !empty($info['mtime'])) {
if (variable_get('advagg_strict_mtime_check', ADVAGG_STRICT_MTIME_CHECK) && $row['mtime'] != $info['mtime']) {
$changed[] = 'mtime db:' . $row['mtime'] . ' file:' . $info['mtime'];
}
elseif ($row['mtime'] < $info['mtime']) {
$changed[] = 'mtime db:' . $row['mtime'] . ' file:' . $info['mtime'];
}
}
if (empty($changed)) {
// Call hook_advagg_scan_for_changes().
$changes_array = module_invoke_all('advagg_scan_for_changes', $row['filename']);
if (is_array($changes_array)) {
foreach ($changes_array as $value) {
if (!empty($value)) {
$changed[] = $value;
break;
}
}
}
}
// If file has changed, add it to the array.
if (!empty($changed)) {
$info['changes'] = $changed;
$files_that_have_changed[$row['filename']] = $info;
}
}
}
return $files_that_have_changed;
}
/**
* Flush the correct caches so CSS/JS changes go live.
*
* @return array
* Array of files that have changed and caches flushed.
*/
function advagg_push_new_changes(array $files = array()) {
$results = array();
// Scan the file system for changes to CSS/JS files.
if (empty($files)) {
$files = advagg_scan_for_changes();
if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
$variables = array(
'@files' => print_r($files, TRUE),
);
watchdog('advagg-debug', 'Changes detected in <pre>@files</pre>.', $variables, WATCHDOG_DEBUG);
}
}
// Clear some static caches.
drupal_static_reset('advagg_get_info_on_file');
drupal_static_reset('advagg_drupal_hash_base64');
drupal_static_reset('advagg_current_hooks_hash_array');
drupal_static_reset('advagg_get_current_hooks_hash');
if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
// Exception used to get a compact stack trace.
$e = new Exception();
$variables = array(
'@changes' => print_r($e
->getTraceAsString(), TRUE),
);
watchdog('advagg-debug', 'New changes called by: <pre>@changes</pre>', $variables, WATCHDOG_DEBUG);
}
// If something changed, flush the correct caches so that change goes out.
if (!empty($files)) {
$types = array();
module_load_include('inc', 'advagg', 'advagg');
foreach ($files as $filename => $meta_data) {
// Lookup the aggregates/cache ids that use this file.
$cache_ids = advagg_get_aggregates_using_file($meta_data['filename_hash'], TRUE);
$cache_hits = array();
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$types[$ext] = TRUE;
if (!empty($cache_ids)) {
$cache_hits = cache_get_multiple($cache_ids, 'cache_advagg_info');
foreach ($cache_hits as $cid => $data) {
if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
watchdog('advagg-debug', 'Clearing cache @cid.', array(
'@cid' => $cid,
), WATCHDOG_DEBUG);
}
cache_clear_all($cid, 'cache_advagg_info', FALSE);
}
}
$changes = array();
if (!empty($meta_data['changes'])) {
$changes = $meta_data['changes'];
unset($meta_data['changes']);
}
$results[$filename] = array(
count($cache_ids),
count($cache_hits),
$changes,
);
// Update database.
advagg_insert_update_files(array(
$filename => $meta_data,
), $ext);
}
// Change query-strings on css/js files to enforce reload for all users.
// Change css_js_query_string variable.
_drupal_flush_css_js();
// Let other modules know about the changed files.
// Call hook_advagg_changed_files().
module_invoke_all('advagg_changed_files', $files, $types);
// Clear out the full aggregates cache.
foreach ($types as $ext => $bool) {
if (variable_get('advagg_debug', ADVAGG_DEBUG) >= 2) {
$variables = array(
'@ext' => print_r($ext, TRUE),
);
watchdog('advagg-debug', 'Clearing cache advagg:@ext: in cache_advagg_aggregates.', $variables, WATCHDOG_DEBUG);
}
cache_clear_all('advagg:' . $ext . ':', 'cache_advagg_aggregates', TRUE);
}
}
// Return what was done.
return $results;
}
/**
* Given a filename hash get back all aggregates that include it.
*
* @param string $filename_hash
* Hash of the filename.
* @param bool $cid_only
* Set to TRUE to only have cache ids returned.
*
* @return array
* Array of aggregates that use this file.
*/
function advagg_get_aggregates_using_file($filename_hash, $cid_only = FALSE) {
// Create main query for the advagg_aggregates table.
$query = db_select('advagg_aggregates', 'aa')
->condition('aa.filename_hash', $filename_hash);
// Create join query for the advagg_aggregates_versions table.
$query
->join('advagg_aggregates_versions', 'aav', 'aa.aggregate_filenames_hash = aav.aggregate_filenames_hash AND aav.atime > 0');
$query = $query
->fields('aav', array(
'aggregate_filenames_hash',
'aggregate_contents_hash',
));
$query
->comment('Query called from ' . __FUNCTION__ . '()');
$results = $query
->execute();
// Put results into $aggregates array.
$aggregates = array();
foreach ($results as $row) {
$row = (array) $row;
$cid = 'advagg:db:' . $row['aggregate_filenames_hash'] . ADVAGG_SPACE . $row['aggregate_contents_hash'];
if ($cid_only) {
$aggregates[] = $cid;
}
else {
$row['cid'] = $cid;
$aggregates[] = $row;
}
}
return $aggregates;
}
/**
* Get all CSS/JS advagg files.
*
* @param array $options
* Array of options to pass along to file_scan_directory().
*
* @return array
* Array of css and js files.
*/
function advagg_get_all_files(array $options = array()) {
list($css_path, $js_path) = advagg_get_root_files_dir();
$options += array(
'nomask' => '/(\\.\\.?|CVS|\\.gz|\\.br)$/',
);
// Get a list of files.
$css_files = file_scan_directory($css_path[0], '/.*/', $options);
$js_files = file_scan_directory($js_path[0], '/.*/', $options);
return array(
$css_files,
$js_files,
);
}
/**
* Scan CSS/JS advagg dir and remove that file if atime is grater than 30 days.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_stale_aggregates() {
list($css_files, $js_files) = advagg_get_all_files();
// Make the advagg_get_hashes_from_filename() function available.
module_load_include('inc', 'advagg', 'advagg.missing');
$css_files = advagg_delete_files_if_stale($css_files);
$js_files = advagg_delete_files_if_stale($js_files);
return array(
$css_files,
$js_files,
);
}
/**
* Given an array of files remove that file if atime is grater than 30 days.
*
* @param array $files
* Array of files returned by file_scan_directory.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_files_if_stale(array $files) {
// Array used to record what files were deleted.
$kill_list = array();
foreach ($files as $uri => $file) {
// Get info on file.
$filename = $file->filename;
$data = advagg_get_hashes_from_filename($filename);
if (is_array($data)) {
list(, $aggregate_filenames_hash, $aggregate_contents_hash) = $data;
}
else {
// Can not get data on file, remove it.
$kill_list[] = advagg_delete_file_by_uri($uri);
continue;
}
// Get atime of file.
$atime = advagg_get_atime($aggregate_filenames_hash, $aggregate_contents_hash, $uri);
if (empty($atime)) {
$kill_list[] = advagg_delete_file_by_uri($uri);
continue;
}
// Default stale file threshold is 30 days.
if (REQUEST_TIME - $atime > variable_get('drupal_stale_file_threshold', 2592000)) {
$kill_list[] = advagg_delete_file_by_uri($uri);
continue;
}
}
// Let other modules know about the removed files.
// Call hook_advagg_removed_aggregates().
module_invoke_all('advagg_removed_aggregates', $kill_list);
return $kill_list;
}
/**
* Scan CSS/JS advagg dir and remove that file if it is empty.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_empty_aggregates() {
list($css_files, $js_files) = advagg_get_all_files();
$css_files = advagg_delete_files_if_empty($css_files);
$js_files = advagg_delete_files_if_empty($js_files);
return array(
$css_files,
$js_files,
);
}
/**
* Given an array of files remove that file if it is empty.
*
* @param array $files
* Array of files returned by file_scan_directory.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_files_if_empty(array $files) {
// Array used to record what files were deleted.
$kill_list = array();
foreach ($files as $uri => $file) {
// Ignore temp files. There's a separate process for cleaning those up.
if (strpos($uri, '/advagg_file_') !== FALSE) {
continue;
}
$size = filesize($uri);
if ($size === 0) {
$kill_list[] = advagg_delete_file_by_uri($uri);
continue;
}
}
// Let other modules know about the removed files.
// Call hook_advagg_removed_aggregates().
module_invoke_all('advagg_removed_aggregates', $kill_list);
return $kill_list;
}
/**
* Delete a file, and any compressed versions.
*
* @param string $uri
* URI of the file to delete.
*
* @return string
* The given URI.
*/
function advagg_delete_file_by_uri($uri) {
if (file_exists($uri)) {
file_unmanaged_delete($uri);
}
if (file_exists($uri . '.gz')) {
file_unmanaged_delete($uri . '.gz');
}
if (file_exists($uri . '.br')) {
file_unmanaged_delete($uri . '.br');
}
return $uri;
}
/**
* Perform a cache_clear_all on all bins returned by advagg_flush_caches(TRUE).
*
* @param bool $push_new_changes
* FALSE: Do not scan for changes.
*/
function advagg_flush_all_cache_bins($push_new_changes = TRUE) {
$bins = advagg_flush_caches(TRUE, $push_new_changes);
foreach ($bins as $bin) {
cache_clear_all('*', $bin, TRUE);
}
}
/**
* Remove all files from the advagg CSS/JS directories.
*
* @param bool $kill_htaccess
* Set to TRUE to remove the htaccess files as well.
*
* @return array
* Array of all files removed.
*/
function advagg_remove_all_aggregated_files($kill_htaccess = FALSE) {
$options = array(
'callback' => 'file_unmanaged_delete',
'nomask' => '/(\\.\\.?|CVS)$/',
);
list($css_files, $js_files) = advagg_get_all_files($options);
// Let other modules know about the removed files.
// Call hook_advagg_removed_aggregates().
module_invoke_all('advagg_removed_aggregates', $css_files);
module_invoke_all('advagg_removed_aggregates', $js_files);
// Remove the htaccess files as well.
if ($kill_htaccess) {
list($css_path, $js_path) = advagg_get_root_files_dir();
if (file_exists($css_path[0] . '/.htaccess')) {
file_unmanaged_delete($css_path[0] . '/.htaccess');
$css_files[] = $css_path[0] . '/.htaccess';
}
if (file_exists($js_path[0] . '/.htaccess')) {
file_unmanaged_delete($js_path[0] . '/.htaccess');
$js_files[] = $js_path[0] . '/.htaccess';
}
}
return array(
$css_files,
$js_files,
);
}
/**
* Increment the advagg_global_counter variable by one.
*
* @todo Allow this value to be kept in sync across a multisite.
*
* @return int
* New value of advagg_global_counter.
*/
function advagg_increment_global_counter() {
$new_value = advagg_get_global_counter() + 1;
variable_set('advagg_global_counter', $new_value);
return $new_value;
}
/**
* Scan for missing files and remove the associated entries in the database.
*
* @return array
* Array of what files were cleared out of the database.
*/
function advagg_remove_missing_files_from_db() {
$missing_files = array();
$deleted = array();
// Get all files stored in the database.
$result = db_select('advagg_files', 'af')
->fields('af')
->execute();
if (empty($result)) {
return $deleted;
}
// Find missing files.
module_load_include('inc', 'advagg', 'advagg');
foreach ($result as $row) {
$row = (array) $row;
$info = advagg_get_info_on_file($row['filename'], TRUE);
// Make sure file exists.
if (empty($info['content_hash'])) {
$info += advagg_get_aggregates_using_file($info['filename_hash']);
$missing_files[$row['filename']] = $info;
continue;
}
}
if (empty($missing_files)) {
return $deleted;
}
// Remove missing file database entries.
$types = array();
foreach ($missing_files as $filename => $data) {
// Setup this run.
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$advagg_files_del = 0;
$advagg_aggregates_del = 0;
$advagg_aggregates_versions_del = 0;
$clean_sweep = TRUE;
$filename_hash = '';
// Scan the data.
foreach ($data as $key => $values) {
if (!is_numeric($key)) {
$filename_hash = $values;
}
else {
// Remove the entry from the database if this aggregate has not been
// accessed in the last 2 weeks.
$can_delete = db_delete('advagg_aggregates_versions')
->condition('aggregate_filenames_hash', $values['aggregate_filenames_hash'])
->condition('atime', REQUEST_TIME - variable_get('advagg_remove_missing_files_from_db_time', ADVAGG_REMOVE_MISSING_FILES_FROM_DB_TIME), '<')
->execute();
if ($can_delete > 0) {
$advagg_aggregates_versions_del += $can_delete;
$advagg_aggregates_del += db_delete('advagg_aggregates')
->condition('aggregate_filenames_hash', $values['aggregate_filenames_hash'])
->execute();
}
else {
$clean_sweep = FALSE;
}
// Clear the cache.
cache_clear_all($values['cid'], 'cache_advagg_info', FALSE);
}
}
// Remove the file entry if all aggregates referencing it have been removed.
if ($clean_sweep) {
$advagg_files_del += db_delete('advagg_files')
->condition('filename_hash', $filename_hash)
->execute();
// Add info to array.
if (!empty($advagg_files_del) || !empty($advagg_aggregates_versions_del) || !empty($advagg_aggregates_del)) {
$types[$ext] = TRUE;
$deleted[$filename] = array(
'advagg_files' => $advagg_files_del,
'advagg_aggregates_versions' => $advagg_aggregates_versions_del,
'advagg_aggregates' => $advagg_aggregates_del,
);
}
}
}
// If something was deleted, clear the full aggregates cache.
if (!empty($deleted)) {
foreach ($types as $ext => $bool) {
cache_clear_all('advagg:' . $ext . ':', 'cache_advagg_aggregates', TRUE);
}
}
// Return what was deleted.
return $deleted;
}
/**
* Scan CSS/JS advagg dir and remove file if there is no associated db record.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_orphaned_aggregates() {
list($css_files, $js_files) = advagg_get_all_files();
// Make the advagg_get_hashes_from_filename() function available.
module_load_include('inc', 'advagg', 'advagg.missing');
$css_files = advagg_delete_files_if_orphaned($css_files);
$js_files = advagg_delete_files_if_orphaned($js_files);
return array(
$css_files,
$js_files,
);
}
/**
* Given an array of files remove that file if there is no associated db record.
*
* @param array $files
* Array of files returned by file_scan_directory.
*
* @return array
* Array of files that got removed.
*/
function advagg_delete_files_if_orphaned(array $files) {
// Get the uri for the advagg_css/parts directory.
list($css_path) = advagg_get_root_files_dir();
$parts_uri = $css_path[0] . '/parts/';
// Array used to record what files were deleted.
$kill_list = $keyed_file_list = array();
// Create a listing of all file names and associated hashes.
foreach ($files as $uri => $file) {
// Get info on file.
$data = advagg_get_hashes_from_filename($file->filename, TRUE);
if (is_array($data)) {
list(, $aggregate_filenames_hash) = $data;
// Check to see if the file is in the database.
$keyed_file_list[$aggregate_filenames_hash] = $uri;
}
else {
// Check to see if this is a parts css file.
$start = strpos($file->uri, $parts_uri);
if ($start !== FALSE) {
// Get the original filename.
$original_file = substr($file->uri, $start + strlen($parts_uri));
$original_file = preg_replace('/(.\\d+\\.css)$/i', '.css', $original_file);
if (file_exists($original_file)) {
// Original file exists, do not delete.
continue;
}
}
// Can not get data on file, remove it.
$kill_list[] = $uri;
continue;
}
}
if (!empty($keyed_file_list)) {
$filenames_hash = array_keys($keyed_file_list);
$aggregates_in_database = array();
// Process in chunks when a large array is passed.
do {
// Check if the aggregate_filenames_hash exists in the database.
$aggregates_in_database += db_select('advagg_aggregates_versions', 'av')
->fields('av', array(
'aggregate_filenames_hash',
))
->condition('av.aggregate_filenames_hash', array_splice($filenames_hash, 0, 1000), 'IN')
->distinct()
->execute()
->fetchAllAssoc('aggregate_filenames_hash');
} while (count($filenames_hash));
// Get values not found in the database.
$to_delete = array_values(array_diff_key($keyed_file_list, $aggregates_in_database));
// Add the file uri to the kill list.
$kill_list = array_merge($kill_list, $to_delete);
}
if (!empty($kill_list)) {
foreach ($kill_list as $uri) {
advagg_delete_file_by_uri($uri);
}
}
// Let other modules know about the removed files.
// Call hook_advagg_removed_aggregates().
module_invoke_all('advagg_removed_aggregates', $kill_list);
return $kill_list;
}
/**
* Delete aggregates that have not been accessed in the last 6 weeks.
*
* @return int
* Count of the number of rows removed from the databases.
*/
function advagg_remove_old_unused_aggregates() {
$advagg_aggregates_versions_del = 0;
$advagg_aggregates_del = 0;
// Find orphaned aggregate versions entries.
// Create main query.
$query = db_select('advagg_aggregates_versions', 'aav')
->fields('aav', array(
'aggregate_filenames_hash',
))
->groupBy('aav.aggregate_filenames_hash');
// Create join and add in query comment.
$query
->leftjoin('advagg_aggregates', 'aa', 'aa.aggregate_filenames_hash=aav.aggregate_filenames_hash');
$query
->isNull('aa.aggregate_filenames_hash');
$query
->comment('Query called from ' . __FUNCTION__ . '()');
$results = $query
->execute();
// If we have an orphaned db entry, delete it.
if (!empty($results)) {
foreach ($results as $row) {
$advagg_aggregates_versions_del += db_delete('advagg_aggregates_versions')
->condition('aggregate_filenames_hash', $row->aggregate_filenames_hash)
->execute();
}
}
// Delete aggregate versions that have not been accessed in the last 45 days.
$advagg_aggregates_versions_del += db_delete('advagg_aggregates_versions')
->condition('atime', REQUEST_TIME - variable_get('advagg_remove_old_unused_aggregates_time', ADVAGG_REMOVE_OLD_UNUSED_AGGREGATES_TIME), '<')
->execute();
// See if any aggregates are orphaned now.
// Create main query.
$query = db_select('advagg_aggregates', 'aa')
->fields('aa', array(
'aggregate_filenames_hash',
))
->groupBy('aa.aggregate_filenames_hash');
// Create join and add in query comment.
$query
->leftjoin('advagg_aggregates_versions', 'aav', 'aa.aggregate_filenames_hash=aav.aggregate_filenames_hash');
$query
->isNull('aav.aggregate_filenames_hash');
$query
->comment('Query called from ' . __FUNCTION__ . '()');
$results = $query
->execute();
// If we have an orphaned db entry, delete it.
if (!empty($results)) {
foreach ($results as $row) {
$advagg_aggregates_del += db_delete('advagg_aggregates')
->condition('aggregate_filenames_hash', $row->aggregate_filenames_hash)
->execute();
}
}
// Return the total count of entires removed from the database.
return $advagg_aggregates_versions_del + $advagg_aggregates_del;
}
/**
* Delete orphaned/expired advagg locks from the semaphore database table.
*
* @return int
* Count of the number of rows removed from the databases.
*/
function advagg_cleanup_semaphore_table() {
// Let expiration times vary by 5 minutes.
$fuzz_factor = 300;
$results = db_delete('semaphore')
->condition('name', db_like('advagg_') . '%', 'LIKE')
->condition('expire', REQUEST_TIME - $fuzz_factor, '<')
->execute();
return $results;
}
/**
* Delete leftover temp files.
*
* @return int
* Count of the number of files removed
*/
function advagg_remove_temp_files() {
// Make sure advagg_get_root_files_dir() is available.
drupal_load('module', 'advagg');
// Make sure advagg_install_delete_empty_file_if_stale() is available.
module_load_include('install', 'advagg', 'advagg');
// Get the advagg paths.
$advagg_path = advagg_get_root_files_dir();
$total_count = 0;
// Get the top level path.
$top_level = substr($advagg_path[0][0], 0, strpos($advagg_path[0][0], 'advagg_css'));
// Remove empty temp files from public://.
$files = file_scan_directory($top_level, '/(?!files$)file.*|fil.*\\.tmp/', array(
'recurse' => FALSE,
'callback' => 'advagg_install_delete_empty_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_css.
$files = file_scan_directory($advagg_path[0][0], '/file.*|fil.*\\.tmp/', array(
'recurse' => FALSE,
'callback' => 'advagg_install_delete_empty_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_js.
$files = file_scan_directory($advagg_path[1][0], '/file.*|fil.*\\.tmp/', array(
'recurse' => FALSE,
'callback' => 'advagg_install_delete_empty_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://.
$files = file_scan_directory($top_level, '/file_advagg_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_css.
$files = file_scan_directory($advagg_path[0][0], '/file_advagg_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_js.
$files = file_scan_directory($advagg_path[1][0], '/file_advagg_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://.
$files = file_scan_directory($top_level, '/advagg_file_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_css.
$files = file_scan_directory($advagg_path[0][0], '/advagg_file_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Remove empty temp files from public://advagg_js.
$files = file_scan_directory($advagg_path[1][0], '/advagg_file_.*/', array(
'recurse' => FALSE,
'callback' => 'advagg_delete_temp_file_if_stale',
));
foreach ($files as $key => $file) {
if (file_exists($file->uri)) {
unset($files[$key]);
}
}
$total_count += count($files);
// Output info.
return $total_count;
}
/**
* Refresh all locale files.
*
* @return int
* Count of the number of files removed
*/
function advagg_refresh_all_locale_files() {
$locale_files = array();
if (!module_exists('locale')) {
return $locale_files;
}
$results = db_select('advagg_files', 'af')
->fields('af')
->condition('af.filetype', 'js')
->condition('af.filesize', 0, '>')
->execute();
$javascript = array();
foreach ($results as $row) {
$javascript[] = array(
'type' => 'file',
'data' => $row->filename,
);
}
if (!empty($javascript)) {
$javascript_before = $javascript;
$language_before = $GLOBALS['language'];
$language_list = language_list();
foreach ($language_list as $lang) {
if ($lang->enabled) {
$GLOBALS['language'] = $lang;
$javascript = $javascript_before;
locale_js_alter($javascript);
$locale_file = array_diff_key($javascript, $javascript_before);
$locale_files += $locale_file;
}
}
$GLOBALS['language'] = $language_before;
}
return $locale_files;
}
/**
* Callback to delete files if modified more than 60 seconds ago.
*
* @param string $uri
* Location of the file to check.
*/
function advagg_delete_temp_file_if_stale($uri) {
// Set stale file threshold to 60 seconds.
if (REQUEST_TIME - filemtime($uri) > 60) {
file_unmanaged_delete($uri);
}
}
/**
* See if any of the subfiles has changed.
*
* @param string $filename
* Name of the file that is related to the subfiles.
* @param array $subfiles
* An array of files to check for changes.
* @param string $keyname
* Under what key to save the info on the files.
* @param bool $save_changes
* If TRUE then the changes will be updated in the cache.
*
* @return bool
* TRUE if one of the subfiles has changed.
*/
function advagg_detect_subfile_changes($filename, array $subfiles, $keyname, $save_changes = FALSE) {
// Get the info on this file from the cache.
module_load_include('inc', 'advagg', 'advagg');
$info = advagg_get_info_on_file($filename);
$hash_id = 'advagg:subfiles:' . $keyname . ':' . $info['filename_hash'];
if (!isset($info[$keyname])) {
// Pull up the info from the database if missing from the cache.
$info[$keyname] = advagg_get_hash_settings($hash_id);
}
$subfile_changed = array();
// Check every subfile seeing if they have changed.
foreach ($subfiles as $subfile) {
$current_file_info = $defaults = array(
'hash' => '',
'size' => 0,
'mtime' => 0,
);
// Get the currently saved info on this file.
$saved_file_info = isset($info[$keyname][$subfile]) ? $info[$keyname][$subfile] : array();
$saved_file_info += $defaults;
// Get the current info on the file.
if (file_exists($subfile)) {
$current_file_info = array(
'hash' => drupal_hash_base64((string) @advagg_file_get_contents($subfile)),
'size' => filesize($subfile),
'mtime' => filemtime($subfile),
);
}
// Set the info in case a save happens.
$info[$keyname][$subfile] = $current_file_info;
// Check for any differences.
$diff = array_diff_assoc($saved_file_info, $current_file_info);
if (!empty($diff)) {
$subfile_changed[$subfile] = $diff;
}
}
if (!empty($subfile_changed) && $save_changes) {
$cache_id = 'advagg:file:' . $info['filename_hash'];
// Set static cache.
$filename_hashes =& drupal_static('advagg_get_info_on_file');
$filename_hashes[$cache_id] = $info;
// Set drupal cache.
cache_set($cache_id, $info, 'cache_advagg_info', CACHE_PERMANENT);
// Save to database.
advagg_set_hash_settings($hash_id, $info[$keyname]);
}
return $subfile_changed;
}
Functions
Name | Description |
---|---|
advagg_cleanup_semaphore_table | Delete orphaned/expired advagg locks from the semaphore database table. |
advagg_delete_empty_aggregates | Scan CSS/JS advagg dir and remove that file if it is empty. |
advagg_delete_files_if_empty | Given an array of files remove that file if it is empty. |
advagg_delete_files_if_orphaned | Given an array of files remove that file if there is no associated db record. |
advagg_delete_files_if_stale | Given an array of files remove that file if atime is grater than 30 days. |
advagg_delete_file_by_uri | Delete a file, and any compressed versions. |
advagg_delete_orphaned_aggregates | Scan CSS/JS advagg dir and remove file if there is no associated db record. |
advagg_delete_stale_aggregates | Scan CSS/JS advagg dir and remove that file if atime is grater than 30 days. |
advagg_delete_temp_file_if_stale | Callback to delete files if modified more than 60 seconds ago. |
advagg_detect_subfile_changes | See if any of the subfiles has changed. |
advagg_flush_all_cache_bins | Perform a cache_clear_all on all bins returned by advagg_flush_caches(TRUE). |
advagg_get_aggregates_using_file | Given a filename hash get back all aggregates that include it. |
advagg_get_all_files | Get all CSS/JS advagg files. |
advagg_increment_global_counter | Increment the advagg_global_counter variable by one. |
advagg_push_new_changes | Flush the correct caches so CSS/JS changes go live. |
advagg_refresh_all_locale_files | Refresh all locale files. |
advagg_remove_all_aggregated_files | Remove all files from the advagg CSS/JS directories. |
advagg_remove_missing_files_from_db | Scan for missing files and remove the associated entries in the database. |
advagg_remove_old_unused_aggregates | Delete aggregates that have not been accessed in the last 6 weeks. |
advagg_remove_temp_files | Delete leftover temp files. |
advagg_scan_for_changes | Uses the database to scan CSS/JS files for changes. |