security updates of unpatched modules

This commit is contained in:
Bachir Soussi Chiadmi
2016-10-25 16:23:00 +02:00
parent 610760bedf
commit f6f7fd575f
133 changed files with 5598 additions and 2574 deletions

View File

@@ -1 +0,0 @@
.DS_Store

View File

@@ -238,8 +238,17 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
}
// Try and get a batch context if possible.
$eid = !empty($_GET['eid']) ? $_GET['eid'] :
(!empty($this->batched_execution_state->eid) ? $this->batched_execution_state->eid : FALSE);
if (!empty($_GET['eid']) && !empty($_GET['token']) && drupal_valid_token($_GET['token'], 'views_data_export/' . $_GET['eid'])) {
$eid = $_GET['eid'];
}
elseif (!empty($this->batched_execution_state->eid)) {
$eid = $this->batched_execution_state->eid;
}
else {
$eid = FALSE;
}
if ($eid) {
$this->batched_execution_state = views_data_export_get($eid);
}
@@ -293,19 +302,29 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
$this->batched_execution_state = views_data_export_new($this->view->name, $this->view->current_display, $this->outputfile_create());
views_data_export_view_store($this->batched_execution_state->eid, $this->view);
// Record a usage of our file, so we can identify our exports later.
file_usage_add(file_load($this->batched_execution_state->fid), 'views_data_export', 'eid', $this->batched_execution_state->eid);
// We need to build the index right now, before we lose $_GET etc.
$this->initialize_index();
//$this->batched_execution_state->fid = $this->outputfile_create();
// Initialize the progress counter
$this->batched_execution_state->sandbox['max'] = db_query('SELECT COUNT(*) FROM {' . $this->index_tablename() . '}')->fetchField();
// Initialize the progress counter.
if (db_table_exists($this->index_tablename())) {
$this->batched_execution_state->sandbox['max'] = db_query('SELECT COUNT(*) FROM {' . $this->index_tablename() . '}')->fetchField();
}
// Record the time we started.
list($usec, $sec) = explode(' ', microtime());
$this->batched_execution_state->sandbox['started'] = (float) $usec + (float) $sec;
// Pop something into the session to ensure it stays aorund.
$_SESSION['views_data_export'][$this->batched_execution_state->eid] = TRUE;
// Build up our querystring for the final page callback.
$querystring = array(
'eid' => $this->batched_execution_state->eid,
'token' => drupal_get_token('views_data_export/' . $this->batched_execution_state->eid),
'return-url' => NULL,
);
@@ -401,6 +420,9 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
break;
case VIEWS_DATA_EXPORT_FOOTER:
// Update the temporary file size, otherwise we would get a problematic
// "Content-Length: 0" HTTP header, that may break the export download.
$this->outputfile_update_size();
$sandbox['finished'] = 1;
$state->batch_state = VIEWS_DATA_EXPORT_FINISHED;
break;
@@ -418,6 +440,13 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
function execute_final() {
// Should we download the file.
if (!empty($_GET['download'])) {
// Clean up our session, if we need to.
if (isset($_SESSION)) {
unset($_SESSION['views_data_export'][$this->batched_execution_state->eid]);
if (empty($_SESSION['views_data_export'])) {
unset($_SESSION['views_data_export']);
}
}
// This next method will exit.
$this->transfer_file();
}
@@ -526,6 +555,7 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
$query = array(
'download' => 1,
'eid' => $this->batched_execution_state->eid,
'token' => drupal_get_token('views_data_export/' . $this->batched_execution_state->eid),
);
return theme('views_data_export_complete_page', array(
@@ -573,7 +603,10 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
}
// Set the headers.
$this->add_http_headers();
file_transfer($this->outputfile_path(), array());
$headers = array(
'Content-Length' => $this->outputfile_entity()->filesize,
);
file_transfer($this->outputfile_path(), $headers);
}
/**
@@ -666,9 +699,9 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
}
/**
* Get the output file path.
* Get the output file entity.
*/
function outputfile_path() {
public function outputfile_entity() {
if (empty($this->_output_file)) {
if (!empty($this->batched_execution_state->fid)) {
// Return the filename associated with this file.
@@ -678,7 +711,16 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
return NULL;
}
}
return $this->_output_file->uri;
return $this->_output_file;
}
/**
* Get the output file path.
*/
public function outputfile_path() {
if ($file = $this->outputfile_entity()) {
return $file->uri;
}
}
/**
@@ -700,6 +742,11 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
// Save the file into the DB.
$file = $this->file_save_file($path);
// Make sure the file is marked as temporary.
// There is no FILE_STATUS_TEMPORARY constant.
$file->status = 0;
file_save($file);
return $file->fid;
}
@@ -713,6 +760,16 @@ class views_data_export_plugin_display_export extends views_plugin_display_feed
}
}
/**
* Updates the file size in the file entity.
*/
protected function outputfile_update_size() {
if ($file = $this->outputfile_entity()) {
$file->filesize = filesize($file->uri);
file_save($file);
}
}
function abort_export($errors) {
// Just cause the next batch to do the clean-up
if (!is_array($errors)) {

View File

@@ -343,9 +343,20 @@ class views_data_export_plugin_style_export extends views_plugin_style {
if (!empty($view->exposed_input[$handler->options['expose']['identifier']])) {
$identifier = $handler->options['expose']['identifier'];
$option = $view->exposed_input[$identifier];
// The option may be a string or an array, depending on whether the
// widget is a text box/area or a select box.
// The option may be a string or an array or even an array of arrays,
// depending on whether the widget is a text box/area, a select box
// or a date range.
if (is_array($option)) {
// loop over each option
foreach ($option as $key => $item) {
if (!is_array($item)) {
continue;
}
// if its an array implode it first
else {
$option[$key] = implode('--', $item);
}
}
$option = implode('--', $option);
}
$exposed[] = check_plain($identifier) . '_' . check_plain($option);

View File

@@ -40,6 +40,10 @@ class views_data_export_plugin_style_export_csv extends views_data_export_plugin
'default' => ', ',
'translatable' => FALSE,
);
$options['newline_token'] = array(
'default' => 1,
'translatable' => FALSE,
);
$options['header'] = array(
'default' => TRUE,
'translatable' => FALSE,
@@ -99,6 +103,18 @@ class views_data_export_plugin_style_export_csv extends views_data_export_plugin
'#process' => array('ctools_dependent_process'),
'#dependency' => array('edit-style-options-replace-newlines' => array(TRUE)),
);
$form['newline_token'] = array(
'#prefix' => '<div><div id="edit-options-newline-token">',
'#suffix' => '</div></div>',
'#type' => 'radios',
'#default_value' => !empty($this->options['newline_token']) ? $this->options['newline_token'] : '0',
'#title' => t('What to replace?'),
'#options' => array(
t('Replace only Linefeed ("\n")'),
t('Replace Carriage Return plus Linefeed ("\r\n") and single Linefeed ("\n") as well')
),
'#dependency' => array('edit-style-options-replace-newlines' => array(TRUE)),
);
$form['header'] = array(
'#type' => 'checkbox',
'#title' => t('Make first row a list of column headers.'),

View File

@@ -0,0 +1,208 @@
<?php
/**
* Test class for access checks for VDE downloads.
*
* Views Data Export enforces that a previously exported file may only be
* re-downloaded by the user that created the export. We test for that with
* this class.
*/
class ViewsDataExportAccessTest extends ViewsDataExportBaseTest {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Access to temp files',
'description' => 'Check access to created export files.',
'group' => 'Views Data Export',
);
}
/**
* Test that VDE export can only be downloaded by the user that created them.
*/
public function testExportedTempFileAccess() {
$this->admin_user1 = $this->drupalCreateUser();
$this->admin_user2 = $this->drupalCreateUser();
// Run a batched export.
$path = 'vde_test/' . $this->randomName();
list($view, $expected) = $this->getExportView($path);
$display = &$view->display['vde_test']->handler;
// Set this view to be batched.
$display->override_option('use_batch', 'batch');
// Save this view so we can hit the path.
$view->save();
// Ensure that the menu router system is rebuilt on the next page load.
variable_set('menu_rebuild_needed', TRUE);
$this->drupalLogin($this->admin_user1);
// Catpure the session_id as the redirects in the request ditch it.
$session_id = $this->session_id;
$this->assertBatchedExportEqual($path, $expected, 'Batched access export matched expected output.');
// Remove all the test data, so future exports will be different.
db_truncate('views_test')->execute();
$this->resetAll();
// Assert that we can re-download directly when supplying the token.
// We rely on this being the first export in this test class.
// Restore the session_id from above so we can use drupalGetToken.
$this->session_id = $session_id;
$token = $this->drupalGetToken('views_data_export/1');
$this->drupalGet($path, array('query' => array('eid' => 1, 'download' => 1, 'token' => $token)));
$output = $this->drupalGetContent();
$this->assertEqual($this->normaliseString($output), $expected, 'Re-download of export file by original user is possible with session token.');
// Assert that we cannot re-download directly without supplying the token.
// We rely on this being the first export in this test class.
$this->drupalGet($path, array('query' => array('eid' => 1, 'download' => 1)));
$output = $this->drupalGetContent();
$this->assertEqual($this->normaliseString($output), '', 'Re-download of export file by original user is not possible.');
// Assert that someone else can't download our file.
// We rely on this being the first export in this test class.
$this->drupalLogin($this->admin_user2);
$this->drupalGet($path, array('query' => array('eid' => 1, 'download' => 1, 'token' => $token)));
$output = $this->drupalGetContent();
$this->assertEqual($this->normaliseString($output), '', 'Re-download of export file by different user is not possible.');
}
/**
* Overrides DrupalWebTestCase::drupalGetToken() to support the hash salt.
*
* @todo Remove when http://drupal.org/node/1555862 is fixed in core.
*/
protected function drupalGetToken($value = '') {
$private_key = drupal_get_private_key();
return drupal_hmac_base64($value, $this->session_id . $private_key . drupal_get_hash_salt());
}
/**
* Build and return a basic view of the views_test table.
*
* @return view
*/
protected function getBasicExportView() {
views_include('view');
// Create the basic view.
$view = new view();
$view->vid = 'new';
$view->base_table = 'views_test';
// Set up the fields we need.
$display = $view->new_display('default', 'Master', 'default');
$display->override_option('fields', array(
'id' => array(
'id' => 'id',
'table' => 'views_test',
'field' => 'id',
'relationship' => 'none',
),
'name' => array(
'id' => 'name',
'table' => 'views_test',
'field' => 'name',
'relationship' => 'none',
),
'age' => array(
'id' => 'age',
'table' => 'views_test',
'field' => 'age',
'relationship' => 'none',
),
));
// Set up the sort order.
$display->override_option('sorts', array(
'id' => array(
'order' => 'ASC',
'id' => 'id',
'table' => 'views_test',
'field' => 'id',
'relationship' => 'none',
),
));
// Set up the pager.
$display->override_option('pager', array(
'type' => 'none',
'options' => array('offset' => 0),
));
return $view;
}
protected function getStylePluginName() {
return 'views_data_export_txt';
}
protected function getExportView($path = 'vde_test') {
// Create the basic view.
$view = $this->getBasicExportView();
$display = $view->new_display('views_data_export', 'Data export', 'vde_test');
$display->override_option('style_plugin', $this->getStylePluginName());
$display->override_option('path', $path);
$expected = '[ID]
1
[Name]
John
[Age]
25
----------------------------------------
[ID]
2
[Name]
George
[Age]
27
----------------------------------------
[ID]
3
[Name]
Ringo
[Age]
28
----------------------------------------
[ID]
4
[Name]
Paul
[Age]
26
----------------------------------------
[ID]
5
[Name]
Meredith
[Age]
30
----------------------------------------';
return array(&$view, $expected);
}
}

View File

@@ -212,13 +212,13 @@ abstract class ViewsDataExportBaseTest extends ViewsTestCase {
array(
'name' => 'John',
'age' => 25,
'job' => 'Singer',
'job' => "Singer\r\nSongwriter\r\nPianist",
'created' => gmmktime(0, 0, 0, 1, 1, 2000),
),
array(
'name' => 'George',
'age' => 27,
'job' => 'Singer',
'job' => "Singer\nGuitar player\nSitar player",
'created' => gmmktime(0, 0, 0, 1, 2, 2000),
),
array(
@@ -230,7 +230,7 @@ abstract class ViewsDataExportBaseTest extends ViewsTestCase {
array(
'name' => 'Paul',
'age' => 26,
'job' => 'Songwriter',
'job' => "Songwriter\rBass guitarist",
'created' => gmmktime(6, 0, 0, 1, 1, 2000),
),
array(

View File

@@ -208,4 +208,78 @@ class CSVExportViewsDataExportTests extends ViewsDataExportSimpleExportTest {
}
/**
* Test to ensure that all new line characters are replaced in CSV files when requested.
*/
protected function testReplaceNewLines() {
$view = $this->getBasicExportView();
$display = $view->display['default']->handler;
$display->override_option('fields', array(
'id' => array(
'id' => 'id',
'table' => 'views_test',
'field' => 'id',
'relationship' => 'none',
'label' => 'ID',
),
'name' => array(
'id' => 'name',
'table' => 'views_test',
'field' => 'name',
'relationship' => 'none',
),
'age' => array(
'id' => 'age',
'table' => 'views_test',
'field' => 'age',
'relationship' => 'none',
),
'job' => array(
'id' => 'job',
'table' => 'views_test',
'field' => 'job',
'relationship' => 'none',
),
));
$style_options = array(
'replace_newlines' => TRUE,
'newline_replacement' => ';',
'newline_token' => 0,
);
$expected = <<<EOT
"ID","Name","Age","Job"
"1","John","25","Singer\r;Songwriter\r;Pianist"
"2","George","27","Singer;Guitar player;Sitar player"
"3","Ringo","28","Drummer"
"4","Paul","26","Songwriter\rBass guitarist"
"5","Meredith","30","Speaker"
EOT;
$message = 'Linefeed characters are replaced.';
$this->executeAndCompareGivenView($view, $expected, $message, $style_options);
// And now replace all kind of newlines.
$style_options = array(
'replace_newlines' => TRUE,
'newline_replacement' => ';',
'newline_token' => 1,
);
$expected = '"ID","Name","Age","Job"
"1","John","25","Singer;Songwriter;Pianist"
"2","George","27","Singer;Guitar player;Sitar player"
"3","Ringo","28","Drummer"
"4","Paul","26","Songwriter;Bass guitarist"
"5","Meredith","30","Speaker"';
$message = 'All newline characters are replaced.';
$this->executeAndCompareGivenView($view, $expected, $message, $style_options);
}
}

View File

@@ -0,0 +1,187 @@
<?php
/**
* Test class for garbage collection of VDE export data.
*/
class ViewsDataExportGarbageCollectionTest extends ViewsDataExportBaseTest {
protected $profile = 'testing';
public static function getInfo() {
return array(
'name' => 'Garbage collection',
'description' => 'Checks garbage collection of batched exports',
'group' => 'Views Data Export',
);
}
/**
* Test that VDE export can only be downloaded by the user that created them.
*/
public function testExportedGarbageCollection() {
// Run a batched export.
$path = 'vde_test/' . $this->randomName();
list($view, $expected) = $this->getExportView($path);
$display = &$view->display['vde_test']->handler;
// Set this view to be batched.
$display->override_option('use_batch', 'batch');
// Save this view so we can hit the path.
$view->save();
// Ensure that the menu router system is rebuilt on the next page load.
variable_set('menu_rebuild_needed', TRUE);
$exports = $this->getNumberOfStoredExports();
$files = $this->getNumberOfFiles();
$this->assertBatchedExportEqual($path, $expected, 'Batched access export matched expected output.');
// We should have created a new export and file.
$this->assertEqual($this->getNumberOfStoredExports(), $exports + 1, 'A single new batched export was created');
$this->assertEqual($this->getNumberOfFiles(), $files + 1, 'A single new temporary file was created');
$middle_timestamp = time();
sleep(1);
$this->assertBatchedExportEqual($path, $expected, 'Batched access export matched expected output.');
// We should have created a new export and file.
$this->assertEqual($this->getNumberOfStoredExports(), $exports + 2, 'A single new batched export was created');
$this->assertEqual($this->getNumberOfFiles(), $files + 2, 'A single new temporary file was created');
// Garbage collect the first export only.
views_data_export_garbage_collect(REQUEST_TIME - $middle_timestamp);
$this->assertEqual($this->getNumberOfStoredExports(), $exports + 1, 'Garbage collection removed 1 old export');
$this->assertEqual($this->getNumberOfFiles(), $files + 1, 'Garbage collection removed 1 old temporary file');
}
protected function getNumberOfStoredExports() {
return (int) db_select('views_data_export')->countQuery()->execute()->fetchField();
}
protected function getNumberOfFiles() {
return (int) db_select('file_managed')->countQuery()->execute()->fetchField();
}
/**
* Build and return a basic view of the views_test table.
*
* @return view
*/
protected function getBasicExportView() {
views_include('view');
// Create the basic view.
$view = new view();
$view->vid = 'new';
$view->base_table = 'views_test';
// Set up the fields we need.
$display = $view->new_display('default', 'Master', 'default');
$display->override_option('fields', array(
'id' => array(
'id' => 'id',
'table' => 'views_test',
'field' => 'id',
'relationship' => 'none',
),
'name' => array(
'id' => 'name',
'table' => 'views_test',
'field' => 'name',
'relationship' => 'none',
),
'age' => array(
'id' => 'age',
'table' => 'views_test',
'field' => 'age',
'relationship' => 'none',
),
));
// Set up the sort order.
$display->override_option('sorts', array(
'id' => array(
'order' => 'ASC',
'id' => 'id',
'table' => 'views_test',
'field' => 'id',
'relationship' => 'none',
),
));
// Set up the pager.
$display->override_option('pager', array(
'type' => 'none',
'options' => array('offset' => 0),
));
return $view;
}
protected function getStylePluginName() {
return 'views_data_export_txt';
}
protected function getExportView($path = 'vde_test') {
// Create the basic view.
$view = $this->getBasicExportView();
$display = $view->new_display('views_data_export', 'Data export', 'vde_test');
$display->override_option('style_plugin', $this->getStylePluginName());
$display->override_option('path', $path);
$expected = '[ID]
1
[Name]
John
[Age]
25
----------------------------------------
[ID]
2
[Name]
George
[Age]
27
----------------------------------------
[ID]
3
[Name]
Ringo
[Age]
28
----------------------------------------
[ID]
4
[Name]
Paul
[Age]
26
----------------------------------------
[ID]
5
[Name]
Meredith
[Age]
30
----------------------------------------';
return array(&$view, $expected);
}
}

View File

@@ -171,7 +171,12 @@ function template_preprocess_views_data_export_csv_body(&$vars) {
}
}
if (!empty($vars['options']['replace_newlines'])) {
$output = str_replace("\n", $vars['options']['newline_replacement'], $output);
if (!empty($vars['options']['newline_token'])) {
$output = str_replace( array("\r\n", "\r", "\n"), $vars['options']['newline_replacement'], $output);
}
else {
$output = str_replace("\n", $vars['options']['newline_replacement'], $output);
}
}
$vars['themed_rows'][$i][$j] = $wrap . str_replace('"', $replace_value, $output) . $wrap;
}
@@ -254,11 +259,17 @@ function template_preprocess_views_data_export_txt_body(&$vars) {
_views_data_export_body_shared_preprocess($vars);
}
/**
* Implements hook_preprocess_views_data_export_doc_body().
*/
function template_preprocess_views_data_export_doc_body(&$vars) {
// Pass through the generic MS Office preprocess.
template_preprocess_views_data_export_msoffice_body($vars);
}
/**
* Implements hook_preprocess_views_data_export_xls_body().
*/
function template_preprocess_views_data_export_xls_body(&$vars) {
// Pass through the generic MS Office preprocess.
template_preprocess_views_data_export_msoffice_body($vars);
@@ -267,6 +278,25 @@ function template_preprocess_views_data_export_xls_body(&$vars) {
function template_preprocess_views_data_export_msoffice_body(&$vars) {
_views_data_export_header_shared_preprocess($vars);
_views_data_export_body_shared_preprocess($vars);
}
/**
* Implements hook_process_views_data_export_doc_body().
*/
function template_process_views_data_export_doc_body(&$vars) {
// Pass through the generic MS Office process.
template_process_views_data_export_msoffice_body($vars);
}
/**
* Implements hook_process_views_data_export_xls_body().
*/
function template_process_views_data_export_xls_body(&$vars) {
// Pass through the generic MS Office process.
template_process_views_data_export_msoffice_body($vars);
}
function template_process_views_data_export_msoffice_body(&$vars) {
$output = '';
@@ -475,14 +505,18 @@ function _views_data_export_xml_tag_clean($tag) {
function _views_data_export_header_shared_preprocess(&$vars) {
$view = $vars['view'];
$fields = &$view->field;
$fields_info = $view->display_handler->get_option('fields');
$vars['header'] = array();
foreach ($fields as $key => $field) {
if (empty($field->options['exclude'])) {
$vars['header'][$key] = check_plain($field->label());
if (isset($fields_info) && isset($fields_info[$key]['label'])) {
$vars['header'][$key] = check_plain($fields_info[$key]['label']);
}
else {
$vars['header'][$key] = check_plain($field->label());
}
}
}
}
/**

View File

@@ -17,12 +17,12 @@ function views_data_export_drush_command() {
'output_file' => 'The file to write the results to - will be overwritten if it already exists',
),
'options' => array (
'--arguments' => 'Comma separated list of arguments to be passed to the view.',
'--format' => 'csv,doc,txt,xls or xml. These options are ignored if the display_id passed is a "views_data_export" display.',
'--separator' => 'csv only: What character separates the fields (default:,)',
'--trim-whitespace' => 'csv only: Trim whitespace from either side of fields (default:1)',
'--header-row' => 'csv only: Make the first row a row of headers (default:1)',
'--quote-values' => 'csv only: Surround each field in quotes (default:1)',
'arguments' => 'Comma separated list of arguments to be passed to the view.',
'format' => 'csv,doc,txt,xls or xml. These options are ignored if the display_id passed is a "views_data_export" display.',
'separator' => 'csv only: What character separates the fields (default:,)',
'trim-whitespace' => 'csv only: Trim whitespace from either side of fields (default:1)',
'header-row' => 'csv only: Make the first row a row of headers (default:1)',
'quote-values' => 'csv only: Surround each field in quotes (default:1)',
),
'examples' => array (
'drush views-data-export myviewname views_data_export_1 output.csv' => 'Export myviewname:views_data_export_1 and write the output to output.csv in the current directory',
@@ -168,19 +168,19 @@ function drush_views_data_export($view_name, $display_id, $output_file) {
$options['output_file'] = realpath(drush_get_context('DRUSH_OLDCWD', getcwd())) . '/' . $output_file;
}
$arguments = drush_get_option('arguments', '');
$arguments = explode(',', $arguments);
if ($view->display_handler->is_batched()) {
// This is a batched export, and needs to be handled as such.
_drush_views_data_export_override_batch($view_name, $display_id, $options);
$arguments = drush_get_option('arguments', '');
$arguments = explode(',', $arguments);
$view->execute_display($display_id, $arguments);
}
else {
// This export isn't batched.
ob_start();
$view->execute_display($display_id);
$view->execute_display($display_id, $arguments);
// Get the results, and clean the output buffer.
$result = ob_get_contents();
// Clean the buffer.

View File

@@ -14,15 +14,17 @@ files[] = plugins/views_data_export_plugin_style_export_xml.inc
; Tests
files[] = "tests/base.test"
files[] = "tests/access.test"
files[] = "tests/garbagecollection.test"
files[] = "tests/csv_export.test"
files[] = "tests/doc_export.test"
files[] = "tests/txt_export.test"
files[] = "tests/xls_export.test"
files[] = "tests/xml_export.test"
; Information added by Drupal.org packaging script on 2014-08-27
version = "7.x-3.0-beta8"
; Information added by Drupal.org packaging script on 2016-09-20
version = "7.x-3.1"
core = "7.x"
project = "views_data_export"
datestamp = "1409118835"
datestamp = "1474360174"

View File

@@ -30,6 +30,25 @@ function views_data_export_views_api() {
);
}
/**
/**
* Checks whether the passed URI identifies an export file.
*
* @param string $uri
* A file URI.
*
* @return bool
* TRUE if the URI identifies an export file, FALSE otherwise.
*/
function views_data_export_is_export_file($uri) {
foreach (entity_load('file', FALSE, array('uri' => $uri)) as $file) {
// See if this is an export file.
$usages = file_usage_list($file);
return !empty($usages['views_data_export']['eid']);
}
return FALSE;
}
/**
* Implementation of hook_theme().
*/
@@ -114,9 +133,10 @@ function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) {
}
// We do two things to exports we want to garbage collect
// 1. Delete the index table for it, if it is still around
// 2. Delete the row from the exports table
// 3. Delete the view from the object_cache
// 1. Delete the index table for it, if it is still around.
// 2. Delete the files used during the export.
// 3. Delete the row from the exports table.
// 4. Delete the view from the object_cache.
if (count($eids_to_clear)) {
foreach ($eids_to_clear as $eid) {
// 1. Delete index table, if it is still around for some reason
@@ -124,14 +144,19 @@ function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) {
if (db_table_exists($table)) {
db_drop_table($table);
}
// 2. Delete the files used during the export.
foreach (views_data_export_export_list_files($eid) as $file) {
file_delete($file, TRUE);
}
}
// 2. Delete the entries in the exports table.
// 3. Delete the entries in the exports table.
db_delete('views_data_export')
->condition('eid', $eids_to_clear, 'IN')
->execute();
// 3. Clear the cached views
// 4. Clear the cached views
views_data_export_view_clear($eids_to_clear);
}
@@ -139,6 +164,25 @@ function views_data_export_garbage_collect($expires = NULL, $chunk = NULL) {
}
}
/**
* Determines where a file is used.
*
* @param $eid
* The ID of a Views Data Export.
*
* @return array
* An array of loaded files objects used by the specified export.
*/
function views_data_export_export_list_files($eid) {
$result = db_select('file_usage', 'f')
->fields('f', array('fid'))
->condition('id', $eid)
->condition('type', 'eid')
->condition('module', 'views_data_export')
->execute();
return file_load_multiple($result->fetchCol());
}
/**
* Batch API callback.
@@ -268,15 +312,3 @@ function views_data_export_view_clear($export_id) {
->condition('eid', $export_id)
->execute();
}
/**
* Implements hook_file_presave().
*/
function views_data_export_file_presave($file) {
// Ensure temporary files really are temporary.
// @see: https://drupal.org/node/2198399
if (strpos($file->filename, 'views_data_export') === 0) {
// There is no FILE_STATUS_TEMPORARY.
$file->status = 0;
}
}