ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.assFileUpload.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7require_once './Modules/TestQuestionPool/interfaces/interface.ilObjFileHandlingQuestionType.php';
8
21{
22 // hey: prevPassSolutions - support reusing selected files
23 const REUSE_FILES_TBL_POSTVAR = 'reusefiles';
24 const DELETE_FILES_TBL_POSTVAR = 'deletefiles';
25 // hey.
26
27 protected $maxsize;
28
30
32 protected $completion_by_submission = false;
33
47 public function __construct(
48 $title = "",
49 $comment = "",
50 $author = "",
51 $owner = -1,
52 $question = ""
53 ) {
54 parent::__construct($title, $comment, $author, $owner, $question);
55 }
56
62 public function isComplete()
63 {
64 if (
65 strlen($this->title)
66 && ($this->author)
67 && ($this->question)
68 && ($this->getMaximumPoints() >= 0)
69 && is_numeric($this->getMaximumPoints())) {
70 return true;
71 }
72 return false;
73 }
74
78 public function saveToDb($original_id = "")
79 {
82 parent::saveToDb();
83 }
84
86 {
87 global $DIC;
88 $ilDB = $DIC['ilDB'];
89 $ilDB->manipulateF(
90 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
91 array( "integer" ),
92 array( $this->getId() )
93 );
94 $ilDB->manipulateF(
95 "INSERT INTO " . $this->getAdditionalTableName(
96 ) . " (question_fi, maxsize, allowedextensions, compl_by_submission) VALUES (%s, %s, %s, %s)",
97 array( "integer", "float", "text", "integer" ),
98 array(
99 $this->getId(),
100 (strlen($this->getMaxSize())) ? $this->getMaxSize() : null,
101 (strlen($this->getAllowedExtensions())) ? $this->getAllowedExtensions() : null,
103 )
104 );
105 }
106
112 public function loadFromDb($question_id)
113 {
114 global $DIC;
115 $ilDB = $DIC['ilDB'];
116 $result = $ilDB->queryF(
117 "SELECT qpl_questions.*, " . $this->getAdditionalTableName() . ".* FROM qpl_questions LEFT JOIN " . $this->getAdditionalTableName() . " ON " . $this->getAdditionalTableName() . ".question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s",
118 array("integer"),
119 array($question_id)
120 );
121 if ($result->numRows() == 1) {
122 $data = $ilDB->fetchAssoc($result);
123 $this->setId($question_id);
124 $this->setTitle($data["title"]);
125 $this->setComment($data["description"]);
126 $this->setNrOfTries($data['nr_of_tries']);
127 $this->setSuggestedSolution($data["solution_hint"]);
128 $this->setOriginalId($data["original_id"]);
129 $this->setObjId($data["obj_fi"]);
130 $this->setAuthor($data["author"]);
131 $this->setOwner($data["owner"]);
132 $this->setPoints($data["points"]);
133
134 include_once("./Services/RTE/classes/class.ilRTE.php");
135 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
136 $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
137 $this->setMaxSize($data["maxsize"]);
138 $this->setAllowedExtensions($data["allowedextensions"]);
139 $this->setCompletionBySubmission($data['compl_by_submission'] == 1 ? true : false);
140
141 try {
142 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
143 } catch (ilTestQuestionPoolException $e) {
144 }
145 }
146 parent::loadFromDb($question_id);
147 }
148
152 public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
153 {
154 if ($this->id <= 0) {
155 // The question has not been saved. It cannot be duplicated
156 return;
157 }
158 // duplicate the question in database
159 $this_id = $this->getId();
160 $thisObjId = $this->getObjId();
161
162 $clone = $this;
163 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
165 $clone->id = -1;
166
167 if ((int) $testObjId > 0) {
168 $clone->setObjId($testObjId);
169 }
170
171 if ($title) {
172 $clone->setTitle($title);
173 }
174
175 if ($author) {
176 $clone->setAuthor($author);
177 }
178 if ($owner) {
179 $clone->setOwner($owner);
180 }
181
182 if ($for_test) {
183 $clone->saveToDb($original_id);
184 } else {
185 $clone->saveToDb();
186 }
187
188 // copy question page content
189 $clone->copyPageOfQuestion($this_id);
190 // copy XHTML media objects
191 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
192
193 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
194
195 return $clone->id;
196 }
197
201 public function copyObject($target_questionpool_id, $title = "")
202 {
203 if ($this->id <= 0) {
204 // The question has not been saved. It cannot be duplicated
205 return;
206 }
207 // duplicate the question in database
208 $clone = $this;
209 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
211 $clone->id = -1;
212 $source_questionpool_id = $this->getObjId();
213 $clone->setObjId($target_questionpool_id);
214 if ($title) {
215 $clone->setTitle($title);
216 }
217 $clone->saveToDb();
218
219 // copy question page content
220 $clone->copyPageOfQuestion($original_id);
221 // copy XHTML media objects
222 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
223
224 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
225
226 return $clone->id;
227 }
228
229 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
230 {
231 if ($this->id <= 0) {
232 // The question has not been saved. It cannot be duplicated
233 return;
234 }
235
236 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
237
238 $sourceQuestionId = $this->id;
239 $sourceParentId = $this->getObjId();
240
241 // duplicate the question in database
242 $clone = $this;
243 $clone->id = -1;
244
245 $clone->setObjId($targetParentId);
246
247 if ($targetQuestionTitle) {
248 $clone->setTitle($targetQuestionTitle);
249 }
250
251 $clone->saveToDb();
252 // copy question page content
253 $clone->copyPageOfQuestion($sourceQuestionId);
254 // copy XHTML media objects
255 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
256
257 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
258
259 return $clone->id;
260 }
261
267 public function getMaximumPoints()
268 {
269 return $this->getPoints();
270 }
271
282 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
283 {
284 if ($returndetails) {
285 throw new ilTestException('return details not implemented for ' . __METHOD__);
286 }
287
288 if ($this->isCompletionBySubmissionEnabled()) {
289 if (is_null($pass)) {
290 $pass = $this->getSolutionMaxPass($active_id);
291 }
292
293 global $DIC;
294
295 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
296
297 while ($data = $DIC->database()->fetchAssoc($result)) {
298 if ($this->isDummySolutionRecord($data)) {
299 continue;
300 }
301
302 return $this->getPoints();
303 }
304 }
305
306 return 0;
307 }
308
309 protected function calculateReachedPointsForSolution($userSolution)
310 {
311 if ($this->isCompletionBySubmissionEnabled() && count($userSolution)) {
312 return $this->getPoints();
313 }
314
315 return 0;
316 }
317
323 public function checkUpload()
324 {
325 $this->lng->loadLanguageModule("form");
326 // remove trailing '/'
327 $_FILES["upload"]["name"] = rtrim($_FILES["upload"]["name"], '/');
328
329 $filename = $_FILES["upload"]["name"];
330 $filename_arr = pathinfo($_FILES["upload"]["name"]);
331 $suffix = $filename_arr["extension"];
332 $mimetype = $_FILES["upload"]["type"];
333 $size_bytes = $_FILES["upload"]["size"];
334 $temp_name = $_FILES["upload"]["tmp_name"];
335 $error = $_FILES["upload"]["error"];
336
337 if ($size_bytes > $this->getMaxFilesizeInBytes()) {
338 ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
339 return false;
340 }
341
342 // error handling
343 if ($error > 0) {
344 switch ($error) {
345 case UPLOAD_ERR_INI_SIZE:
346 ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
347 return false;
348 break;
349
350 case UPLOAD_ERR_FORM_SIZE:
351 ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
352 return false;
353 break;
354
355 case UPLOAD_ERR_PARTIAL:
356 ilUtil::sendFailure($this->lng->txt("form_msg_file_partially_uploaded"), true);
357 return false;
358 break;
359
360 case UPLOAD_ERR_NO_FILE:
361 ilUtil::sendFailure($this->lng->txt("form_msg_file_no_upload"), true);
362 return false;
363 break;
364
365 case UPLOAD_ERR_NO_TMP_DIR:
366 ilUtil::sendFailure($this->lng->txt("form_msg_file_missing_tmp_dir"), true);
367 return false;
368 break;
369
370 case UPLOAD_ERR_CANT_WRITE:
371 ilUtil::sendFailure($this->lng->txt("form_msg_file_cannot_write_to_disk"), true);
372 return false;
373 break;
374
375 case UPLOAD_ERR_EXTENSION:
376 ilUtil::sendFailure($this->lng->txt("form_msg_file_upload_stopped_ext"), true);
377 return false;
378 break;
379 }
380 }
381
382 // check suffixes
383 if (count($this->getAllowedExtensionsArray())) {
384 if (!strlen($suffix)) {
385 ilUtil::sendFailure($this->lng->txt("form_msg_file_missing_file_ext"), true);
386 return false;
387 }
388
389 if (!in_array(strtolower($suffix), $this->getAllowedExtensionsArray())) {
390 ilUtil::sendFailure($this->lng->txt("form_msg_file_wrong_file_type"), true);
391 return false;
392 }
393 }
394
395 // virus handling
396 if (strlen($temp_name)) {
397 $vir = ilUtil::virusHandling($temp_name, $filename);
398 if ($vir[0] == false) {
399 ilUtil::sendFailure($this->lng->txt("form_msg_file_virus_found") . "<br />" . $vir[1], true);
400 return false;
401 }
402 }
403 return true;
404 }
405
409 public function getFileUploadPath($test_id, $active_id, $question_id = null)
410 {
411 if (is_null($question_id)) {
412 $question_id = $this->getId();
413 }
414 return CLIENT_WEB_DIR . "/assessment/tst_$test_id/$active_id/$question_id/files/";
415 }
416
420 protected function getPreviewFileUploadPath($userId)
421 {
422 return CLIENT_WEB_DIR . "/assessment/qst_preview/$userId/{$this->getId()}/fileuploads/";
423 }
424
430 public function getFileUploadPathWeb($test_id, $active_id, $question_id = null)
431 {
432 if (is_null($question_id)) {
433 $question_id = $this->getId();
434 }
435 include_once "./Services/Utilities/classes/class.ilUtil.php";
436 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/tst_$test_id/$active_id/$question_id/files/";
437 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
438 }
439
443 protected function getPreviewFileUploadPathWeb($userId)
444 {
445 include_once "./Services/Utilities/classes/class.ilUtil.php";
446 $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/qst_preview/$userId/{$this->getId()}/fileuploads/";
447 return str_replace(ilUtil::removeTrailingPathSeparators(ILIAS_ABSOLUTE_PATH), ilUtil::removeTrailingPathSeparators(ILIAS_HTTP_PATH), $webdir);
448 }
449
455 public function getUploadedFiles($active_id, $pass = null, $authorized = true)
456 {
457 global $DIC;
458 $ilDB = $DIC['ilDB'];
459
460 if (is_null($pass)) {
461 $pass = $this->getSolutionMaxPass($active_id);
462 }
463 // fau: testNav - check existing value1 because the intermediate solution will have a dummy entry
464 $result = $ilDB->queryF(
465 "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",
466 array("integer", "integer", "integer", 'integer'),
467 array($active_id, $this->getId(), $pass, (int) $authorized)
468 );
469 // fau.
470 $found = array();
471
472 while ($data = $ilDB->fetchAssoc($result)) {
473 array_push($found, $data);
474 }
475
476 return $found;
477 }
478
479 public function getPreviewFileUploads(ilAssQuestionPreviewSession $previewSession)
480 {
481 return (array) $previewSession->getParticipantsSolution();
482 }
483
489 public function getUploadedFilesForWeb($active_id, $pass)
490 {
491 global $DIC;
492 $ilDB = $DIC['ilDB'];
493
494 $found = $this->getUploadedFiles($active_id, $pass);
495 $result = $ilDB->queryF(
496 "SELECT test_fi FROM tst_active WHERE active_id = %s",
497 array('integer'),
498 array($active_id)
499 );
500 if ($result->numRows() == 1) {
501 $row = $ilDB->fetchAssoc($result);
502 $test_id = $row["test_fi"];
503 $path = $this->getFileUploadPathWeb($test_id, $active_id);
504 foreach ($found as $idx => $data) {
505 $found[$idx]['webpath'] = $path;
506 }
507 }
508 return $found;
509 }
510
516 protected function deleteUploadedFiles($files, $test_id, $active_id, $authorized)
517 {
518 global $DIC;
519 $ilDB = $DIC['ilDB'];
520
521 $pass = null;
522 $active_id = null;
523 foreach ($files as $solution_id) {
524 $result = $ilDB->queryF(
525 "SELECT * FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
526 array("integer", 'integer'),
527 array($solution_id, (int) $authorized)
528 );
529 if ($result->numRows() == 1) {
530 $data = $ilDB->fetchAssoc($result);
531 $pass = $data['pass'];
532 $active_id = $data['active_fi'];
533 @unlink($this->getFileUploadPath($test_id, $active_id) . $data['value1']);
534 }
535 }
536 foreach ($files as $solution_id) {
537 $affectedRows = $ilDB->manipulateF(
538 "DELETE FROM tst_solutions WHERE solution_id = %s AND authorized = %s",
539 array("integer", 'integer'),
540 array($solution_id, $authorized)
541 );
542 }
543 }
544
545 // fau: testNav new function deleteUnusedFiles()
552 protected function deleteUnusedFiles($test_id, $active_id, $pass)
553 {
554 // read all solutions (authorized and intermediate) from all steps
555 $step = $this->getStep();
556 $this->setStep(null);
557 $solutions = array_merge(
558 $this->getSolutionValues($active_id, $pass, true),
559 $this->getSolutionValues($active_id, $pass, false)
560 );
561 $this->setStep($step);
562
563 // get the used files from these solutions
564 $used_files = array();
565 foreach ($solutions as $solution) {
566 $used_files[] = $solution['value1'];
567 }
568
569 // read the existing files for user and pass
570 // delete all files that are not used in the solutions
571 $uploadPath = $this->getFileUploadPath($test_id, $active_id);
572 if (is_dir($uploadPath) && is_readable($uploadPath)) {
573 $iter = new \RegexIterator(new \DirectoryIterator($uploadPath), '/^file_' . $active_id . '_' . $pass . '_(.*)/');
574 foreach ($iter as $file) {
576 if ($file->isFile() && !in_array($file->getFilename(), $used_files)) {
577 unlink($file->getPathname());
578 }
579 }
580 }
581 }
582 // fau.
583
584 protected function deletePreviewFileUploads($userId, $userSolution, $files)
585 {
586 foreach ($files as $name) {
587 if (isset($userSolution[$name])) {
588 unset($userSolution[$name]);
589 @unlink($this->getPreviewFileUploadPath($userId) . $name);
590 }
591 }
592
593 return $userSolution;
594 }
595
601 public function getMaxFilesizeAsString()
602 {
603 $size = $this->getMaxFilesizeInBytes();
604 if ($size < 1024) {
605 $max_filesize = sprintf("%d Bytes", $size);
606 } elseif ($size < 1024 * 1024) {
607 $max_filesize = sprintf("%.1f KB", $size / 1024);
608 } else {
609 $max_filesize = sprintf("%.1f MB", $size / 1024 / 1024);
610 }
611
612 return $max_filesize;
613 }
614
620 public function getMaxFilesizeInBytes()
621 {
622 if (strlen($this->getMaxSize())) {
623 return $this->getMaxSize();
624 } else {
625 // get the value for the maximal uploadable filesize from the php.ini (if available)
626 $umf = get_cfg_var("upload_max_filesize");
627 // get the value for the maximal post data from the php.ini (if available)
628 $pms = get_cfg_var("post_max_size");
629
630 //convert from short-string representation to "real" bytes
631 $multiplier_a = array("K" => 1024, "M" => 1024 * 1024, "G" => 1024 * 1024 * 1024);
632
633 $umf_parts = preg_split("/(\d+)([K|G|M])/", $umf, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
634 $pms_parts = preg_split("/(\d+)([K|G|M])/", $pms, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
635
636 if (count($umf_parts) == 2) {
637 $umf = $umf_parts[0] * $multiplier_a[$umf_parts[1]];
638 }
639 if (count($pms_parts) == 2) {
640 $pms = $pms_parts[0] * $multiplier_a[$pms_parts[1]];
641 }
642
643 // use the smaller one as limit
644 $max_filesize = min($umf, $pms);
645
646 if (!$max_filesize) {
647 $max_filesize = max($umf, $pms);
648 }
649 return $max_filesize;
650 }
651 }
652
653 // hey: prevPassSolutions - refactored method to get intermediate/authorized
654 // as well as upload, delete and previous files working
655 // BASED ON LAST FRED IMPLEMENTATION (@Fred: simply replace and solve unknown calls)
664 public function saveWorkingData($active_id, $pass = null, $authorized = true)
665 {
666 $pass = $this->ensureCurrentTestPass($active_id, $pass);
667 $test_id = $this->lookupTestId($active_id);
668
669 $uploadHandlingRequired = $this->isFileUploadAvailable() && $this->checkUpload();
670
671 $entered_values = false;
672
673 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $uploadHandlingRequired, $test_id, $active_id, $pass, $authorized) {
674 if ($authorized == false) {
675 $this->forceExistingIntermediateSolution($active_id, $pass, true);
676 }
677
678 if ($this->isFileDeletionAction()) {
679 if ($this->isFileDeletionSubmitAvailable()) {
680 foreach ($_POST[self::DELETE_FILES_TBL_POSTVAR] as $solution_id) {
681 $this->removeSolutionRecordById($solution_id);
682 }
683 } else {
684 ilUtil::sendInfo($this->lng->txt('no_checkbox'), true);
685 }
686 } else {
687 if ($this->isFileReuseHandlingRequired()) {
688 foreach ($_POST[self::REUSE_FILES_TBL_POSTVAR] as $solutionId) {
689 $solution = $this->getSolutionRecordById($solutionId);
690
691 $this->saveCurrentSolution(
692 $active_id,
693 $pass,
694 $solution['value1'],
695 $solution['value2'],
696 false,
697 $solution['tstamp']
698 );
699 }
700 }
701
702 if ($uploadHandlingRequired) {
703 if (!@file_exists($this->getFileUploadPath($test_id, $active_id))) {
705 }
706
707 $solutionFileVersioningUploadTS = time();
708 $filename_arr = pathinfo($_FILES["upload"]["name"]);
709 $extension = $filename_arr["extension"];
710 $newfile = "file_" . $active_id . "_" . $pass . "_" . $solutionFileVersioningUploadTS . "." . $extension;
711
712 include_once 'Services/Utilities/classes/class.ilFileUtils.php';
713 $dispoFilename = ilFileUtils::getValidFilename($_FILES['upload']['name']);
714 $newfile = ilFileUtils::getValidFilename($newfile);
715
716 ilUtil::moveUploadedFile($_FILES["upload"]["tmp_name"], $_FILES["upload"]["name"], $this->getFileUploadPath($test_id, $active_id) . $newfile);
717
718 $this->saveCurrentSolution(
719 $active_id,
720 $pass,
721 $newfile,
722 $dispoFilename,
723 false,
724 $solutionFileVersioningUploadTS
725 );
726
727 $entered_values = true;
728 }
729 }
730
731 if ($authorized == true && $this->intermediateSolutionExists($active_id, $pass)) {
732 // remove the dummy record of the intermediate solution
733 $this->deleteDummySolutionRecord($active_id, $pass);
734
735 // delete the authorized solution and make the intermediate solution authorized (keeping timestamps)
736 $this->removeCurrentSolution($active_id, $pass, true);
737 $this->updateCurrentSolutionsAuthorization($active_id, $pass, true, true);
738 }
739
740 $this->deleteUnusedFiles($test_id, $active_id, $pass);
741 });
742
743 if ($entered_values) {
744 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
746 assQuestion::logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
747 }
748 } else {
749 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
751 assQuestion::logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
752 }
753 }
754
755 return true;
756 }
757 // hey.
758
759 // fau: testNav - remove dummy value when intermediate solution is got for test display
766 public function getUserSolutionPreferingIntermediate($active_id, $pass = null)
767 {
768 $solution = $this->getSolutionValues($active_id, $pass, false);
769
770 if (!count($solution)) {
771 $solution = $this->getSolutionValues($active_id, $pass, true);
772 } else {
773 $cleaned = array();
774 foreach ($solution as $row) {
775 if (!empty($row['value1'])) {
776 $cleaned[] = $row;
777 }
778 }
779 $solution = $cleaned;
780 }
781
782 return $solution;
783 }
784 // fau.
785
786
787 // fau: testNav - remove unused files if an intermediate solution is removed
794 public function removeIntermediateSolution($active_id, $pass)
795 {
796 global $DIC;
797 $ilDB = $DIC['ilDB'];
798
799 $result = parent::removeIntermediateSolution($active_id, $pass);
800
801 // get the current test id
802 // hey: prevPassSolutions - exract until you drop :-D
803 $test_id = $this->lookupTestId($active_id);
804 // hey.
805
806 $this->deleteUnusedFiles($test_id, $active_id, $pass);
807
808 return $result;
809 }
810 // fau.
811
812
813 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
814 {
815 $userSolution = $previewSession->getParticipantsSolution();
816
817 if (!is_array($userSolution)) {
818 $userSolution = array();
819 }
820
821 // hey: prevPassSolutions - readability spree - get a chance to understand the code
822 if ($this->isFileDeletionAction()) {
823 // hey.
824 // hey: prevPassSolutions - readability spree - get a chance to understand the code
825 if ($this->isFileDeletionSubmitAvailable()) {
826 // hey.
827 $userSolution = $this->deletePreviewFileUploads($previewSession->getUserId(), $userSolution, $_POST['deletefiles']);
828 } else {
829 ilUtil::sendInfo($this->lng->txt('no_checkbox'), true);
830 }
831 } else {
832 // hey: prevPassSolutions - readability spree - get a chance to understand the code
833 if ($this->isFileUploadAvailable()) {
834 // hey.
835 if ($this->checkUpload()) {
836 if (!@file_exists($this->getPreviewFileUploadPath($previewSession->getUserId()))) {
838 }
839
840 $version = time();
841 $filename_arr = pathinfo($_FILES["upload"]["name"]);
842 $extension = $filename_arr["extension"];
843 $newfile = "file_" . md5($_FILES["upload"]["name"]) . "_" . $version . "." . $extension;
844 ilUtil::moveUploadedFile($_FILES["upload"]["tmp_name"], $_FILES["upload"]["name"], $this->getPreviewFileUploadPath($previewSession->getUserId()) . $newfile);
845
846 $userSolution[$newfile] = array(
847 'solution_id' => $newfile,
848 'value1' => $newfile,
849 'value2' => $_FILES['upload']['name'],
850 'tstamp' => $version,
851 'webpath' => $this->getPreviewFileUploadPathWeb($previewSession->getUserId())
852 );
853 }
854 }
855 }
856
857 $previewSession->setParticipantsSolution($userSolution);
858 }
859
869 protected function handleSubmission($active_id, $pass, $obligationsAnswered, $authorized)
870 {
871 if (!$authorized) {
872 return;
873 }
874
875 if ($this->isCompletionBySubmissionEnabled()) {
876 $maxpoints = assQuestion::_getMaximumPoints($this->getId());
877
878 if ($this->getUploadedFiles($active_id, $pass, $authorized)) {
879 $points = $maxpoints;
880 } else {
881 // fau: testNav - don't set reached points if no file is available
882 return;
883 // fau.
884 }
885
886 assQuestion::_setReachedPoints($active_id, $this->getId(), $points, $maxpoints, $pass, 1, $obligationsAnswered);
887
888 // update learning progress
889 include_once 'Modules/Test/classes/class.ilObjTestAccess.php';
890 include_once 'Services/Tracking/classes/class.ilLPStatusWrapper.php';
892 ilObjTest::_getObjectIDFromActiveID((int) $active_id),
893 ilObjTestAccess::_getParticipantId((int) $active_id)
894 );
895 }
896 }
897
903 public function getQuestionType()
904 {
905 return "assFileUpload";
906 }
907
913 public function getAdditionalTableName()
914 {
915 return "qpl_qst_fileupload";
916 }
917
923 public function getAnswerTableName()
924 {
925 return "";
926 }
927
933 public function deleteAnswers($question_id)
934 {
935 }
936
942 {
943 $text = parent::getRTETextWithMediaObjects();
944 return $text;
945 }
946
950 public function setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
951 {
952 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
953
954 $i = 1;
955 $solutions = $this->getSolutionValues($active_id, $pass);
956 foreach ($solutions as $solution) {
957 $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
958 $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
959 if (strlen($solution["value1"])) {
960 $worksheet->setCell($startrow + $i, 1, $solution["value1"]);
961 $worksheet->setCell($startrow + $i, 2, $solution["value2"]);
962 }
963 $i++;
964 }
965
966 return $startrow + $i + 1;
967 }
968
981 public function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
982 {
983 include_once "./Modules/TestQuestionPool/classes/import/qti12/class.assFileUploadImport.php";
984 $import = new assFileUploadImport($this);
985 $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
986 }
987
994 public function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
995 {
996 include_once "./Modules/TestQuestionPool/classes/export/qti12/class.assFileUploadExport.php";
997 $export = new assFileUploadExport($this);
998 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
999 }
1000
1006 public function getBestSolution($active_id, $pass)
1007 {
1008 $user_solution = array();
1009 return $user_solution;
1010 }
1011
1017 public function getMaxSize()
1018 {
1019 return $this->maxsize;
1020 }
1021
1027 public function setMaxSize($a_value)
1028 {
1029 $this->maxsize = $a_value;
1030 }
1031
1038 {
1039 if (strlen($this->allowedextensions)) {
1040 return array_filter(array_map('trim', explode(",", $this->allowedextensions)));
1041 }
1042 return array();
1043 }
1044
1050 public function getAllowedExtensions()
1051 {
1053 }
1054
1060 public function setAllowedExtensions($a_value)
1061 {
1062 $this->allowedextensions = strtolower(trim($a_value));
1063 }
1064
1068 public function __get($value)
1069 {
1070 switch ($value) {
1071 case "maxsize":
1072 return $this->getMaxSize();
1073 break;
1074 case "allowedextensions":
1075 return $this->getAllowedExtensions();
1076 break;
1077 case 'completion_by_submission':
1078 return $this->isCompletionBySubmissionEnabled();
1079 break;
1080 default:
1081 return parent::__get($value);
1082 break;
1083 }
1084 }
1085
1089 public function __set($key, $value)
1090 {
1091 switch ($key) {
1092 case "maxsize":
1093 $this->setMaxSize($value);
1094 break;
1095 case "allowedextensions":
1096 $this->setAllowedExtensions($value);
1097 break;
1098 case 'completion_by_submission':
1099 $this->setCompletionBySubmission($value);
1100 break;
1101 default:
1102 parent::__set($key, $value);
1103 break;
1104 }
1105 }
1106
1114 public function hasFileUploads($test_id)
1115 {
1116 global $DIC;
1117 $ilDB = $DIC['ilDB'];
1118 $query = "
1119 SELECT tst_solutions.solution_id
1120 FROM tst_solutions, tst_active, qpl_questions
1121 WHERE tst_solutions.active_fi = tst_active.active_id
1122 AND tst_solutions.question_fi = qpl_questions.question_id
1123 AND tst_solutions.question_fi = %s AND tst_active.test_fi = %s";
1124 $result = $ilDB->queryF(
1125 $query,
1126 array("integer", "integer"),
1127 array($this->getId(), $test_id)
1128 );
1129 if ($result->numRows() > 0) {
1130 return true;
1131 } else {
1132 return false;
1133 }
1134 }
1135
1141 public function deliverFileUploadZIPFile($ref_id, $test_id, $test_title)
1142 {
1143 global $DIC;
1144 $ilDB = $DIC['ilDB'];
1145 $lng = $DIC['lng'];
1146
1147 require_once 'Modules/TestQuestionPool/classes/class.ilAssFileUploadUploadsExporter.php';
1148 $exporter = new ilAssFileUploadUploadsExporter($ilDB, $lng);
1149
1150 $exporter->setRefId($ref_id);
1151 $exporter->setTestId($test_id);
1152 $exporter->setTestTitle($test_title);
1153 $exporter->setQuestion($this);
1154
1155 $exporter->build();
1156
1158 $exporter->getFinalZipFilePath(),
1159 $exporter->getDispoZipFileName(),
1160 $exporter->getZipFileMimeType(),
1161 false,
1162 true
1163 );
1164 }
1165
1175 {
1177 }
1178
1188 public function setCompletionBySubmission($bool)
1189 {
1190 $this->completion_by_submission = (bool) $bool;
1191 return $this;
1192 }
1193
1205 public function isAnswered($active_id, $pass = null)
1206 {
1207 $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1208
1209 return $numExistingSolutionRecords > 0;
1210 }
1211
1222 public static function isObligationPossible($questionId)
1223 {
1224 return true;
1225 }
1226
1227 public function isAutosaveable()
1228 {
1229 return false;
1230 }
1231
1232 // fau: testNav - new function getTestQuestionConfig()
1239 // hey: refactored identifiers
1241 // hey.
1242 {
1243 // hey: refactored identifiers
1244 return parent::buildTestPresentationConfig()
1245 // hey.
1246 ->setFormChangeDetectionEnabled(false);
1247 }
1248 // fau.
1249
1250 // hey: prevPassSolutions - additional extractions to get a just chance to understand saveWorkingData()
1254 protected function isFileDeletionAction()
1255 {
1256 require_once 'Modules/TestQuestionPool/classes/questions/class.ilAssFileUploadFileTableDeleteButton.php';
1258 }
1259
1264 {
1265 return $this->isNonEmptyItemListPostSubmission(self::DELETE_FILES_TBL_POSTVAR);
1266 }
1267
1271 protected function isFileReuseSubmitAvailable()
1272 {
1273 return $this->isNonEmptyItemListPostSubmission(self::REUSE_FILES_TBL_POSTVAR);
1274 }
1275
1279 protected function isFileReuseHandlingRequired()
1280 {
1281 if (!$this->getTestPresentationConfig()->isPreviousPassSolutionReuseAllowed()) {
1282 return false;
1283 }
1284
1285 if (!$this->isFileReuseSubmitAvailable()) {
1286 return false;
1287 }
1288
1289 return true;
1290 }
1291
1295 protected function isFileUploadAvailable()
1296 {
1297 if (!isset($_FILES['upload'])) {
1298 return false;
1299 }
1300
1301 if (!isset($_FILES['upload']['tmp_name'])) {
1302 return false;
1303 }
1304
1305 return strlen($_FILES['upload']['tmp_name']) > 0;
1306 }
1307 // hey.
1308}
$result
$size
Definition: RandomTest.php:84
$path
Definition: aliased.php:25
$filename
Definition: buildRTE.php:89
$version
Definition: build.php:27
$_POST["username"]
An exception for terminatinating execution or to throw for unit testing.
Class for file upload question exports.
Class for file upload question imports.
Class for file upload questions.
fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
Creates a question from a QTI file.
__set($key, $value)
Object setter.
isCompletionBySubmissionEnabled()
Checks whether completion by submission is enabled or not.
deleteAnswers($question_id)
Deletes datasets from answers tables.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
setMaxSize($a_value)
Set max file size.
getUserSolutionPreferingIntermediate($active_id, $pass=null)
Get the user solution preferring the intermediate solution.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
hasFileUploads($test_id)
Checks if file uploads exist for a given test and the original id of the question.
deleteUploadedFiles($files, $test_id, $active_id, $authorized)
Delete uploaded files.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getPreviewFileUploadPathWeb($userId)
Returns the filesystem path for file uploads.
getFileUploadPathWeb($test_id, $active_id, $question_id=null)
Returns the file upload path for web accessible files of a question.
deletePreviewFileUploads($userId, $userSolution, $files)
duplicate($for_test=true, $title="", $author="", $owner="", $testObjId=null)
Duplicates an assFileUpload.
saveToDb($original_id="")
Saves a assFileUpload object to a database.
getUploadedFiles($active_id, $pass=null, $authorized=true)
Returns the uploaded files for an active user in a given pass.
copyObject($target_questionpool_id, $title="")
Copies an assFileUpload object.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
removeIntermediateSolution($active_id, $pass)
Remove an intermediate soluton (overridden to remove unused fies)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
calculateReachedPointsForSolution($userSolution)
setExportDetailsXLS($worksheet, $startrow, $active_id, $pass)
{Creates an Excel worksheet for the detailed cumulated results of this question.object}
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...
handleSubmission($active_id, $pass, $obligationsAnswered, $authorized)
This method is called after an user submitted one or more files.
getBestSolution($active_id, $pass)
Returns the best solution for a given pass of a participant.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
getPreviewFileUploadPath($userId)
Returns the filesystem path for file uploads.
isComplete()
Returns true, if the question is complete for use.
getAllowedExtensions()
Get allowed file extensions.
getMaxSize()
Get max file size.
getMaxFilesizeAsString()
Return the maximum allowed file size as string.
setAllowedExtensions($a_value)
Set allowed file extensions.
getAnswerTableName()
Returns the name of the answer table in the database.
isAnswered($active_id, $pass=null)
returns boolean wether the question is answered during test pass or not
setCompletionBySubmission($bool)
Enabled/Disable completion by submission.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assFileUpload constructor
getFileUploadPath($test_id, $active_id, $question_id=null)
Returns the filesystem path for file uploads.
toXML($a_include_header=true, $a_include_binary=true, $a_shuffle=false, $test_output=false, $force_image_references=false)
Returns a QTI xml representation of the question and sets the internal domxml variable with the DOM X...
savePreviewData(ilAssQuestionPreviewSession $previewSession)
loadFromDb($question_id)
Loads a assFileUpload object from a database.
getPreviewFileUploads(ilAssQuestionPreviewSession $previewSession)
__get($value)
Object getter.
getAllowedExtensionsArray()
Get allowed file extensions.
getQuestionType()
Returns the question type of the question.
getUploadedFilesForWeb($active_id, $pass)
Returns the web accessible uploaded files for an active user in a given pass.
getMaxFilesizeInBytes()
Return the maximum allowed file size in bytes.
checkUpload()
Check file upload.
static isObligationPossible($questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
buildTestPresentationConfig()
Get the test question configuration Overridden from parent to disable the form change detection Other...
getAdditionalTableName()
Returns the name of the additional question data table in the database.
Abstract basic class which is to be extended by the concrete assessment question type classes.
isNonEmptyItemListPostSubmission($postSubmissionFieldname)
getCurrentSolutionResultSet($active_id, $pass, $authorized=true)
Get a restulset for the current user solution for a this question by active_id and pass.
getSolutionValues($active_id, $pass=null, $authorized=true)
Loads solutions of a given user from the database an returns it.
static _getOriginalId($question_id)
Returns the original id of a question.
setId($id=-1)
Sets the id of the assQuestion object.
setOriginalId($original_id)
setObjId($obj_id=0)
Set the object id of the container object.
getSolutionMaxPass($active_id)
Returns the maximum pass a users question solution.
setSuggestedSolution($solution_id="", $subquestion_index=0, $is_import=false)
Sets a suggested solution for the question.
static _getMaximumPoints($question_id)
Returns the maximum points, a learner can reach answering the question.
saveQuestionDataToDb($original_id="")
deleteDummySolutionRecord($activeId, $passIndex)
getId()
Gets the id of the assQuestion object.
saveCurrentSolution($active_id, $pass, $value1, $value2, $authorized=true, $tstamp=null)
getObjId()
Get the object id of the container object.
isDummySolutionRecord($solutionRecord)
setTitle($title="")
Sets the title string of the assQuestion object.
lookupTestId($active_id)
getSolutionRecordById($solutionId)
setOwner($owner="")
Sets the creator/owner ID of the assQuestion object.
setEstimatedWorkingTime($hour=0, $min=0, $sec=0)
Sets the estimated working time of a question from given hour, minute and second.
static logAction($logtext="", $active_id="", $question_id="")
Logs an action into the Test&Assessment log.
removeCurrentSolution($active_id, $pass, $authorized=true)
removeSolutionRecordById($solutionId)
static getNumExistingSolutionRecords($activeId, $pass, $questionId)
returns the number of existing solution records for the given test active / pass and given question i...
setAuthor($author="")
Sets the authors name of the assQuestion object.
getPoints()
Returns the maximum available points for the question.
ensureCurrentTestPass($active_id, $pass)
intermediateSolutionExists($active_id, $pass)
getTestPresentationConfig()
Get the test question configuration (initialised once)
forceExistingIntermediateSolution($activeId, $passIndex, $considerDummyRecordCreation)
static _setReachedPoints($active_id, $question_id, $points, $maxpoints, $pass, $manualscoring, $obligationsEnabled)
Sets the points, a learner has reached answering the question Additionally objective results are upda...
updateCurrentSolutionsAuthorization($activeId, $pass, $authorized, $keepTime=false)
setPoints($a_points)
Sets the maximum available points for the question.
setComment($comment="")
Sets the comment string of the assQuestion object.
setNrOfTries($a_nr_of_tries)
setAdditionalContentEditingMode($additinalContentEditingMode)
setter for additional content editing mode for this question
setQuestion($question="")
Sets the question string of the question object.
static getValidFilename($a_filename)
Get valid filename.
static _updateStatus($a_obj_id, $a_usr_id, $a_obj=null, $a_percentage=false, $a_force_raise=false)
Update status.
static _getLogLanguage()
retrieve the log language for assessment logging
static _enabledAssessmentLogging()
check wether assessment logging is enabled or not
static _getParticipantId($active_id)
Get user id for active id.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
static _replaceMediaObjectImageSrc($a_text, $a_direction=0, $nic=IL_INST_ID)
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
Base Exception for all Exceptions relating to Modules/Test.
static sendFailure($a_info="", $a_keep=false)
Send Failure Message to Screen.
static virusHandling($a_file, $a_orig_name="", $a_clean=true)
scan file for viruses and clean files if possible
static deliverFile( $a_file, $a_filename, $a_mime='', $isInline=false, $removeAfterDelivery=false, $a_exit_after=true)
deliver file for download via browser.
static makeDirParents($a_dir)
Create a new directory and all parent directories.
static sendInfo($a_info="", $a_keep=false)
Send Info Message to Screen.
static removeTrailingPathSeparators($path)
$key
Definition: croninfo.php:18
$i
Definition: disco.tpl.php:19
Interface ilObjFileHandlingQuestionType.
Interface ilObjQuestionScoringAdjustable.
$files
Definition: metarefresh.php:49
$row
$query
global $DIC
Definition: saml.php:7
echo;exit;}function LogoutNotification($SessionID){ global $ilDB;$q="SELECT session_id, data FROM usr_session WHERE expires > (\w+)\|/" PREG_SPLIT_NO_EMPTY PREG_SPLIT_DELIM_CAPTURE
global $ilDB
$data
Definition: bench.php:6
$text
Definition: errorreport.php:18