summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2014-04-13 17:52:04 (GMT)
committerwebchick2014-04-13 17:52:04 (GMT)
commit80f9e5819e2e2fac643817fa58c05f7f58372cbc (patch)
tree9c260cfc9c1786a582ddfb8386307d9cf6e03f4a
parentacbd5fa8407597f6e206b34a4981df740a1b1f56 (diff)
Issue #1399846 by slashrsm, Gábor Hojtsy, Berdir, brantwynn, visabhishek, David_Rothstein, cweagans, martin107, SteffenR, Dave Reid: Make unused file 'cleanup' configurable.
-rw-r--r--core/includes/file.inc13
-rw-r--r--core/modules/file/file.install2
-rw-r--r--core/modules/file/file.module15
-rw-r--r--core/modules/file/lib/Drupal/file/Tests/DeleteTest.php9
-rw-r--r--core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php14
-rw-r--r--core/modules/file/lib/Drupal/file/Tests/UsageTest.php66
-rw-r--r--core/modules/system/config/schema/system.schema.yml3
-rw-r--r--core/modules/system/config/system.file.yml1
-rw-r--r--core/modules/system/lib/Drupal/system/Form/FileSystemForm.php14
-rw-r--r--core/modules/system/system.module5
-rw-r--r--core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php7
11 files changed, 111 insertions, 38 deletions
diff --git a/core/includes/file.inc b/core/includes/file.inc
index f141cc8..a26f21f 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -109,8 +109,10 @@ define('STREAM_WRAPPERS_LOCAL_NORMAL', STREAM_WRAPPERS_LOCAL | STREAM_WRAPPERS_N
* - filesize: The size of the file in bytes.
* - status: A bitmapped field indicating the status of the file. The first 8
* bits are reserved for Drupal core. The least significant bit indicates
- * temporary (0) or permanent (1). Temporary files older than
- * DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during cron runs.
+ * temporary (0) or permanent (1). Temporary files will be removed during
+ * cron runs if they are older than the configuration value
+ * "system.file.temporary_maximum_age", and if clean-up is enabled. Permanent
+ * files will not be removed.
* - timestamp: UNIX timestamp for the date the file was added to the database.
*/
@@ -142,9 +144,10 @@ const FILE_EXISTS_ERROR = 2;
/**
* Indicates that the file is permanent and should not be deleted.
*
- * Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed
- * during cron runs, but permanent files will not be removed during the file
- * garbage collection process.
+ * Temporary files older than the system.file.temporary_maximum_age
+ * configuration value will be, if clean-up not disabled, removed during cron
+ * runs, but permanent files will not be removed during the file garbage
+ * collection process.
*/
const FILE_STATUS_PERMANENT = 1;
diff --git a/core/modules/file/file.install b/core/modules/file/file.install
index fb5a4eb..6bbed79 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -69,7 +69,7 @@ function file_schema() {
'default' => 0,
),
'status' => array(
- 'description' => 'A field indicating the status of the file. Two status are defined in core: temporary (0) and permanent (1). Temporary files older than DRUPAL_MAXIMUM_TEMP_FILE_AGE will be removed during a cron run.',
+ 'description' => 'A field indicating the status of the file. Two status are defined in core: temporary (0) and permanent (1). Temporary files older than system.file.temporary_maximum_age will be removed during a cron run.',
'type' => 'int',
'not null' => TRUE,
'default' => 0,
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 3890862..2543616 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -694,9 +694,18 @@ function file_file_download($uri, $field_type = 'file') {
* Implements file_cron()
*/
function file_cron() {
- $result = \Drupal::entityManager()->getStorage('file')->retrieveTemporaryFiles();
- foreach ($result as $row) {
- if ($file = file_load($row->fid)) {
+ $age = \Drupal::config('system.file')->get('temporary_maximum_age');
+
+ // Only delete temporary files if older than $age. Note that automatic cleanup
+ // is disabled if $age set to 0.
+ if ($age) {
+ $fids = Drupal::entityQuery('file')
+ ->condition('status', FILE_STATUS_PERMANENT, '<>')
+ ->condition('changed', REQUEST_TIME - $age, '<')
+ ->range(0, 100)
+ ->execute();
+ $files = file_load_multiple($fids);
+ foreach ($files as $file) {
$references = \Drupal::service('file.usage')->listUsage($file);
if (empty($references)) {
if (file_exists($file->getFileUri())) {
diff --git a/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php b/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
index f345811..f7889b5 100644
--- a/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/DeleteTest.php
@@ -61,17 +61,18 @@ class DeleteTest extends FileManagedUnitTestBase {
$this->assertTrue($file->isTemporary(), 'File is temporary.');
file_test_reset();
- // Call system_cron() to clean up the file. Make sure the timestamp
- // of the file is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Call file_cron() to clean up the file. Make sure the changed timestamp
+ // of the file is older than the system.file.temporary_maximum_age
+ // configuration value.
db_update('file_managed')
->fields(array(
- 'changed' => REQUEST_TIME - (DRUPAL_MAXIMUM_TEMP_FILE_AGE + 1),
+ 'changed' => REQUEST_TIME - ($this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') + 1),
))
->condition('fid', $file->id())
->execute();
\Drupal::service('cron')->run();
- // system_cron() loads
+ // file_cron() loads
$this->assertFileHooksCalled(array('delete'));
$this->assertFalse(file_exists($file->getFileUri()), 'File has been deleted after its last usage was removed.');
$this->assertFalse(file_load($file->id()), 'File was removed from the database.');
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
index f586446..070217b 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
@@ -115,11 +115,12 @@ class FileFieldRevisionTest extends FileFieldTestBase {
clearstatcache($node_file_r3->getFileUri());
clearstatcache($node_file_r4->getFileUri());
- // Call system_cron() to clean up the file. Make sure the timestamp
- // of the file is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Call file_cron() to clean up the file. Make sure the changed timestamp
+ // of the file is older than the system.file.temporary_maximum_age
+ // configuration value.
db_update('file_managed')
->fields(array(
- 'changed' => REQUEST_TIME - (DRUPAL_MAXIMUM_TEMP_FILE_AGE + 1),
+ 'changed' => REQUEST_TIME - ($this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') + 1),
))
->condition('fid', $node_file_r3->id())
->execute();
@@ -130,11 +131,12 @@ class FileFieldRevisionTest extends FileFieldTestBase {
// Delete the entire node and check that the original file is deleted.
$this->drupalPostForm('node/' . $nid . '/delete', array(), t('Delete'));
- // Call system_cron() to clean up the file. Make sure the timestamp
- // of the file is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Call file_cron() to clean up the file. Make sure the changed timestamp
+ // of the file is older than the system.file.temporary_maximum_age
+ // configuration value.
db_update('file_managed')
->fields(array(
- 'changed' => REQUEST_TIME - (DRUPAL_MAXIMUM_TEMP_FILE_AGE + 1),
+ 'changed' => REQUEST_TIME - ($this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') + 1),
))
->condition('fid', $node_file_r1->id())
->execute();
diff --git a/core/modules/file/lib/Drupal/file/Tests/UsageTest.php b/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
index 3cff7da..1b3ea76 100644
--- a/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/UsageTest.php
@@ -123,24 +123,24 @@ class UsageTest extends FileManagedUnitTestBase {
}
/**
- * Ensure that temporary files are removed.
+ * Create files for all the possible combinations of age and status.
*
- * Create files for all the possible combinations of age and status. We are
- * using UPDATE statements because using the API would set the timestamp.
+ * We are using UPDATE statements because using the API would set the
+ * timestamp.
*/
- function testTempFileCleanup() {
- // Temporary file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ function createTempFiles() {
+ // Temporary file that is old.
$temp_old = file_save_data('');
db_update('file_managed')
->fields(array(
'status' => 0,
- 'changed' => 1,
+ 'changed' => REQUEST_TIME - $this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') - 1,
))
->condition('fid', $temp_old->id())
->execute();
$this->assertTrue(file_exists($temp_old->getFileUri()), 'Old temp file was created correctly.');
- // Temporary file that is less than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Temporary file that is new.
$temp_new = file_save_data('');
db_update('file_managed')
->fields(array('status' => 0))
@@ -148,17 +148,25 @@ class UsageTest extends FileManagedUnitTestBase {
->execute();
$this->assertTrue(file_exists($temp_new->getFileUri()), 'New temp file was created correctly.');
- // Permanent file that is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Permanent file that is old.
$perm_old = file_save_data('');
db_update('file_managed')
- ->fields(array('changed' => 1))
+ ->fields(array('changed' => REQUEST_TIME - $this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') - 1))
->condition('fid', $temp_old->id())
->execute();
$this->assertTrue(file_exists($perm_old->getFileUri()), 'Old permanent file was created correctly.');
- // Permanent file that is newer than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Permanent file that is new.
$perm_new = file_save_data('');
$this->assertTrue(file_exists($perm_new->getFileUri()), 'New permanent file was created correctly.');
+ return array($temp_old, $temp_new, $perm_old, $perm_new);
+ }
+
+ /**
+ * Ensure that temporary files are removed by default.
+ */
+ function testTempFileCleanupDefault() {
+ list($temp_old, $temp_new, $perm_old, $perm_new) = $this->createTempFiles();
// Run cron and then ensure that only the old, temp file was deleted.
$this->container->get('cron')->run();
@@ -167,4 +175,42 @@ class UsageTest extends FileManagedUnitTestBase {
$this->assertTrue(file_exists($perm_old->getFileUri()), 'Old permanent file was correctly ignored.');
$this->assertTrue(file_exists($perm_new->getFileUri()), 'New permanent file was correctly ignored.');
}
+
+ /**
+ * Ensure that temporary files are kept as configured.
+ */
+ function testTempFileNoCleanup() {
+ list($temp_old, $temp_new, $perm_old, $perm_new) = $this->createTempFiles();
+
+ // Set the max age to 0, meaning no temporary files will be deleted.
+ \Drupal::config('system.file')
+ ->set('temporary_maximum_age', 0)
+ ->save();
+
+ // Run cron and then ensure that no file was deleted.
+ $this->container->get('cron')->run();
+ $this->assertTrue(file_exists($temp_old->getFileUri()), 'Old temp file was correctly ignored.');
+ $this->assertTrue(file_exists($temp_new->getFileUri()), 'New temp file was correctly ignored.');
+ $this->assertTrue(file_exists($perm_old->getFileUri()), 'Old permanent file was correctly ignored.');
+ $this->assertTrue(file_exists($perm_new->getFileUri()), 'New permanent file was correctly ignored.');
+ }
+
+ /**
+ * Ensure that temporary files are kept as configured.
+ */
+ function testTempFileCustomCleanup() {
+ list($temp_old, $temp_new, $perm_old, $perm_new) = $this->createTempFiles();
+
+ // Set the max age to older than default.
+ \Drupal::config('system.file')
+ ->set('temporary_maximum_age', 21600 + 2)
+ ->save();
+
+ // Run cron and then ensure that more files were deleted.
+ $this->container->get('cron')->run();
+ $this->assertTrue(file_exists($temp_old->getFileUri()), 'Old temp file was correctly ignored.');
+ $this->assertTrue(file_exists($temp_new->getFileUri()), 'New temp file was correctly ignored.');
+ $this->assertTrue(file_exists($perm_old->getFileUri()), 'Old permanent file was correctly ignored.');
+ $this->assertTrue(file_exists($perm_new->getFileUri()), 'New permanent file was correctly ignored.');
+ }
}
diff --git a/core/modules/system/config/schema/system.schema.yml b/core/modules/system/config/schema/system.schema.yml
index 91f0605..2d9d11d 100644
--- a/core/modules/system/config/schema/system.schema.yml
+++ b/core/modules/system/config/schema/system.schema.yml
@@ -355,6 +355,9 @@ system.file:
temporary:
type: string
label: 'Temporary directory'
+ temporary_maximum_age:
+ type: integer
+ label: 'Maximum age for temporary files'
system.image:
type: mapping
diff --git a/core/modules/system/config/system.file.yml b/core/modules/system/config/system.file.yml
index 35ff1ec..e9f9df0 100644
--- a/core/modules/system/config/system.file.yml
+++ b/core/modules/system/config/system.file.yml
@@ -3,3 +3,4 @@ default_scheme: 'public'
path:
private: ''
temporary: ''
+temporary_maximum_age: 21600
diff --git a/core/modules/system/lib/Drupal/system/Form/FileSystemForm.php b/core/modules/system/lib/Drupal/system/Form/FileSystemForm.php
index 2d51684..4f5a4ee 100644
--- a/core/modules/system/lib/Drupal/system/Form/FileSystemForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/FileSystemForm.php
@@ -68,6 +68,17 @@ class FileSystemForm extends ConfigFormBase {
);
}
+ $intervals = array(0, 21600, 43200, 86400, 604800, 2419200, 7776000);
+ $period = array_combine($intervals, array_map('format_interval', $intervals));
+ $period[0] = t('Never');
+ $form['temporary_maximum_age'] = array(
+ '#type' => 'select',
+ '#title' => t('Delete orphaned files after'),
+ '#default_value' => $config->get('temporary_maximum_age'),
+ '#options' => $period,
+ '#description' => t('Orphaned files are not referenced from any content but remain in the file system and may appear in administrative listings. <strong>Warning:</strong> If enabled, orphaned files will be permanently deleted and may not be recoverable.'),
+ );
+
return parent::buildForm($form, $form_state);
}
@@ -77,7 +88,8 @@ class FileSystemForm extends ConfigFormBase {
public function submitForm(array &$form, array &$form_state) {
$config = $this->configFactory->get('system.file')
->set('path.private', $form_state['values']['file_private_path'])
- ->set('path.temporary', $form_state['values']['file_temporary_path']);
+ ->set('path.temporary', $form_state['values']['file_temporary_path'])
+ ->set('temporary_maximum_age', $form_state['values']['temporary_maximum_age']);
if (isset($form_state['values']['file_default_scheme'])) {
$config->set('default_scheme', $form_state['values']['file_default_scheme']);
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 541168d..d719b5a 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -15,11 +15,6 @@ use Symfony\Component\HttpFoundation\RedirectResponse;
use GuzzleHttp\Exception\RequestException;
/**
- * Maximum age of temporary files in seconds.
- */
-const DRUPAL_MAXIMUM_TEMP_FILE_AGE = 21600;
-
-/**
* New users will be set to the default time zone at registration.
*/
const DRUPAL_USER_TIMEZONE_DEFAULT = 0;
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
index 5ed7462..335050d 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
@@ -65,11 +65,12 @@ class UserPictureTest extends WebTestBase {
$this->drupalPostForm('user/' . $this->web_user->id() . '/edit', $edit, t('Remove'));
$this->drupalPostForm(NULL, array(), t('Save'));
- // Call system_cron() to clean up the file. Make sure the timestamp
- // of the file is older than DRUPAL_MAXIMUM_TEMP_FILE_AGE.
+ // Call file_cron() to clean up the file. Make sure the timestamp
+ // of the file is older than the system.file.temporary_maximum_age
+ // configuration value.
db_update('file_managed')
->fields(array(
- 'changed' => REQUEST_TIME - (DRUPAL_MAXIMUM_TEMP_FILE_AGE + 1),
+ 'changed' => REQUEST_TIME - ($this->container->get('config.factory')->get('system.file')->get('temporary_maximum_age') + 1),
))
->condition('fid', $file->id())
->execute();