webform_submission_export_import.module in Webform 6.x
Same filename and directory in other branches
Provides the ability to export and import submissions.
File
modules/webform_submission_export_import/webform_submission_export_import.moduleView source
<?php
/**
* @file
* Provides the ability to export and import submissions.
*/
use Drupal\Component\Utility\Environment;
use Drupal\Core\File\FileSystemInterface;
use Drupal\file\Entity\File;
/**
* Implements hook_webform_help_info().
*/
function webform_submission_export_import_webform_help_info() {
$help = [];
$help['webform_submission_export_import'] = [
'group' => 'forms',
'title' => t('Upload'),
'content' => t('The <strong>Upload</strong> page allows a CSV (comma separated values) file or URL to be uploaded, converted, and imported into webform submissions.'),
'video_id' => 'import',
'routes' => [
// @see /admin/structure/webform/manage/{webform}/results/upload
'entity.webform_submission_export_import.results_import',
// @see /node/{node}/webform/results/upload
'entity.node.webform_submission_export_import.results_import',
],
];
return $help;
}
/**
* Implements hook_local_tasks_alter().
*/
function webform_submission_export_import_local_tasks_alter(&$local_tasks) {
// Remove webform node results import if the webform_node.module
// is not installed.
if (!\Drupal::moduleHandler()
->moduleExists('webform_node')) {
unset($local_tasks['entity.node.webform_submission_export_import.results_import']);
}
}
/******************************************************************************/
// The below code is copy of _file_save_upload_single() which allows imported
// files to be securely created.
/******************************************************************************/
/**
* Saves a file upload to a new location.
*
* @param \SplFileInfo $file_info
* The file upload to save.
* @param string $form_field_name
* A string that is the associative array key of the upload form element in
* the form array.
* @param array $validators
* (optional) An associative array of callback functions used to validate the
* file.
* @param bool $destination
* (optional) A string containing the URI that the file should be copied to.
* @param int $replace
* (optional) The replace behavior when the destination file already exists.
*
* @return \Drupal\file\FileInterface|false
* The created file entity or FALSE if the uploaded file not saved.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*
* @internal
* This method should only be called from file_save_upload(). Use that method
* instead.
*
* @see file_save_upload()
* @see file_save_upload_single()
*/
function _webform_submission_export_import_file_save_upload_single(\SplFileInfo $file_info, $form_field_name, array $validators = [], $destination = FALSE, $replace = FileSystemInterface::EXISTS_RENAME) {
/** @var \Drupal\Core\File\FileSystemInterface $file_system */
$file_system = \Drupal::service('file_system');
$current_user = \Drupal::currentUser();
/** @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager */
$stream_wrapper_manager = \Drupal::service('stream_wrapper_manager');
// Check for file upload errors and return FALSE for this file if a lower
// level system error occurred. For a complete list of errors:
// See http://php.net/manual/features.file-upload.errors.php.
switch ($file_info
->getError()) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
\Drupal::messenger()
->addError(t('The file %file could not be saved because it exceeds %maxsize, the maximum allowed size for uploads.', [
'%file' => $file_info
->getFilename(),
'%maxsize' => format_size(Environment::getUploadMaxSize()),
]));
return FALSE;
case UPLOAD_ERR_PARTIAL:
case UPLOAD_ERR_NO_FILE:
\Drupal::messenger()
->addError(t('The file %file could not be saved because the upload did not complete.', [
'%file' => $file_info
->getFilename(),
]));
return FALSE;
case UPLOAD_ERR_OK:
/************************************************************************/
// DO NOT USE IF UPLOADED FILE.
/************************************************************************/
/*
// Final check that this is a valid upload, if it isn't, use the
// default error handler.
if (is_uploaded_file($file_info->getRealPath())) {
break;
}
*/
break;
default:
// Unknown error
\Drupal::messenger()
->addError(t('The file %file could not be saved. An unknown error has occurred.', [
'%file' => $file_info
->getFilename(),
]));
return FALSE;
}
// Begin building file entity.
$values = [
'uid' => $current_user
->id(),
'status' => 0,
'filename' => $file_info
->getClientOriginalName(),
'uri' => $file_info
->getRealPath(),
'filesize' => $file_info
->getSize(),
];
$values['filemime'] = \Drupal::service('file.mime_type.guesser')
->guess($values['filename']);
$file = File::create($values);
$extensions = '';
if (isset($validators['file_validate_extensions'])) {
if (isset($validators['file_validate_extensions'][0])) {
// Build the list of non-munged extensions if the caller provided them.
$extensions = $validators['file_validate_extensions'][0];
}
else {
// If 'file_validate_extensions' is set and the list is empty then the
// caller wants to allow any extension. In this case we have to remove the
// validator or else it will reject all extensions.
unset($validators['file_validate_extensions']);
}
}
else {
// No validator was provided, so add one using the default list.
// Build a default non-munged safe list for file_munge_filename().
$extensions = 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp';
$validators['file_validate_extensions'] = [];
$validators['file_validate_extensions'][0] = $extensions;
}
if (!empty($extensions)) {
// Munge the filename to protect against possible malicious extension
// hiding within an unknown file type (ie: filename.html.foo).
$file
->setFilename(file_munge_filename($file
->getFilename(), $extensions));
}
// Rename potentially executable files, to help prevent exploits (i.e. will
// rename filename.php.foo and filename.php to filename.php.foo.txt and
// filename.php.txt, respectively). Don't rename if 'allow_insecure_uploads'
// evaluates to TRUE.
if (!\Drupal::config('system.file')
->get('allow_insecure_uploads') && preg_match(FILE_INSECURE_EXTENSION_REGEX, $file
->getFilename()) && substr($file
->getFilename(), -4) !== '.txt') {
$file
->setMimeType('text/plain');
// The destination filename will also later be used to create the URI.
$file
->setFilename($file
->getFilename() . '.txt');
// The .txt extension may not be in the allowed list of extensions. We have
// to add it here or else the file upload will fail.
if (!empty($extensions)) {
$validators['file_validate_extensions'][0] .= ' txt';
\Drupal::messenger()
->addStatus(t('For security reasons, your upload has been renamed to %filename.', [
'%filename' => $file
->getFilename(),
]));
}
}
// If the destination is not provided, use the temporary directory.
if (empty($destination)) {
$destination = 'temporary://';
}
// Assert that the destination contains a valid stream.
$destination_scheme = $stream_wrapper_manager
->getScheme($destination);
if (!$stream_wrapper_manager
->isValidScheme($destination_scheme)) {
\Drupal::messenger()
->addError(t('The file could not be uploaded because the destination %destination is invalid.', [
'%destination' => $destination,
]));
return FALSE;
}
$file->source = $form_field_name;
// A file URI may already have a trailing slash or look like "public://".
if (substr($destination, -1) !== '/') {
$destination .= '/';
}
$file->destination = \Drupal::service('file_system')
->getDestinationFilename($destination . $file
->getFilename(), $replace);
// If \Drupal::service('file_system')->getDestinationFilename() returns FALSE then $replace === FileSystemInterface::EXISTS_ERROR and
// there's an existing file so we need to bail.
if ($file->destination === FALSE) {
\Drupal::messenger()
->addError(t('The file %source could not be uploaded because a file by that name already exists in the destination %directory.', [
'%source' => $form_field_name,
'%directory' => $destination,
]));
return FALSE;
}
// Add in our check of the file name length.
$validators['file_validate_name_length'] = [];
// Call the validation functions specified by this function's caller.
$errors = file_validate($file, $validators);
// Check for errors.
if (!empty($errors)) {
$message = [
'error' => [
'#markup' => t('The specified file %name could not be uploaded.', [
'%name' => $file
->getFilename(),
]),
],
'item_list' => [
'#theme' => 'item_list',
'#items' => $errors,
],
];
// @todo Add support for render arrays in
// \Drupal\Core\Messenger\MessengerInterface::addMessage()?
// @see https://www.drupal.org/node/2505497.
\Drupal::messenger()
->addError(\Drupal::service('renderer')
->renderPlain($message));
return FALSE;
}
$file
->setFileUri($file->destination);
/************************************************************************/
// DO NOT USE MOVE UPLOADED FILE.
/************************************************************************/
// if (!drupal_move_uploaded_file($file_info->getRealPath(), $file->getFileUri())) {
if (!\Drupal::service('file_system')
->move($file_info
->getRealPath(), $file
->getFileUri(), $replace)) {
\Drupal::messenger()
->addError(t('File upload error. Could not move uploaded file.'));
\Drupal::logger('file')
->notice('Upload error. Could not move uploaded file %file to destination %destination.', [
'%file' => $file
->getFilename(),
'%destination' => $file
->getFileUri(),
]);
return FALSE;
}
// Set the permissions on the new file.
$file_system
->chmod($file
->getFileUri());
// If we are replacing an existing file re-use its database record.
// @todo Do not create a new entity in order to update it.
// @see https://www.drupal.org/node/2241865.
if ($replace === FileSystemInterface::EXISTS_REPLACE) {
$existing_files = \Drupal::entityTypeManager()
->getStorage('file')
->loadByProperties([
'uri' => $file
->getFileUri(),
]);
if (count($existing_files)) {
$existing = reset($existing_files);
$file->fid = $existing
->id();
$file
->setOriginalId($existing
->id());
}
}
// If we made it this far it's safe to record this file in the database.
$file
->save();
// Allow an anonymous user who creates a non-public file to see it. See
// \Drupal\file\FileAccessControlHandler::checkAccess().
if ($current_user
->isAnonymous() && $destination_scheme !== 'public') {
$session = \Drupal::request()
->getSession();
$allowed_temp_files = $session
->get('anonymous_allowed_file_ids', []);
$allowed_temp_files[$file
->id()] = $file
->id();
$session
->set('anonymous_allowed_file_ids', $allowed_temp_files);
}
return $file;
}
Functions
Name![]() |
Description |
---|---|
webform_submission_export_import_local_tasks_alter | Implements hook_local_tasks_alter(). |
webform_submission_export_import_webform_help_info | Implements hook_webform_help_info(). |
_webform_submission_export_import_file_save_upload_single | Saves a file upload to a new location. |