21 require_once
'./Modules/Test/classes/inc.AssessmentConstants.php';
77 $this->file_upload = $DIC[
'upload'];
78 $this->current_cmd = $DIC[
'ilCtrl']->getCmd();
117 $ilDB = $DIC[
'ilDB'];
121 array( $this->
getId() )
125 ) .
" (question_fi, maxsize, allowedextensions, compl_by_submission) VALUES (%s, %s, %s, %s)",
126 array(
"integer",
"float",
"text",
"integer" ),
144 $ilDB = $DIC[
'ilDB'];
145 $result =
$ilDB->queryF(
150 if ($result->numRows() == 1) {
152 $this->
setId($question_id);
154 $this->
setComment((
string) $data[
"description"]);
163 $this->
setMaxSize(($data[
"maxsize"] ?? null) ? (
int) $data[
"maxsize"] : null);
178 parent::loadFromDb($question_id);
186 if ($this->
id <= 0) {
191 $this_id = $this->
getId();
198 if ((
int) $testObjId > 0) {
199 $clone->setObjId($testObjId);
220 $clone->copyPageOfQuestion($this_id);
222 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
224 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
234 if ($this->
getId() <= 0) {
235 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
241 $source_questionpool_id = $this->
getObjId();
242 $clone->setObjId($target_questionpool_id);
253 $clone->onCopy($source_questionpool_id,
$original_id, $clone->getObjId(), $clone->getId());
260 if ($this->
getId() <= 0) {
261 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
265 $sourceParentId = $this->
getObjId();
271 $clone->setObjId($targetParentId);
273 if ($targetQuestionTitle) {
274 $clone->setTitle($targetQuestionTitle);
279 $clone->copyPageOfQuestion($sourceQuestionId);
281 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
283 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
310 if ($returndetails) {
311 throw new ilTestException(
'return details not implemented for ' . __METHOD__);
315 if (is_null($pass)) {
323 while (
$data = $DIC->database()->fetchAssoc($result)) {
338 is_array($userSolution) &&
339 count($userSolution)) {
353 $this->
lng->loadLanguageModule(
"form");
355 $_FILES[
"upload"][
"name"] = rtrim($_FILES[
"upload"][
"name"],
'/');
358 $filename_arr = pathinfo($_FILES[
"upload"][
"name"]);
359 $suffix = $filename_arr[
"extension"] ??
'';
360 $mimetype = $_FILES[
"upload"][
"type"];
361 $size_bytes = $_FILES[
"upload"][
"size"];
362 $temp_name = $_FILES[
"upload"][
"tmp_name"];
363 $error = $_FILES[
"upload"][
"error"];
366 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_size_exceeds"),
true);
373 case UPLOAD_ERR_FORM_SIZE:
374 case UPLOAD_ERR_INI_SIZE:
375 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_size_exceeds"),
true);
379 case UPLOAD_ERR_PARTIAL:
380 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_partially_uploaded"),
true);
384 case UPLOAD_ERR_NO_FILE:
385 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_no_upload"),
true);
389 case UPLOAD_ERR_NO_TMP_DIR:
390 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_missing_tmp_dir"),
true);
394 case UPLOAD_ERR_CANT_WRITE:
395 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_cannot_write_to_disk"),
true);
399 case UPLOAD_ERR_EXTENSION:
400 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_upload_stopped_ext"),
true);
408 if (!strlen($suffix)) {
409 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_missing_file_ext"),
true);
414 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_wrong_file_type"),
true);
420 if (strlen($temp_name)) {
422 if ($vir[0] ==
false) {
423 $this->tpl->setOnScreenMessage(
'failure', $this->
lng->txt(
"form_msg_file_virus_found") .
"<br />" . $vir[1],
true);
435 if (is_null($question_id)) {
436 $question_id = $this->
getId();
438 return CLIENT_WEB_DIR .
"/assessment/tst_$test_id/$active_id/$question_id/files/";
446 return CLIENT_WEB_DIR .
"/assessment/qst_preview/$userId/{$this->getId()}/fileuploads/";
456 if (is_null($question_id)) {
457 $question_id = $this->
getId();
488 $ilDB = $DIC[
'ilDB'];
490 if (is_null($pass)) {
494 $result =
$ilDB->queryF(
495 "SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s AND authorized = %s AND value1 IS NOT NULL ORDER BY tstamp",
496 array(
"integer",
"integer",
"integer",
'integer'),
497 array($active_id, $this->
getId(), $pass, (
int) $authorized)
503 array_push($found,
$data);
526 $ilDB = $DIC[
'ilDB'];
529 $result =
$ilDB->queryF(
530 "SELECT test_fi FROM tst_active WHERE active_id = %s",
534 if ($result->numRows() == 1) {
535 $row =
$ilDB->fetchAssoc($result);
538 foreach ($found as $idx =>
$data) {
539 $found[$idx][
'webpath'] =
$path;
553 $ilDB = $DIC[
'ilDB'];
557 foreach ($files as $solution_id) {
558 $result =
$ilDB->queryF(
559 "SELECT * FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
560 array(
"integer",
'integer'),
561 array($solution_id, (
int) $authorized)
563 if ($result->numRows() == 1) {
565 $pass =
$data[
'pass'];
566 $active_id =
$data[
'active_fi'];
570 foreach ($files as $solution_id) {
571 $affectedRows =
$ilDB->manipulateF(
572 "DELETE FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
573 array(
"integer",
'integer'),
574 array($solution_id, $authorized)
586 protected function deleteUnusedFiles(
$test_id, $active_id, $pass):
void 591 $solutions = array_merge(
598 $used_files = array();
599 foreach ($solutions as $solution) {
600 $used_files[] = $solution[
'value1'];
606 if (is_dir($uploadPath) && is_readable($uploadPath)) {
607 $iter = new \RegexIterator(
new \DirectoryIterator($uploadPath),
'/^file_' . $active_id .
'_' . $pass .
'_(.*)/');
608 foreach ($iter as $file) {
610 if ($file->isFile() && !in_array($file->getFilename(), $used_files)) {
611 unlink($file->getPathname());
620 foreach ($files as
$name) {
621 if (isset($userSolution[$name])) {
622 unset($userSolution[$name]);
627 return $userSolution;
639 $max_filesize = sprintf(
"%d Bytes", $size);
640 } elseif ($size < 1024 * 1024) {
641 $max_filesize = sprintf(
"%.1f KB", $size / 1024);
643 $max_filesize = sprintf(
"%.1f MB", $size / 1024 / 1024);
646 return $max_filesize;
656 $umf = get_cfg_var(
"upload_max_filesize");
658 $pms = get_cfg_var(
"post_max_size");
661 $multiplier_a = array(
"K" => 1024,
"M" => 1024 * 1024,
"G" => 1024 * 1024 * 1024);
663 $umf_parts = preg_split(
"/(\d+)([K|G|M])/", $umf, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
664 $pms_parts = preg_split(
"/(\d+)([K|G|M])/", $pms, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
666 if (count($umf_parts) === 2) {
667 $umf = $umf_parts[0] * $multiplier_a[$umf_parts[1]];
669 if (count($pms_parts) === 2) {
670 $pms = $pms_parts[0] * $multiplier_a[$pms_parts[1]];
674 $max_filesize = min($umf, $pms);
676 if (!$max_filesize) {
677 $max_filesize = max($umf, $pms);
680 return (
int) $max_filesize;
694 $upload_handling_required = $this->current_cmd !==
'submitSolution' 695 && $this->current_cmd !==
'showInstantResponse' 700 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
703 $upload_file_data = [];
705 if ($upload_handling_required) {
710 $upload_file_data [
'solution_file_versioning_upload_ts'] = time();
711 $filename_arr = pathinfo($_FILES[
"upload"][
"name"]);
712 $extension = $filename_arr[
"extension"];
713 $new_file_name =
"file_" . $active_id .
"_" . $pass .
"_" . $upload_file_data [
'solution_file_versioning_upload_ts'] .
"." . $extension;
718 $_FILES[
"upload"][
"tmp_name"],
719 $_FILES[
"upload"][
"name"],
723 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
728 $entered_values =
false;
730 $this->
getProcessLocker()->executeUserSolutionUpdateLockOperation(
function () use (&$entered_values, $upload_handling_required, $upload_file_data,
$test_id, $active_id, $pass, $authorized) {
731 if ($authorized ==
false) {
737 foreach ($_POST[self::DELETE_FILES_TBL_POSTVAR] as $solution_id) {
741 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
745 foreach ($_POST[self::REUSE_FILES_TBL_POSTVAR] as $solutionId) {
759 if ($upload_handling_required) {
765 $upload_file_data[
'new_file_name'],
768 $upload_file_data [
'solution_file_versioning_upload_ts']
771 $entered_values =
true;
784 $this->deleteUnusedFiles(
$test_id, $active_id, $pass);
787 if ($entered_values) {
791 "log_user_entered_values",
793 ), $active_id, $this->
getId());
799 "log_user_not_entered_values",
801 ), $active_id, $this->
getId());
816 if (!count($solution)) {
820 foreach ($solution as $row) {
821 if (!empty($row[
'value1'])) {
825 $solution = $cleaned;
834 parent::removeIntermediateSolution($active_id, $pass);
838 $this->deleteUnusedFiles(
$test_id, $active_id, $pass);
847 if (!is_array($userSolution)) {
848 $userSolution = array();
859 $this->tpl->setOnScreenMessage(
'info', $this->
lng->txt(
'no_checkbox'),
true);
863 $fileUploadAvailable = $this->current_cmd !==
'instantResponse' 866 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
870 if ($fileUploadAvailable) {
878 $filename_arr = pathinfo($_FILES[
"upload"][
"name"]);
879 $extension = $filename_arr[
"extension"];
880 $newfile =
"file_" . md5($_FILES[
"upload"][
"name"]) .
"_" .
$version .
"." . $extension;
883 $_FILES[
"upload"][
"tmp_name"],
884 $_FILES[
"upload"][
"name"],
888 $this->tpl->setOnScreenMessage(
'failure', $e->getMessage(),
true);
893 $userSolution[$newfile] = array(
894 'solution_id' => $newfile,
895 'value1' => $newfile,
896 'value2' => $_FILES[
'upload'][
'name'],
915 protected function handleSubmission($active_id, $pass, $obligationsAnswered, $authorized): void
943 return "assFileUpload";
948 return "qpl_qst_fileupload";
969 $text = parent::getRTETextWithMediaObjects();
978 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
982 foreach ($solutions as $solution) {
983 $worksheet->
setCell($startrow +
$i, 0, $this->
lng->txt(
"result"));
985 if (strlen($solution[
"value1"])) {
986 $worksheet->
setCell($startrow +
$i, 2, $solution[
"value1"]);
987 $worksheet->
setCell($startrow +
$i, 3, $solution[
"value2"]);
992 return $startrow +
$i + 1;
1007 public function fromXML($item,
int $questionpool_id, ?
int $tst_id, &$tst_object,
int &$question_counter, array $import_mapping, array &$solutionhints = []): array
1010 return $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
1013 public function toXML($a_include_header =
true, $a_include_binary =
true, $a_shuffle =
false, $test_output =
false, $force_image_references =
false): string
1016 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
1021 $user_solution = array();
1022 return $user_solution;
1032 $this->maxsize = $a_value;
1037 if (strlen($this->allowedextensions)) {
1038 return array_filter(array_map(
'trim', explode(
",", $this->allowedextensions)));
1055 $this->allowedextensions = strtolower(trim($a_value));
1066 $ilDB = $DIC[
'ilDB'];
1068 SELECT tst_solutions.solution_id 1069 FROM tst_solutions, tst_active, qpl_questions 1070 WHERE tst_solutions.active_fi = tst_active.active_id 1071 AND tst_solutions.question_fi = qpl_questions.question_id 1072 AND tst_solutions.question_fi = %s AND tst_active.test_fi = %s 1073 AND tst_solutions.value1 is not null";
1074 $result =
$ilDB->queryF(
1076 array(
"integer",
"integer"),
1079 if ($result->numRows() > 0) {
1096 $ilDB = $DIC[
'ilDB'];
1103 $exporter->setTestTitle($test_title);
1104 $exporter->setQuestion($this);
1109 $exporter->getFinalZipFilePath(),
1110 $exporter->getDispoZipFileName(),
1111 $exporter->getZipFileMimeType(),
1129 $this->completion_by_submission = (bool) $bool;
1137 return $numExistingSolutionRecords > 0;
1152 return parent::buildTestPresentationConfig()
1189 if (!$this->file_upload->hasUploads()) {
1193 if (!$this->file_upload->hasBeenProcessed()) {
1194 $this->file_upload->process();
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
getPreviewFileUploadPathWeb($userId)
Returns the filesystem path for file uploads.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setFormChangeDetectionEnabled($enableFormChangeDetection)
Set if the detection of form changes is enabled.
ILIAS FileUpload FileUpload $file_upload
setNrOfTries(int $a_nr_of_tries)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstance($identifier)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveWorkingData($active_id, $pass=null, $authorized=true)
public
deliverFileUploadZIPFile($ref_id, $test_id, $test_title)
Generates a ZIP file containing all file uploads for a given test and the original id of the question...
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
setAllowedExtensions($a_value)
Set allowed file extensions.
deleteUploadedFiles($files, $test_id, $active_id, $authorized)
Delete uploaded files.
static _getParticipantId($active_id)
Get user id for active id.
setMaxSize(?int $a_value)
hasFileUploads($test_id)
Checks if file uploads exist for a given test and the original id of the question.
getBestSolution($active_id, $pass)
$completion_by_submission
updateCurrentSolutionsAuthorization(int $activeId, int $pass, bool $authorized, bool $keepTime=false)
Abstract basic class which is to be extended by the concrete assessment question type classes...
fromXML($item, int $questionpool_id, ?int $tst_id, &$tst_object, int &$question_counter, array $import_mapping, array &$solutionhints=[])
Creates a question from a QTI file.
duplicate(bool $for_test=true, string $title="", string $author="", string $owner="", $testObjId=null)
Duplicates an assFileUpload.
static virusHandling(string $a_file, string $a_orig_name='', bool $a_clean=true)
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
getColumnCoord(int $a_col)
Get column "name" from number.
isDummySolutionRecord(array $solutionRecord)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="")
assQuestion constructor
static _getOriginalId(int $question_id)
static getValidFilename(string $a_filename)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getNumExistingSolutionRecords(int $activeId, int $pass, int $questionId)
isComplete()
Returns true, if the question is complete for use.
isAnswered(int $active_id, int $pass)
getParticipantsSolution()
deletePreviewFileUploads($userId, $userSolution, $files)
Class IllegalStateException.
const REUSE_FILES_TBL_POSTVAR
copyObject($target_questionpool_id, $title="")
Copies an assFileUpload object.
getFileUploadPathWeb($test_id, $active_id, $question_id=null)
Returns the file upload path for web accessible files of a question.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
setComment(string $comment="")
isFileReuseHandlingRequired()
Class for file upload questions.
handleSubmission($active_id, $pass, $obligationsAnswered, $authorized)
This method is called after an user submitted one or more files.
float $points
The maximum available points for the question.
getAllowedExtensionsArray()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static removeTrailingPathSeparators(string $path)
setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass)
{}
saveToDb($original_id="")
Saves a assFileUpload object to a database.
setParticipantsSolution($participantSolution)
static deliverFileLegacy(string $a_file, ?string $a_filename=null, ?string $a_mime=null, ?bool $isInline=false, ?bool $removeAfterDelivery=false, ?bool $a_exit_after=true)
deleteDummySolutionRecord(int $activeId, int $passIndex)
lookupTestId(int $active_id)
Move to ilObjTest or similar
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
static _enabledAssessmentLogging()
ensureCurrentTestPass(int $active_id, int $pass)
const DELETE_FILES_TBL_POSTVAR
getUserSolutionPreferingIntermediate($active_id, $pass=null)
static logAction(string $logtext, int $active_id, int $question_id)
removeSolutionRecordById(int $solutionId)
getMaxFilesizeAsString()
Return the maximum allowed file size as string.
checkUpload()
Check file upload.
calculateReachedPointsForSolution($userSolution)
intermediateSolutionExists(int $active_id, int $pass)
getPreviewFileUploads(ilAssQuestionPreviewSession $previewSession)
static _setReachedPoints(int $active_id, int $question_id, float $points, float $maxpoints, int $pass, bool $manualscoring, bool $obligationsEnabled)
Sets the points, a learner has reached answering the question Additionally objective results are upda...
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
removeIntermediateSolution(int $active_id, int $pass)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
string $question
The question text.
static isObligationPossible(int $questionId)
isNonEmptyItemListPostSubmission(string $postSubmissionFieldname)
getUploadedFilesForWeb($active_id, $pass)
Returns the web accessible uploaded files for an active user in a given pass.
int $test_id
The database id of a test in which the question is contained.
const HAS_SPECIFIC_FEEDBACK
buildTestPresentationConfig()
static _getMaximumPoints(int $question_id)
Returns the maximum points, a learner can reach answering the question.
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
saveQuestionDataToDb(int $original_id=-1)
getPreviewFileUploadPath($userId)
Returns the filesystem path for file uploads.
getSolutionMaxPass(int $active_id)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
getFileUploadPath($test_id, $active_id, $question_id=null)
Returns the filesystem path for file uploads.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
__construct(Container $dic, ilPlugin $plugin)
setOriginalId(?int $original_id)
getTestPresentationConfig()
setTitle(string $title="")
setLifecycle(ilAssQuestionLifecycle $lifecycle)
loadFromDb($question_id)
Loads a assFileUpload object from a database.
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
getUploadedFiles($active_id, $pass=null, $authorized=true)
Returns the uploaded files for an active user in a given pass.
isFileDeletionSubmitAvailable()
forceExistingIntermediateSolution(int $activeId, int $passIndex, bool $considerDummyRecordCreation)
setCompletionBySubmission($bool)
Enabled/Disable completion by submission.
setAuthor(string $author="")
getSolutionRecordById(int $solutionId)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
static getDraftInstance()
deleteAnswers($question_id)
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
isCompletionBySubmissionEnabled()
setQuestion(string $question="")
isFileReuseSubmitAvailable()