Skip to content

Commit

Permalink
Fixed issue #16834: When importing a theme bigger in size than the al…
Browse files Browse the repository at this point in the history
…lowed PHP.ini settings, there is no proper description of the error (#1861)

Co-authored-by: encuestabizdevgit <devgit@encuesta.biz>
  • Loading branch information
2 people authored and olleharstedt committed May 20, 2021
1 parent ab5365b commit 6e0fb28
Show file tree
Hide file tree
Showing 7 changed files with 147 additions and 58 deletions.
13 changes: 6 additions & 7 deletions application/controllers/QuestionAdministrationController.php
Expand Up @@ -1073,15 +1073,14 @@ public function actionImport()
$aData['display']['menu_bars']['gid_action'] = 'viewgroup';

$sFullFilepath = App()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(20);
$sExtension = pathinfo($_FILES['the_file']['name'], PATHINFO_EXTENSION);
$fatalerror = '';

// Check file size and redirect on error
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError('the_file', \Yii::app()->createUrl('questionAdministration/importView', array('surveyid' => $iSurveyID)));

if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) {
$fatalerror = sprintf(
gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."),
getMaximumFileUploadSize() / 1024 / 1024
) . '<br>';
} elseif (!@move_uploaded_file($_FILES['the_file']['tmp_name'], $sFullFilepath)) {
$sExtension = pathinfo($_FILES['the_file']['name'], PATHINFO_EXTENSION);
if (!@move_uploaded_file($_FILES['the_file']['tmp_name'], $sFullFilepath)) {
$fatalerror = gT(
"An error occurred uploading your file."
. " This may be caused by incorrect permissions for the application /tmp folder."
Expand Down
29 changes: 7 additions & 22 deletions application/controllers/SurveyAdministrationController.php
Expand Up @@ -1271,6 +1271,13 @@ public function actionApplythemeoptions($iSurveyID = 0)
*/
public function actionUploadimagefile()
{
$debug = [$_FILES];
// Check file size and render JSON on error.
// This is done before checking the survey permissions because, if the max POST size was exceeded,
// there is no Survey ID to check for permissions, so the error could be misleading.
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->renderJsonOnError('file', $debug);

$iSurveyID = Yii::app()->request->getPost('surveyid');
$success = false;
$debug = [];
Expand All @@ -1288,28 +1295,6 @@ public function actionUploadimagefile()
false
);
}
$debug[] = $_FILES;
if (empty($_FILES)) {
$uploadresult = gT("No file was uploaded.");
return $this->renderPartial(
'/admin/super/_renderJson',
array('data' => ['success' => $success, 'message' => $uploadresult, 'debug' => $debug]),
false,
false
);
}
if ($_FILES['file']['error'] == 1 || $_FILES['file']['error'] == 2) {
$uploadresult = sprintf(
gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."),
getMaximumFileUploadSize() / 1024 / 1024
);
return $this->renderPartial(
'/admin/super/_renderJson',
array('data' => ['success' => $success, 'message' => $uploadresult, 'debug' => $debug]),
false,
false
);
}
$checkImage = LSYii_ImageValidator::validateImage($_FILES["file"]);
if ($checkImage['check'] === false) {
return $this->renderPartial(
Expand Down
9 changes: 4 additions & 5 deletions application/controllers/admin/labels.php
Expand Up @@ -128,18 +128,17 @@ public function import()
$action = returnGlobal('action');
$aViewUrls = array();

// Check file size and redirect on error
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError('the_file', \Yii::app()->createUrl("/admin/labels/sa/newlabelset"));

if ($action == 'importlabels') {
Yii::app()->loadHelper('admin/import');

$sFullFilepath = Yii::app()->getConfig('tempdir') . DIRECTORY_SEPARATOR . randomChars(20);
$aPathInfo = pathinfo($_FILES['the_file']['name']);
$sExtension = !empty($aPathInfo['extension']) ? $aPathInfo['extension'] : '';

if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) {
Yii::app()->setFlashMessage(sprintf(gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."), getMaximumFileUploadSize() / 1024 / 1024), 'error');
$this->getController()->redirect(App()->createUrl("/admin/labels/sa/newlabelset"));
}

if (!@move_uploaded_file($_FILES['the_file']['tmp_name'], $sFullFilepath)) {
Yii::app()->setFlashMessage(gT("An error occurred uploading your file. This may be caused by incorrect permissions for the application /tmp folder."), 'error');
$this->getController()->redirect(App()->createUrl("/admin/labels/sa/newlabelset"));
Expand Down
10 changes: 5 additions & 5 deletions application/controllers/admin/participantsaction.php
Expand Up @@ -780,6 +780,10 @@ public function attributeMapCSV()
{
$this->checkPermission('import');

// Check file size and redirect on error
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError('the_file', array('admin/participants/sa/importCSV'));

if ($_FILES['the_file']['name'] == '') {
Yii::app()->setFlashMessage(gT('Please select a file to import!'), 'error');
Yii::app()->getController()->redirect(array('admin/participants/sa/importCSV'));
Expand All @@ -789,11 +793,7 @@ public function attributeMapCSV()
$aPathinfo = pathinfo($_FILES['the_file']['name']);
$sExtension = $aPathinfo['extension'];
$bMoveFileResult = false;
if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) {
Yii::app()->setFlashMessage(sprintf(gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."), getMaximumFileUploadSize() / 1024 / 1024), 'error');
Yii::app()->getController()->redirect(array('admin/participants/sa/importCSV'));
Yii::app()->end();
} elseif (strtolower($sExtension) == 'csv') {
if (strtolower($sExtension) == 'csv') {
$bMoveFileResult = @move_uploaded_file($_FILES['the_file']['tmp_name'], $sFilePath);
$filterblankemails = Yii::app()->request->getPost('filterbea');
} else {
Expand Down
35 changes: 19 additions & 16 deletions application/controllers/admin/themes.php
Expand Up @@ -223,8 +223,9 @@ protected function uploadTemplateImageFile(string $sTemplateName)

$debug[] = $_FILES;

// Redirect back at file size error.
$this->checkFileSizeError('file');
// Return json at file size error.
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->renderJsonOnError('file', $debug);

$checkImageContent = LSYii_ImageValidator::validateImage($_FILES["file"]);
if ($checkImageContent['check'] === false) {
Expand Down Expand Up @@ -437,12 +438,22 @@ protected function uploadTemplate()
*/
public function uploadfile()
{
$editfile = App()->request->getPost('editfile');
$templatename = returnGlobal('templatename');
$screenname = returnGlobal('screenname');
if (empty($screenname)) {
$screenname = 'welcome';
}

$redirectUrl = array('admin/themes', 'sa' => 'view', 'editfile' => $editfile, 'screenname' => $screenname, 'templatename' => $templatename);

if (Permission::model()->hasGlobalPermission('templates', 'import')) {
// Check file size and redirect on error
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError('upload_file', $redirectUrl);

$action = returnGlobal('action');
$editfile = App()->request->getPost('editfile');
$templatename = returnGlobal('templatename');
$oEditedTemplate = Template::getInstance($templatename);
$screenname = returnGlobal('screenname');
$allowedthemeuploads = Yii::app()->getConfig('allowedthemeuploads') . ',' . Yii::app()->getConfig('allowedthemeimageformats');
$filename = sanitize_filename($_FILES['upload_file']['name'], false, false, false); // Don't force lowercase or alphanumeric
$dirfilepath = $oEditedTemplate->filesPath;
Expand Down Expand Up @@ -482,7 +493,7 @@ public function uploadfile()
} else {
Yii::app()->setFlashMessage(gT("We are sorry but you don't have permissions to do this."), 'error');
}
$this->getController()->redirect(array('admin/themes', 'sa' => 'view', 'editfile' => $editfile, 'screenname' => $screenname, 'templatename' => $templatename));
$this->getController()->redirect($redirectUrl);
}


Expand Down Expand Up @@ -1313,16 +1324,8 @@ protected function checkDemoMode()
*/
protected function checkFileSizeError($uploadName = 'the_file')
{
if ($_FILES[$uploadName]['error'] == 1 || $_FILES[$uploadName]['error'] == 2) {
Yii::app()->setFlashMessage(
sprintf(
gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."),
getMaximumFileUploadSize() / 1024 / 1024
),
'error'
);
$this->getController()->redirect(array("admin/themes/sa/upload"));
}
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError($uploadName, array("admin/themes/sa/upload"));
}

/**
Expand Down
8 changes: 5 additions & 3 deletions application/controllers/admin/tokens.php
Expand Up @@ -1907,12 +1907,14 @@ public function import($iSurveyId)
$aModelErrorList = array();
$aFirstLine = array();

// Check file size and redirect on error
$uploadValidator = new LimeSurvey\Models\Services\UploadValidator();
$uploadValidator->redirectOnError('the_file', \Yii::app()->createUrl('admin/tokens', array('sa' => 'import', 'surveyid' => $iSurveyId)));

$oFile = CUploadedFile::getInstanceByName("the_file");
$sPath = Yii::app()->getConfig('tempdir');
$sFileName = $sPath . '/' . randomChars(20);
if ($_FILES['the_file']['error'] == 1 || $_FILES['the_file']['error'] == 2) {
Yii::app()->setFlashMessage(sprintf(gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."), getMaximumFileUploadSize() / 1024 / 1024), 'error');
} elseif (strtolower($oFile->getExtensionName()) != 'csv') {
if (strtolower($oFile->getExtensionName()) != 'csv') {
Yii::app()->setFlashMessage(gT("Only CSV files are allowed."), 'error');
} elseif (!@$oFile->saveAs($sFileName)) {
Yii::app()->setFlashMessage(sprintf(gT("Upload file not found. Check your permissions and path (%s) for the upload directory"), $sPath), 'error');
Expand Down
101 changes: 101 additions & 0 deletions application/models/services/UploadValidator.php
@@ -0,0 +1,101 @@
<?php

namespace LimeSurvey\Models\Services;

class UploadValidator
{

/** @var array<string,mixed> HTTP POST variables*/
private $post;

/** @var array<string,mixed> HTTP File Upload variables*/
private $files;

/**
* UploadValidator constructor.
*
* @param array<string,mixed>|null $post HTTP POST variables. If null, $_POST is used.
* @param array<string,mixed>|null $post HTTP File Upload variables. If null, $_FILES is used.
*/
public function __construct($post = null, $files = null)
{
$this->post = is_null($post) ? $_POST : $post;
$this->files = is_null($files) ? $_FILES : $files;
}

/**
* Check uploaded file size
*
* @param string $fileName the name of the posted file
* @param mixed $customMaxSize maximum file upload size
*
* @return string|null the error message or null if all checks are ok
*/
public function getError($fileName, $customMaxSize = null)
{
if (is_null($customMaxSize)) {
$maximumSize = getMaximumFileUploadSize();
} else {
$maximumSize = min((int) $customMaxSize, getMaximumFileUploadSize());
}

// When 'post_max_size' is exceeded $_POST and $_FILES are empty.
// There is no way to confirm if the superglobals are empty because 'post_max_size' was
// exceeded, or because nothing was posted.
if (empty($this->post) && empty($this->files)) {
return sprintf(
gT("No file was uploaded or the request exceeded %01.2f MB."),
convertPHPSizeToBytes(ini_get('post_max_size')) / 1024 / 1024
);
}

if (!isset($this->files[$fileName])) {
return gT("File not found.");
}

$fileSize = $this->files[$fileName]['size'];

if ($fileSize > $maximumSize || $this->files[$fileName]['error'] == 1 || $this->files[$fileName]['error'] == 2) {
return sprintf(
gT("Sorry, this file is too large. Only files up to %01.2f MB are allowed."),
$maximumSize / 1024 / 1024
);
}
}

/**
* Check uploaded file size. Redirects to the specified URL on failure.
*
* @param string $fileName the name of the posted file
* @param mixed $redirectUrl the URL to redirect on failure
* @param mixed $customMaxSize maximum file upload size
*/
public function redirectOnError($fileName, $redirectUrl, $customMaxSize = null)
{
$error = $this->getError($fileName, $customMaxSize);
if (!is_null($error)) {
\Yii::app()->setFlashMessage($error, 'error');
\Yii::app()->getController()->redirect($redirectUrl);
}
}

/**
* Check uploaded file size. Renders JSON on failure.
*
* @param string $fileName the name of the posted file
* @param array $debugInfo the URL to redirect on failure
* @param mixed $customMaxSize maximum file upload size
*/
public function renderJsonOnError($fileName, $debugInfo = [], $customMaxSize = null)
{
$error = $this->getError($fileName, $customMaxSize);
if (!is_null($error)) {
return \Yii::app()->getController()->renderPartial(
'/admin/super/_renderJson',
array('data' => ['success' => 'error', 'message' => $error, 'debug' => $debugInfo]),
false,
false
);
}
}
}

0 comments on commit 6e0fb28

Please sign in to comment.