security updates of unpatched modules
This commit is contained in:
@@ -1 +0,0 @@
|
||||
.DS_Store
|
@@ -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)) {
|
||||
|
@@ -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);
|
||||
|
@@ -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.'),
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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(
|
||||
|
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -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.
|
||||
|
@@ -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"
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user