ILIAS  Release_5_0_x_branch Revision 61816
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 
4 require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
5 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
6 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
7 require_once './Modules/TestQuestionPool/interfaces/interface.ilObjFileHandlingQuestionType.php';
8 
21 {
22  protected $maxsize;
23 
24  protected $allowedextensions;
25 
27  protected $completion_by_submission = false;
28 
42  function __construct(
43  $title = "",
44  $comment = "",
45  $author = "",
46  $owner = -1,
47  $question = ""
48  )
49  {
51  }
52 
58  public function isComplete()
59  {
60  if (
61  strlen($this->title)
62  && ($this->author)
63  && ($this->question)
64  && ($this->getMaximumPoints() >= 0)
65  && is_numeric($this->getMaximumPoints()))
66  {
67  return true;
68  }
69  return false;
70  }
71 
75  public function saveToDb($original_id = "")
76  {
80  }
81 
83  {
84  global $ilDB;
85  $ilDB->manipulateF( "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
86  array( "integer" ),
87  array( $this->getId() )
88  );
89  $ilDB->manipulateF( "INSERT INTO " . $this->getAdditionalTableName(
90  ) . " (question_fi, maxsize, allowedextensions, compl_by_submission) VALUES (%s, %s, %s, %s)",
91  array( "integer", "float", "text", "integer" ),
92  array(
93  $this->getId(),
94  (strlen( $this->getMaxSize() )) ? $this->getMaxSize() : NULL,
95  (strlen( $this->getAllowedExtensions() )) ? $this->getAllowedExtensions() : NULL,
97  )
98  );
99  }
100 
106  public function loadFromDb($question_id)
107  {
108  global $ilDB;
109  $result = $ilDB->queryF("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",
110  array("integer"),
111  array($question_id)
112  );
113  if ($result->numRows() == 1)
114  {
115  $data = $ilDB->fetchAssoc($result);
116  $this->setId($question_id);
117  $this->setTitle($data["title"]);
118  $this->setComment($data["description"]);
119  $this->setNrOfTries($data['nr_of_tries']);
120  $this->setSuggestedSolution($data["solution_hint"]);
121  $this->setOriginalId($data["original_id"]);
122  $this->setObjId($data["obj_fi"]);
123  $this->setAuthor($data["author"]);
124  $this->setOwner($data["owner"]);
125  $this->setPoints($data["points"]);
126 
127  include_once("./Services/RTE/classes/class.ilRTE.php");
128  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc($data["question_text"], 1));
129  $this->setEstimatedWorkingTime(substr($data["working_time"], 0, 2), substr($data["working_time"], 3, 2), substr($data["working_time"], 6, 2));
130  $this->setMaxSize($data["maxsize"]);
131  $this->setAllowedExtensions($data["allowedextensions"]);
132  $this->setCompletionBySubmission($data['compl_by_submission'] == 1 ? true : false);
133 
134  try
135  {
136  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
137  }
139  {
140  }
141  }
142  parent::loadFromDb($question_id);
143  }
144 
148  public function duplicate($for_test = true, $title = "", $author = "", $owner = "", $testObjId = null)
149  {
150  if ($this->id <= 0)
151  {
152  // The question has not been saved. It cannot be duplicated
153  return;
154  }
155  // duplicate the question in database
156  $this_id = $this->getId();
157  $thisObjId = $this->getObjId();
158 
159  $clone = $this;
160  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
162  $clone->id = -1;
163 
164  if( (int)$testObjId > 0 )
165  {
166  $clone->setObjId($testObjId);
167  }
168 
169  if ($title)
170  {
171  $clone->setTitle($title);
172  }
173 
174  if ($author)
175  {
176  $clone->setAuthor($author);
177  }
178  if ($owner)
179  {
180  $clone->setOwner($owner);
181  }
182 
183  if ($for_test)
184  {
185  $clone->saveToDb($original_id);
186  }
187  else
188  {
189  $clone->saveToDb();
190  }
191 
192  // copy question page content
193  $clone->copyPageOfQuestion($this_id);
194  // copy XHTML media objects
195  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
196 
197  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
198 
199  return $clone->id;
200  }
201 
205  public function copyObject($target_questionpool_id, $title = "")
206  {
207  if ($this->id <= 0)
208  {
209  // The question has not been saved. It cannot be duplicated
210  return;
211  }
212  // duplicate the question in database
213  $clone = $this;
214  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
216  $clone->id = -1;
217  $source_questionpool_id = $this->getObjId();
218  $clone->setObjId($target_questionpool_id);
219  if ($title)
220  {
221  $clone->setTitle($title);
222  }
223  $clone->saveToDb();
224 
225  // copy question page content
226  $clone->copyPageOfQuestion($original_id);
227  // copy XHTML media objects
228  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
229 
230  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
231 
232  return $clone->id;
233  }
234 
235  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = "")
236  {
237  if ($this->id <= 0)
238  {
239  // The question has not been saved. It cannot be duplicated
240  return;
241  }
242 
243  include_once ("./Modules/TestQuestionPool/classes/class.assQuestion.php");
244 
245  $sourceQuestionId = $this->id;
246  $sourceParentId = $this->getObjId();
247 
248  // duplicate the question in database
249  $clone = $this;
250  $clone->id = -1;
251 
252  $clone->setObjId($targetParentId);
253 
254  if ($targetQuestionTitle)
255  {
256  $clone->setTitle($targetQuestionTitle);
257  }
258 
259  $clone->saveToDb();
260  // copy question page content
261  $clone->copyPageOfQuestion($sourceQuestionId);
262  // copy XHTML media objects
263  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
264 
265  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
266 
267  return $clone->id;
268  }
269 
275  public function getMaximumPoints()
276  {
277  return $this->getPoints();
278  }
279 
290  public function calculateReachedPoints($active_id, $pass = NULL, $returndetails = FALSE)
291  {
292  if( $returndetails )
293  {
294  throw new ilTestException('return details not implemented for '.__METHOD__);
295  }
296 
297  global $ilDB;
298 
299  if (is_null($pass))
300  {
301  $pass = $this->getSolutionMaxPass($active_id);
302  }
303  $points = 0;
304  return $points;
305  }
306 
307  protected function calculateReachedPointsForSolution($userSolution)
308  {
309  $points = 0;
310  return $points;
311  }
312 
318  function checkUpload()
319  {
320  $this->lng->loadLanguageModule("form");
321  // remove trailing '/'
322  while (substr($_FILES["upload"]["name"],-1) == '/')
323  {
324  $_FILES["upload"]["name"] = substr($_FILES["upload"]["name"],0,-1);
325  }
326 
327  $filename = $_FILES["upload"]["name"];
328  $filename_arr = pathinfo($_FILES["upload"]["name"]);
329  $suffix = $filename_arr["extension"];
330  $mimetype = $_FILES["upload"]["type"];
331  $size_bytes = $_FILES["upload"]["size"];
332  $temp_name = $_FILES["upload"]["tmp_name"];
333  $error = $_FILES["upload"]["error"];
334 
335  if ($size_bytes > $this->getMaxFilesizeInBytes())
336  {
337  ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
338  return false;
339  }
340 
341  // error handling
342  if ($error > 0)
343  {
344  switch ($error)
345  {
346  case UPLOAD_ERR_INI_SIZE:
347  ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
348  return false;
349  break;
350 
351  case UPLOAD_ERR_FORM_SIZE:
352  ilUtil::sendFailure($this->lng->txt("form_msg_file_size_exceeds"), true);
353  return false;
354  break;
355 
356  case UPLOAD_ERR_PARTIAL:
357  ilUtil::sendFailure($this->lng->txt("form_msg_file_partially_uploaded"), true);
358  return false;
359  break;
360 
361  case UPLOAD_ERR_NO_FILE:
362  ilUtil::sendFailure($this->lng->txt("form_msg_file_no_upload"), true);
363  return false;
364  break;
365 
366  case UPLOAD_ERR_NO_TMP_DIR:
367  ilUtil::sendFailure($this->lng->txt("form_msg_file_missing_tmp_dir"), true);
368  return false;
369  break;
370 
371  case UPLOAD_ERR_CANT_WRITE:
372  ilUtil::sendFailure($this->lng->txt("form_msg_file_cannot_write_to_disk"), true);
373  return false;
374  break;
375 
376  case UPLOAD_ERR_EXTENSION:
377  ilUtil::sendFailure($this->lng->txt("form_msg_file_upload_stopped_ext"), true);
378  return false;
379  break;
380  }
381  }
382 
383  // check suffixes
384  if (strlen($suffix) && count($this->getAllowedExtensionsArray()))
385  {
386  if (!in_array(strtolower($suffix), $this->getAllowedExtensionsArray()))
387  {
388  ilUtil::sendFailure($this->lng->txt("form_msg_file_wrong_file_type"), true);
389  return false;
390  }
391  }
392 
393  // virus handling
394  if (strlen($temp_name))
395  {
396  $vir = ilUtil::virusHandling($temp_name, $filename);
397  if ($vir[0] == false)
398  {
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  protected function getFileUploadPath($test_id, $active_id, $question_id = null)
410  {
411  if (is_null($question_id)) $question_id = $this->getId();
412  return CLIENT_WEB_DIR . "/assessment/tst_$test_id/$active_id/$question_id/files/";
413  }
414 
418  protected function getPreviewFileUploadPath($userId)
419  {
420  return CLIENT_WEB_DIR . "/assessment/qst_preview/$userId/{$this->getId()}/fileuploads/";
421  }
422 
428  function getFileUploadPathWeb($test_id, $active_id, $question_id = null)
429  {
430  if (is_null($question_id)) $question_id = $this->getId();
431  include_once "./Services/Utilities/classes/class.ilUtil.php";
432  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/tst_$test_id/$active_id/$question_id/files/";
434  }
435 
439  protected function getPreviewFileUploadPathWeb($userId)
440  {
441  include_once "./Services/Utilities/classes/class.ilUtil.php";
442  $webdir = ilUtil::removeTrailingPathSeparators(CLIENT_WEB_DIR) . "/assessment/qst_preview/$userId/{$this->getId()}/fileuploads/";
444  }
445 
451  public function getUploadedFiles($active_id, $pass = null)
452  {
453  global $ilDB;
454  if (is_null($pass))
455  {
456  $pass = $this->getSolutionMaxPass($active_id);
457  }
458  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s ORDER BY tstamp",
459  array("integer", "integer", "integer"),
460  array($active_id, $this->getId(), $pass)
461  );
462  $found = array();
463  while ($data = $ilDB->fetchAssoc($result))
464  {
465  array_push($found, $data);
466  }
467  return $found;
468  }
469 
470  public function getPreviewFileUploads(ilAssQuestionPreviewSession $previewSession)
471  {
472  return (array)$previewSession->getParticipantsSolution();
473  }
474 
480  public function getUploadedFilesForWeb($active_id, $pass)
481  {
482  global $ilDB;
483 
484  $found = $this->getUploadedFiles($active_id, $pass);
485  $result = $ilDB->queryF("SELECT test_fi FROM tst_active WHERE active_id = %s",
486  array('integer'),
487  array($active_id)
488  );
489  if ($result->numRows() == 1)
490  {
491  $row = $ilDB->fetchAssoc($result);
492  $test_id = $row["test_fi"];
493  $path = $this->getFileUploadPathWeb($test_id, $active_id);
494  foreach ($found as $idx => $data)
495  {
496  $found[$idx]['webpath'] = $path;
497  }
498  }
499  return $found;
500  }
501 
507  protected function deleteUploadedFiles($files, $test_id, $active_id)
508  {
509  global $ilDB;
510 
511  $pass = null;
512  $active_id = null;
513  foreach ($files as $solution_id)
514  {
515  $result = $ilDB->queryF("SELECT * FROM tst_solutions WHERE solution_id = %s",
516  array("integer"),
517  array($solution_id)
518  );
519  if ($result->numRows() == 1)
520  {
521  $data = $ilDB->fetchAssoc($result);
522  $pass = $data['pass'];
523  $active_id = $data['active_fi'];
524  @unlink($this->getFileUploadPath($test_id, $active_id) . $data['value1']);
525  }
526  }
527  foreach ($files as $solution_id)
528  {
529  $affectedRows = $ilDB->manipulateF("DELETE FROM tst_solutions WHERE solution_id = %s",
530  array("integer"),
531  array($solution_id)
532  );
533  }
534  }
535 
536  protected function deletePreviewFileUploads($userId, $userSolution, $files)
537  {
538  foreach($files as $name)
539  {
540  if( isset($userSolution[$name]) )
541  {
542  unset($userSolution[$name]);
543  @unlink($this->getPreviewFileUploadPath($userId) . $name);
544  }
545  }
546 
547  return $userSolution;
548  }
549 
555  public function getMaxFilesizeAsString()
556  {
557  $size = $this->getMaxFilesizeInBytes();
558  if ($size < 1024)
559  {
560  $max_filesize = sprintf("%d Bytes",$size);
561  }
562  else if ($size < 1024*1024)
563  {
564  $max_filesize = sprintf("%.1f KB",$size/1024);
565  }
566  else
567  {
568  $max_filesize = sprintf("%.1f MB",$size/1024/1024);
569  }
570 
571  return $max_filesize;
572  }
573 
579  public function getMaxFilesizeInBytes()
580  {
581  if (strlen($this->getMaxSize()))
582  {
583  return $this->getMaxSize();
584  }
585  else
586  {
587  // get the value for the maximal uploadable filesize from the php.ini (if available)
588  $umf = get_cfg_var("upload_max_filesize");
589  // get the value for the maximal post data from the php.ini (if available)
590  $pms = get_cfg_var("post_max_size");
591 
592  //convert from short-string representation to "real" bytes
593  $multiplier_a=array("K"=>1024, "M"=>1024*1024, "G"=>1024*1024*1024);
594 
595  $umf_parts=preg_split("/(\d+)([K|G|M])/", $umf, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
596  $pms_parts=preg_split("/(\d+)([K|G|M])/", $pms, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
597 
598  if (count($umf_parts) == 2) { $umf = $umf_parts[0]*$multiplier_a[$umf_parts[1]]; }
599  if (count($pms_parts) == 2) { $pms = $pms_parts[0]*$multiplier_a[$pms_parts[1]]; }
600 
601  // use the smaller one as limit
602  $max_filesize = min($umf, $pms);
603 
604  if (!$max_filesize) $max_filesize=max($umf, $pms);
605  return $max_filesize;
606  }
607  }
608 
617  public function saveWorkingData($active_id, $pass = NULL)
618  {
619  global $ilDB;
620  global $ilUser;
621 
622  if (is_null($pass))
623  {
624  include_once "./Modules/Test/classes/class.ilObjTest.php";
625  $pass = ilObjTest::_getPass($active_id);
626  }
627 
628  if( $_POST['cmd'][$this->questionActionCmd] != $this->lng->txt('delete')
629  && strlen($_FILES["upload"]["tmp_name"]) )
630  {
631  $checkUploadResult = $this->checkUpload();
632  }
633  else
634  {
635  $checkUploadResult = false;
636  }
637 
638  $result = $ilDB->queryF("SELECT test_fi FROM tst_active WHERE active_id = %s",
639  array('integer'),
640  array($active_id)
641  );
642  $test_id = 0;
643  if ($result->numRows() == 1)
644  {
645  $row = $ilDB->fetchAssoc($result);
646  $test_id = $row["test_fi"];
647  }
648 
649  $this->getProcessLocker()->requestUserSolutionUpdateLock();
650 
651  $entered_values = false;
652  if( $_POST['cmd'][$this->questionActionCmd] == $this->lng->txt('delete') )
653  {
654  if (is_array($_POST['deletefiles']) && count($_POST['deletefiles']) > 0)
655  {
656  $this->deleteUploadedFiles($_POST['deletefiles'], $test_id, $active_id);
657  }
658  else
659  {
660  ilUtil::sendInfo($this->lng->txt('no_checkbox'), true);
661  }
662  }
663  elseif( $checkUploadResult )
664  {
665  if (!@file_exists($this->getFileUploadPath($test_id, $active_id))) ilUtil::makeDirParents($this->getFileUploadPath($test_id, $active_id));
666  $version = time();
667  $filename_arr = pathinfo($_FILES["upload"]["name"]);
668  $extension = $filename_arr["extension"];
669  $newfile = "file_" . $active_id . "_" . $pass . "_" . $version . "." . $extension;
670  ilUtil::moveUploadedFile($_FILES["upload"]["tmp_name"], $_FILES["upload"]["name"], $this->getFileUploadPath($test_id, $active_id) . $newfile);
671  $next_id = $ilDB->nextId('tst_solutions');
672  $affectedRows = $ilDB->insert("tst_solutions", array(
673  "solution_id" => array("integer", $next_id),
674  "active_fi" => array("integer", $active_id),
675  "question_fi" => array("integer", $this->getId()),
676  "value1" => array("clob", $newfile),
677  "value2" => array("clob", $_FILES['upload']['name']),
678  "pass" => array("integer", $pass),
679  "tstamp" => array("integer", time())
680  ));
681  $entered_values = true;
682  }
683 
684  $this->getProcessLocker()->releaseUserSolutionUpdateLock();
685 
686  if ($entered_values)
687  {
688  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
690  {
691  $this->logAction($this->lng->txtlng("assessment", "log_user_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
692  }
693  }
694  else
695  {
696  include_once ("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
698  {
699  $this->logAction($this->lng->txtlng("assessment", "log_user_not_entered_values", ilObjAssessmentFolder::_getLogLanguage()), $active_id, $this->getId());
700  }
701  }
702 
703  return true;
704  }
705 
706  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession)
707  {
708  $userSolution = $previewSession->getParticipantsSolution();
709 
710  if( !is_array($userSolution) )
711  {
712  $userSolution = array();
713  }
714 
715  if (strcmp($_POST['cmd'][$this->questionActionCmd], $this->lng->txt('delete')) == 0)
716  {
717  if (is_array($_POST['deletefiles']) && count($_POST['deletefiles']) > 0)
718  {
719  $userSolution = $this->deletePreviewFileUploads($previewSession->getUserId(), $userSolution, $_POST['deletefiles']);
720  }
721  else
722  {
723  ilUtil::sendInfo($this->lng->txt('no_checkbox'), true);
724  }
725  }
726  else
727  {
728  if (strlen($_FILES["upload"]["tmp_name"]))
729  {
730  if ($this->checkUpload())
731  {
732  if( !@file_exists($this->getPreviewFileUploadPath($previewSession->getUserId())) )
733  {
734  ilUtil::makeDirParents($this->getPreviewFileUploadPath($previewSession->getUserId()));
735  }
736 
737  $version = time();
738  $filename_arr = pathinfo($_FILES["upload"]["name"]);
739  $extension = $filename_arr["extension"];
740  $newfile = "file_".md5($_FILES["upload"]["name"])."_" . $version . "." . $extension;
741  ilUtil::moveUploadedFile($_FILES["upload"]["tmp_name"], $_FILES["upload"]["name"], $this->getPreviewFileUploadPath($previewSession->getUserId()) . $newfile);
742 
743  $userSolution[$newfile] = array(
744  'solution_id' => $newfile,
745  'value1' => $newfile,
746  'value2' => $_FILES['upload']['name'],
747  'tstamp' => $version,
748  'webpath' => $this->getPreviewFileUploadPathWeb($previewSession->getUserId())
749  );
750  }
751  }
752  }
753 
754  $previewSession->setParticipantsSolution($userSolution);
755  }
756 
765  protected function reworkWorkingData($active_id, $pass, $obligationsAnswered)
766  {
767  $this->handleSubmission($active_id, $pass, $obligationsAnswered);
768  }
769 
779  protected function handleSubmission($active_id, $pass, $obligationsAnswered)
780  {
781  global $ilObjDataCache;
782 
784  {
785  $maxpoints = assQuestion::_getMaximumPoints($this->getId());
786 
787  if($this->getUploadedFiles($active_id, $pass))
788  {
789  $points = $maxpoints;
790  }
791  else
792  {
793  $points = 0;
794  }
795 
796  assQuestion::_setReachedPoints($active_id, $this->getId(), $points, $maxpoints, $pass, 1, $obligationsAnswered);
797 
798  // update learning progress
799  include_once 'Modules/Test/classes/class.ilObjTestAccess.php';
800  include_once 'Services/Tracking/classes/class.ilLPStatusWrapper.php';
802  ilObjTest::_getObjectIDFromActiveID((int)$active_id),
803  ilObjTestAccess::_getParticipantId((int) $active_id)
804  );
805  }
806  }
807 
813  public function getQuestionType()
814  {
815  return "assFileUpload";
816  }
817 
823  public function getAdditionalTableName()
824  {
825  return "qpl_qst_fileupload";
826  }
827 
833  public function getAnswerTableName()
834  {
835  return "";
836  }
837 
843  public function deleteAnswers($question_id)
844  {
845  }
846 
851  public function getRTETextWithMediaObjects()
852  {
854  return $text;
855  }
856 
868  public function setExportDetailsXLS(&$worksheet, $startrow, $active_id, $pass, &$format_title, &$format_bold)
869  {
870  include_once ("./Services/Excel/classes/class.ilExcelUtils.php");
871  $worksheet->writeString($startrow, 0, ilExcelUtils::_convert_text($this->lng->txt($this->getQuestionType())), $format_title);
872  $worksheet->writeString($startrow, 1, ilExcelUtils::_convert_text($this->getTitle()), $format_title);
873  $i = 1;
874  $solutions = $this->getSolutionValues($active_id, $pass);
875  foreach ($solutions as $solution)
876  {
877  $worksheet->writeString($startrow + $i, 0, ilExcelUtils::_convert_text($this->lng->txt("result")), $format_bold);
878  if (strlen($solution["value1"]))
879  {
880  $worksheet->write($startrow + $i, 1, ilExcelUtils::_convert_text($solution["value1"]));
881  $worksheet->write($startrow + $i, 2, ilExcelUtils::_convert_text($solution["value2"]));
882  }
883  $i++;
884  }
885  return $startrow + $i + 1;
886  }
887 
900  public function fromXML(&$item, &$questionpool_id, &$tst_id, &$tst_object, &$question_counter, &$import_mapping)
901  {
902  include_once "./Modules/TestQuestionPool/classes/import/qti12/class.assFileUploadImport.php";
903  $import = new assFileUploadImport($this);
904  $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
905  }
906 
913  public function toXML($a_include_header = true, $a_include_binary = true, $a_shuffle = false, $test_output = false, $force_image_references = false)
914  {
915  include_once "./Modules/TestQuestionPool/classes/export/qti12/class.assFileUploadExport.php";
916  $export = new assFileUploadExport($this);
917  return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
918  }
919 
925  public function getBestSolution($active_id, $pass)
926  {
927  $user_solution = array();
928  return $user_solution;
929  }
930 
936  public function getMaxSize()
937  {
938  return $this->maxsize;
939  }
940 
946  public function setMaxSize($a_value)
947  {
948  $this->maxsize = $a_value;
949  }
950 
956  public function getAllowedExtensionsArray()
957  {
958  if (strlen($this->allowedextensions))
959  {
960  return array_filter(array_map('trim', explode(",", $this->allowedextensions)));
961  }
962  return array();
963  }
964 
970  public function getAllowedExtensions()
971  {
973  }
974 
980  public function setAllowedExtensions($a_value)
981  {
982  $this->allowedextensions = strtolower(trim($a_value));
983  }
984 
988  public function __get($value)
989  {
990  switch ($value)
991  {
992  case "maxsize":
993  return $this->getMaxSize();
994  break;
995  case "allowedextensions":
996  return $this->getAllowedExtensions();
997  break;
998  case 'completion_by_submission':
999  return $this->isCompletionBySubmissionEnabled();
1000  break;
1001  default:
1002  return parent::__get($value);
1003  break;
1004  }
1005  }
1006 
1010  public function __set($key, $value)
1011  {
1012  switch ($key)
1013  {
1014  case "maxsize":
1015  $this->setMaxSize($value);
1016  break;
1017  case "allowedextensions":
1018  $this->setAllowedExtensions($value);
1019  break;
1020  case 'completion_by_submission':
1021  $this->setCompletionBySubmission($value);
1022  break;
1023  default:
1024  parent::__set($key, $value);
1025  break;
1026  }
1027  }
1028 
1036  public function hasFileUploads($test_id)
1037  {
1038  global $ilDB;
1039  $query = "
1040  SELECT tst_solutions.solution_id
1041  FROM tst_solutions, tst_active, qpl_questions
1042  WHERE tst_solutions.active_fi = tst_active.active_id
1043  AND tst_solutions.question_fi = qpl_questions.question_id
1044  AND tst_solutions.question_fi = %s AND tst_active.test_fi = %s";
1045  $result = $ilDB->queryF( $query,
1046  array("integer", "integer"),
1047  array($this->getId(), $test_id)
1048  );
1049  if ($result->numRows() > 0)
1050  {
1051  return true;
1052  }
1053  else
1054  {
1055  return false;
1056  }
1057  }
1058 
1064  public function getFileUploadZIPFile($test_id)
1065  {
1067  global $ilDB;
1068  $query = "
1069  SELECT
1070  tst_solutions.solution_id, tst_solutions.pass, tst_solutions.active_fi, tst_solutions.question_fi,
1071  tst_solutions.value1, tst_solutions.value2, tst_solutions.tstamp
1072  FROM tst_solutions, tst_active, qpl_questions
1073  WHERE tst_solutions.active_fi = tst_active.active_id
1074  AND tst_solutions.question_fi = qpl_questions.question_id
1075  AND tst_solutions.question_fi = %s
1076  AND tst_active.test_fi = %s
1077  ORDER BY tst_solutions.active_fi, tst_solutions.tstamp";
1078 
1079  $result = $ilDB->queryF( $query,
1080  array("integer", "integer"),
1081  array($this->getId(), $test_id)
1082  );
1083  $zipfile = ilUtil::ilTempnam() . ".zip";
1084  $tempdir = ilUtil::ilTempnam();
1085  if ($result->numRows())
1086  {
1087  $userdata = array();
1088  $data .= "<html><head>";
1089  $data .= '<meta http-equiv="content-type" content="text/html; charset=UTF-8" />';
1090  $data .= '<style>
1091  table { border: 1px #333 solid; border-collapse:collapse;}
1092  td, th { border: 1px #333 solid; padding: 0.25em;}
1093  th { color: #fff; background-color: #666;}
1094  </style>
1095  ';
1096  $data .= "<title>" . $this->getTitle() . "</title></head><body>\n";
1097  $data .= "<h1>" . $this->getTitle() . "</h1>\n";
1098  $data .= "<table><thead>\n";
1099  $data .= "<tr><th>" . $this->lng->txt("name") . "</th><th>" . $this->lng->txt("filename") . "</th><th>" . $this->lng->txt("pass") . "</th><th>" . $this->lng->txt("location") . "</th><th>" . $this->lng->txt("date") . "</th></tr></thead><tbody>\n";
1100  while ($row = $ilDB->fetchAssoc($result))
1101  {
1102  ilUtil::makeDirParents($tempdir . "/" . $row["active_fi"]."/".$row["question_fi"]);
1103  @copy($this->getFileUploadPath($test_id, $row["active_fi"], $row["question_fi"]) . $row["value1"], $tempdir . "/" . $row["active_fi"]."/".$row["question_fi"] . "/" . $row["value1"]);
1104  if (!array_key_exists($row["active_fi"], $userdata))
1105  {
1106  include_once "./Modules/Test/classes/class.ilObjTestAccess.php";
1107  $userdata[$row["active_fi"]] = ilObjTestAccess::_getParticipantData($row["active_fi"]);
1108  }
1109  $data .= "<tr><td>".$userdata[$row["active_fi"]]."</td><td><a href=\"".$row["active_fi"]."/".$row["question_fi"]."/".$row["value1"]."\" target=\"_blank\">".$row["value2"]."</a></td><td>".$row["pass"]."</td><td>".$row["active_fi"]."/".$row["question_fi"]."/".$row["value1"]."</td>";
1110  $data .= "<td>" . ilFormat::fmtDateTime(ilFormat::unixtimestamp2datetime($row["tstamp"]), $this->lng->txt("lang_dateformat"), $this->lng->txt("lang_timeformat"), "datetime", FALSE) . "</td>";
1111  $data .= "</tr>\n";
1112  }
1113  $data .= "</tbody></table>\n";
1114  $data .= "</body></html>\n";
1115 
1116  $indexfile = $tempdir . "/index.html";
1117  $fh = fopen($indexfile, 'w');
1118  fwrite($fh, $data);
1119  fclose($fh);
1120  }
1121  ilUtil::zip($tempdir, $zipfile);
1122  ilUtil::delDir($tempdir);
1123  ilUtil::deliverFile($zipfile, ilUtil::getASCIIFilename($this->getTitle().".zip"), "application/zip", false, true);
1124  }
1125 
1135  {
1137  }
1138 
1148  public function setCompletionBySubmission($bool)
1149  {
1150  $this->completion_by_submission = (bool)$bool;
1151  return $this;
1152  }
1153 
1165  public function isAnswered($active_id, $pass)
1166  {
1167  $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1168 
1169  return $numExistingSolutionRecords > 0;
1170  }
1171 
1182  public static function isObligationPossible($questionId)
1183  {
1184  return true;
1185  }
1186 
1187  public function isAutosaveable()
1188  {
1189  return FALSE;
1190  }
1191 }