View source
<?php
function auditfiles_help($section) {
switch ($section) {
case 'admin/settings/auditfiles':
return t('You can choose to exclude specific files, paths and extensions from the \'files not in database\' audit report by adding them to the relevant lists below.');
case 'admin/help#auditfiles':
return '<p>' . t('The audit files module performs an audit of the file table and the files directory to check for inconsistencies.') . '</p>';
case 'admin/logs/auditfiles':
return '<p>' . t('These reports allow you to audit the consistency of the {files} table and your physical files. Choose from the two reports offered below.') . '</p>';
case 'admin/logs/auditfiles/notonserver':
$output .= '<p>' . t('The files listed below are in the {files} table but the physical files do not exist on the server. This might mean the file has been deleted using a program such as FTP, or it may mean there is an error in the database. You can click on the node numbers to view the item to which the missing file relates to try and determine what action needs to be taken. For example, you may need to edit the node to re-attach the file.') . '</p>';
$output .= '<p>' . t('Files in this list are relative to the files directory %directorypath.', array(
'%directorypath' => file_directory_path(),
)) . '</p>';
return $output;
case 'admin/logs/auditfiles/notindb':
$output .= '<p>' . t('The files listed below are in the files directory on the server but appear to have no corresponding entry in the {files} table. Files in "temporary" folders such as those created by the image module are included in order to check that they are not filling up. You can choose to delete files from this report but remember that if you do this the action cannot be undone.') . '</p>';
$output .= '<p>' . t('Files in this list are relative to the files directory %directorypath.', array(
'%directorypath' => file_directory_path(),
)) . '</p>';
if ($_POST['operation'] == 'delete' && $_POST['files']) {
$output = '';
}
return $output;
}
}
function auditfiles_perm() {
return array(
'access file audits',
'administer file audits',
);
}
function auditfiles_menu($may_cache) {
$items = array();
$access = user_access('access file audits');
if ($may_cache) {
$items[] = array(
'path' => 'admin/logs/auditfiles',
'title' => t('Audit files'),
'description' => t('Perform an audit of the file system.'),
'access' => $access,
'type' => MENU_ITEM_GROUPING,
'weight' => 10,
);
$items[] = array(
'path' => 'admin/logs/auditfiles/notindb',
'title' => t('Not in database'),
'description' => t('List files that are on the server, but not in the database.'),
'callback' => 'auditfiles_notindb',
'access' => $access,
);
$items[] = array(
'path' => 'admin/logs/auditfiles/notonserver',
'title' => t('Not on server'),
'description' => t('List files that are in the database, but not on the server.'),
'callback' => 'auditfiles_notonserver',
'access' => $access,
);
$items[] = array(
'path' => 'admin/settings/auditfiles',
'title' => 'Audit files',
'callback' => 'drupal_get_form',
'callback arguments' => array(
'auditfiles_admin_settings',
),
'access' => user_access('administer file audits'),
'type' => MENU_NORMAL_ITEM,
'description' => t('Set file, extension and path exclusions for file audits.'),
);
}
return $items;
}
function auditfiles_notonserver() {
drupal_set_title(t('Audit of files not on the server'));
$header = array(
array(
'data' => t('Node'),
'field' => 'nid',
'sort' => 'asc',
),
array(
'data' => t('File'),
'field' => 'filepath',
),
array(
'data' => t('Operations'),
),
);
$sql = 'SELECT nid, filepath FROM {files}';
$table_sort = tablesort_sql($header);
$result = db_query($sql . $table_sort);
$rows = array();
while ($file = db_fetch_object($result)) {
$target = file_create_path($file->filepath);
if (!file_exists($target)) {
$file->filepath = preg_replace('@^' . preg_quote(file_directory_path()) . '/@', '', $file->filepath);
$rows[] = array(
array(
'data' => l($file->nid, 'node/' . $file->nid),
),
array(
'data' => $file->filepath,
),
array(
'data' => l(t('edit'), 'node/' . $file->nid . '/edit'),
),
);
}
}
if ($rows) {
$output .= format_plural(count($rows), '1 file found.', '@count files found.');
$output .= theme('table', $header, $rows);
}
else {
$output .= t('No files found.');
}
return $output;
}
function auditfiles_notindb_form() {
global $form_values;
$filesnotindb = _auditfiles_filesnotindb();
if ($filesnotindb) {
$form['count'] = array(
'#value' => format_plural(count($filesnotindb), '1 file found.', '@count files found.'),
);
}
else {
$form['count'] = array(
'#value' => t('No files found.'),
);
}
$form['options'] = array(
'#type' => 'fieldset',
'#title' => t('Action'),
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
);
$options = array(
'donothing' => t('Do nothing'),
'delete' => t('Delete checked files'),
);
$form['options']['operation'] = array(
'#type' => 'select',
'#options' => $options,
'#default_value' => 'donothing',
);
$form['options']['submit'] = array(
'#type' => 'submit',
'#value' => t('Update'),
);
$files_dir = file_directory_path();
foreach ($filesnotindb as $file) {
$files[$file] = '';
$form['file'][$file] = array(
'#value' => l($file, $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $file)),
);
}
$form['files'] = array(
'#type' => 'checkboxes',
'#options' => $files,
);
return $form;
}
function theme_auditfiles_notindb_form($form) {
$output .= drupal_render($form['count']);
$header = array(
t('Delete?'),
t('File'),
);
if (isset($form['file']) && is_array($form['file'])) {
foreach (element_children($form['file']) as $key) {
$row = array();
$row[] = drupal_render($form['files'][$key]);
$row[] = drupal_render($form['file'][$key]);
$rows[] = $row;
}
$output .= drupal_render($form['options']);
$output .= theme('table', $header, $rows);
}
return $output;
}
function auditfiles_notindb() {
if ($_POST['operation'] == 'delete' && $_POST['files']) {
return drupal_get_form('auditfiles_multiple_delete_confirm');
}
drupal_set_title(t('Audit of files not in the database'));
$output .= drupal_get_form('auditfiles_notindb_form');
return $output;
}
function _auditfiles_directorytoarray($directory, $recursive) {
$array_items = array();
if ($handle = opendir($directory)) {
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") {
if (is_dir($directory . "/" . $file)) {
if ($recursive) {
$array_items = array_merge($array_items, _auditfiles_directorytoarray($directory . "/" . $file, $recursive));
}
$file = $directory . "/" . $file;
$array_items[] = preg_replace("/\\/\\//si", "/", $file);
}
else {
$file = $directory . "/" . $file;
$array_items[] = preg_replace("/\\/\\//si", "/", $file);
}
}
}
closedir($handle);
}
return $array_items;
}
function _auditfiles_filesnotindb() {
$filesnotindb = array();
$result = db_query("SELECT filepath FROM {files} ORDER BY filepath ASC");
$filesindb = array();
while ($file = db_fetch_object($result)) {
$filesindb[] = file_create_path($file->filepath);
}
$filesonserver = _auditfiles_directorytoarray(realpath(file_create_path()), TRUE);
asort($filesonserver);
$root .= realpath('./');
$exclusions = _auditfiles_make_preg();
foreach ($filesonserver as $file) {
$file = preg_replace('@' . preg_quote($root) . '.@', '', $file);
if (!file_check_directory($file)) {
if (!preg_match('@' . $exclusions . '@', $file) || !$exclusions) {
if (!in_array($file, $filesindb)) {
$file = preg_replace('@^' . preg_quote(file_directory_path()) . '/@', '', $file);
$filesnotindb[] = $file;
}
}
}
}
return $filesnotindb;
}
function auditfiles_multiple_delete_confirm() {
$edit = $_POST;
$form['files'] = array(
'#prefix' => '<ul>',
'#suffix' => '</ul>',
'#tree' => TRUE,
);
foreach (array_filter($edit['files']) as $file) {
$form['files'][$file] = array(
'#type' => 'hidden',
'#value' => $file,
'#prefix' => '<li>',
'#suffix' => check_plain($file) . "</li>\n",
);
}
$form['operation'] = array(
'#type' => 'hidden',
'#value' => 'delete',
);
return confirm_form($form, t('Are you sure you want to delete these items?'), 'admin/logs/auditfiles/notindb', '<strong>' . t('This action cannot be undone.') . '</strong>', t('Delete all'), t('Cancel'));
}
function auditfiles_multiple_delete_confirm_submit($form_id, $form_values) {
if ($form_values['confirm']) {
foreach ($form_values['files'] as $file) {
if (file_delete(file_create_path($file))) {
watchdog('audit', t('%file was deleted', array(
'%file' => $file,
)));
}
else {
drupal_set_message(t('Failed to delete %file', array(
'%file' => $file,
)));
}
}
drupal_set_message(t('The items have been deleted.'));
}
return 'admin/logs/auditfiles/notindb';
}
function auditfiles_admin_settings() {
$form['auditfiles_exclude_files'] = array(
'#type' => 'textfield',
'#title' => t('Exclude these files'),
'#default_value' => trim(variable_get('auditfiles_exclude_files', '.htaccess')),
'#description' => t('Enter a list of files to exclude, separated by spaces.'),
);
$form['auditfiles_exclude_extensions'] = array(
'#type' => 'textfield',
'#title' => t('Exclude these extensions'),
'#default_value' => trim(variable_get('auditfiles_exclude_extensions', '')),
'#description' => t('Enter a list of extensions to exclude, separated by spaces. Do not include the leading dot.'),
);
$form['auditfiles_exclude_paths'] = array(
'#type' => 'textfield',
'#title' => t('Exclude these paths'),
'#default_value' => trim(variable_get('auditfiles_exclude_paths', 'color')),
'#description' => t('Enter a list of paths to exclude, separated by spaces. Do not include the leading slash. Paths are relative to %directorypath', array(
'%directorypath' => file_directory_path(),
)),
);
return system_settings_form($form);
}
function _auditfiles_make_preg() {
$files = trim(variable_get('auditfiles_exclude_files', '.htaccess'));
$extensions = trim(variable_get('auditfiles_exclude_extensions', ''));
$paths = trim(variable_get('auditfiles_exclude_paths', 'color'));
$exclusions_array = array();
if ($files) {
$exclude_files = explode(' ', $files);
array_walk($exclude_files, '_auditfiles_preg_quote', FALSE);
$exclusions_array = array_merge($exclusions_array, $exclude_files);
}
if ($paths) {
$exclude_paths = explode(' ', $paths);
array_walk($exclude_paths, '_auditfiles_preg_quote', TRUE);
$exclusions_array = array_merge($exclusions_array, $exclude_paths);
}
if ($extensions) {
$exclude_extensions = explode(' ', $extensions);
array_walk($exclude_extensions, '_auditfiles_preg_quote', FALSE);
$extensions = implode('|', $exclude_extensions);
$extensions = '(' . $extensions . ')$';
$exclusions_array[] = $extensions;
}
$exclusions = implode('|', $exclusions_array);
return $exclusions;
}
function _auditfiles_preg_quote(&$element, $key, $makefilepath = FALSE) {
if ($makefilepath) {
$element = file_create_path($element);
}
$element = preg_quote($element);
}