ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilFolderDownloadBackgroundTaskHandler.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 include_once "Services/BackgroundTask/classes/class.ilZipBackgroundTaskHandler.php";
5 
13 {
14  protected $settings; // [ilSetting]
15  protected $ref_ids = array(); // [array]
16  // bugfix mantis 24309: array for systematically numbering copied files
17  private static $duplicate_files = array(); // [array]
18 
19 
20  protected static $initialized; // [bool]
21 
22  //
23  // constructor
24  //
25 
31  public function __construct()
32  {
33  parent::__construct();
34  $this->settings = new ilSetting("fold");
35  }
36 
37  public static function getInstanceFromTask(ilBackgroundTask $a_task)
38  {
39  global $DIC;
40  $tree = $DIC['tree'];
41 
42  $obj = new self();
43  $obj->setTask($a_task);
44 
45  $params = $a_task->getParams();
46  $obj->setRefIds($params["ref_ids"]);
47 
48  $ref_id = (sizeof($params["ref_ids"]) == 1)
49  ? $params["ref_ids"][0]
50  : $tree->getParentId($params["ref_ids"][0]);
51  $obj->setDeliveryFilename(ilObject::_lookupTitle(ilObject::_lookupObjId($ref_id)));
52 
53  return $obj;
54  }
55 
56 
57  //
58  // setter/getter/status
59  //
60 
66  public static function isActive()
67  {
68  $settings = new ilSetting("fold");
69  return (bool) $settings->get("bgtask_download", false);
70  }
71 
77  public function getRefIds()
78  {
79  return $this->ref_ids;
80  }
81 
87  public function setRefIds($a_val)
88  {
89  $this->ref_ids = $a_val;
90  }
91 
92 
93  //
94  // gui integration
95  //
96 
104  public static function getObjectListAction($a_ref_id)
105  {
106  self::initObjectListAction();
107 
108  return "il.BgTask.init('" . static::class . "', " . $a_ref_id . ");";
109  }
110 
111 
115  public static function initObjectListAction()
116  {
117  // js init only needed once per request
118  if (!self::$initialized) {
119  global $DIC;
120  $tpl = $DIC['tpl'];
121  $ilCtrl = $DIC['ilCtrl'];
122 
123  $url = $ilCtrl->getLinkTargetByClass(array("ilrepositorygui", "ilobjfoldergui", "ilbackgroundtaskhub"), "", "", true, false);
124 
125  $tpl->addJavaScript("Services/BackgroundTask/js/BgTask.js");
126  $tpl->addOnLoadCode('il.BgTask.setAjax("' . $url . '");');
127 
128  // enable modals from js
129  include_once "Services/UIComponent/Modal/classes/class.ilModalGUI.php";
131 
132  self::$initialized = true;
133  }
134  }
135 
136 
137  //
138  // handler interface
139  //
140 
141  public function init($a_params = null)
142  {
143  global $DIC;
144  $lng = $DIC['lng'];
145  $ilUser = $DIC['ilUser'];
146 
147  if ($a_params) {
148  $this->setRefIds(explode(",", $a_params));
149  }
150 
151  $file_count = $total_bytes = 0;
152  $this->calculateRecursive($this->getRefIds(), $file_count, $total_bytes);
153 
154  include_once "Services/BackgroundTask/classes/class.ilBackgroundTaskJson.php";
155 
156  // empty folder - nothing to do
157  if (!$file_count) {
158  $json = ilBackgroundTaskJson::getFailedJson($lng->txt("bgtask_empty_folder"));
159  } else {
160  // check if below download size limit
161  $size_limit_mb = $this->getDownloadSizeLimit() * 1024 * 1024;
162  if ($size_limit_mb > 0 && $total_bytes > $size_limit_mb) {
163  $json = ilBackgroundTaskJson::getFailedJson(sprintf($lng->txt("bgtask_download_too_large"), ilUtil::formatSize($size_limit_mb)));
164  } else {
165  // set up task instance
166  include_once "Services/BackgroundTask/classes/class.ilBackgroundTask.php";
167  $task = new ilBackgroundTask();
168  $task->setHandlerId(get_class($this));
169  $task->setUserId($ilUser->getId());
170  $task->setParams(array(
171  "ref_ids" => $this->getRefIds()
172  ));
173  $task->setSteps($file_count+1); // +1 = create zip
175  $task->save();
176 
177  $this->setTask($task);
178 
179  // above thresholds: do background task
180  if ($file_count >= $this->getFileCountThreshold()
181  || $total_bytes >= $this->getTotalSizeThreshold() * 1024 * 1024) {
182  // check for other tasks from same user
183  $existing = ilBackgroundTask::getActiveByUserId($ilUser->getId());
184  if (sizeof($existing)) {
186  } else {
188  $task->getId(),
189  sprintf($lng->txt("bgtask_download_long"), $file_count, ilUtil::formatSize($total_bytes)),
190  $file_count+1
191  );
192  }
193  }
194  // below thresholds: direct download
195  else {
196  $this->process();
197 
199  $task->save();
200 
201  $res = $this->finish();
202 
203  // see ilBackgroundTaskHub::progress()
204  $json = ilBackgroundTaskJson::getFinishedJson($task->getId(), $res[0], $res[1]);
205  }
206  }
207  }
208 
209  return $json;
210  }
211 
212  protected function gatherFiles()
213  {
214  $tmpdir = $this->getTempFolderPath();
215 
216  $current_step = 0;
217 
218  // parse folders
219  foreach ($this->getRefIds() as $ref_id) {
220  // has been cancelled: hurry up
221  if ($this->task->isToBeCancelled()) {
222  return;
223  }
224 
225  if (!$this->validateAccess($ref_id)) {
226  continue;
227  }
228 
229  $object = ilObjectFactory::getInstanceByRefId($ref_id);
230  switch ($object->getType()) {
231  case "fold":
232  $this->recurseFolder($ref_id, $object->getTitle(), $tmpdir, $current_step);
233  break;
234 
235  case "file":
236  $this->copyFile($object->getId(), $object->getTitle(), $tmpdir, $current_step);
237  break;
238  }
239  }
240 
241  return $current_step;
242  }
243 
244 
245  //
246  // processing
247  //
248 
256  protected function calculateRecursive($a_ref_ids, &$a_file_count, &$a_file_size)
257  {
258  global $DIC;
259  $tree = $DIC['tree'];
260 
261  include_once("./Modules/File/classes/class.ilObjFileAccess.php");
262 
263  // parse folders
264  foreach ($a_ref_ids as $ref_id) {
265  if (!$this->validateAccess($ref_id)) {
266  continue;
267  }
268 
269  // we are only interested in folders and files
270  switch (ilObject::_lookupType($ref_id, true)) {
271  case "fold":
272  // get child objects
273  $subtree = $tree->getChildsByTypeFilter($ref_id, array("fold", "file"));
274  if (count($subtree) > 0) {
275  $child_ref_ids = array();
276  foreach ($subtree as $child) {
277  $child_ref_ids[] = $child["ref_id"];
278  }
279  $this->calculateRecursive($child_ref_ids, $a_file_count, $a_file_size);
280  }
281  break;
282 
283  case "file":
285  $a_file_count += 1;
286  break;
287  }
288  }
289  }
290 
299  protected function recurseFolder($a_ref_id, $a_title, $a_tmpdir, &$a_current_step)
300  {
301  global $DIC;
302  $tree = $DIC['tree'];
303 
304  $tmpdir = $a_tmpdir . "/" . ilUtil::getASCIIFilename($a_title);
305  ilUtil::makeDir($tmpdir);
306 
307  $subtree = $tree->getChildsByTypeFilter($a_ref_id, array("fold", "file"));
308  foreach ($subtree as $child) {
309  // has been cancelled: hurry up
310  if ($this->task->isToBeCancelled()) {
311  return;
312  }
313 
314  if (!$this->validateAccess($child["ref_id"])) {
315  continue;
316  }
317 
318  switch ($child["type"]) {
319  case "fold":
320  $this->recurseFolder($child["ref_id"], $child["title"], $tmpdir, $a_current_step);
321  break;
322 
323  case "file":
324  $this->copyFile($child["obj_id"], $child["title"], $tmpdir, $a_current_step);
325  break;
326  }
327  }
328  }
329 
338  protected function copyFile($a_obj_id, $a_title, $a_tmpdir, &$a_current_step)
339  {
340  // :TODO: every file?
341  $this->task->setCurrentStep(++$a_current_step);
342  $this->task->save();
343 
344  $new_filename = $a_tmpdir . "/" . ilUtil::getASCIIFilename($a_title);
345 
346  // bugfix mantis 24309:
347  // alter the filename if there are identically named files in the same folder to prevent overwriting
348  if (file_exists($new_filename)) {
349  $new_filename = $this->renameDuplicateFile($new_filename);
350  }
351 
352  // copy to temporary directory
353  include_once "Modules/File/classes/class.ilObjFile.php";
354  $old_filename = ilObjFile::_lookupAbsolutePath($a_obj_id);
355  if (!copy($old_filename, $new_filename)) {
356  throw new ilFileException("Could not copy " . $old_filename . " to " . $new_filename);
357  }
358 
359  touch($new_filename, filectime($old_filename));
360  }
361 
362 
372  private static function renameDuplicateFile($duplicate_filename)
373  {
374  // determine the copy_number that will be added to the filename either by obtaining it from
375  // the entry of the current file in the duplicate_files-array or use 1 if there is no entry yet
376  $copy_number = 1;
377  $duplicate_has_array_entry = false;
378  foreach (self::$duplicate_files as &$duplicate_file) {
379  if ($duplicate_file['file_name'] == $duplicate_filename) {
380  $duplicate_has_array_entry = true;
381  $copy_number = $duplicate_file['copy_number'];
382  // increment the copy_number for correctly renaming the next duplicate of this file
383  $duplicate_file['copy_number']++;
384  }
385  }
386 
387  // create an array entry for the duplicate file if there isn't one to ensure that the
388  // copy_number can be determined correctly for other duplicates of this file
389  if (!$duplicate_has_array_entry) {
390  self::$duplicate_files[] = [
391  'file_name' => $duplicate_filename,
392  'copy_number' => 2 // set as 2 because 1 is already used for this duplicate
393  ];
394  }
395 
396  // rename the file
397  $path = pathinfo($duplicate_filename, PATHINFO_DIRNAME);
398  $filename = pathinfo($duplicate_filename, PATHINFO_FILENAME);
399  $extension = pathinfo($duplicate_filename, PATHINFO_EXTENSION);
400  $new_filename = $path . "/" . $filename . " (" . $copy_number . ")." . $extension;
401 
402  return $new_filename;
403  }
404 
405 
412  protected function validateAccess($ref_id)
413  {
414  global $DIC;
415  $ilAccess = $DIC['ilAccess'];
416 
417  if (!$ilAccess->checkAccess("read", "", $ref_id)) {
418  return false;
419  }
420 
421  if (ilObject::_isInTrash($ref_id)) {
422  return false;
423  }
424 
425  return true;
426  }
427 
428 
429  //
430  // settings
431  //
432 
438  protected function getDownloadSizeLimit()
439  {
440  return (int) $this->settings->get("bgtask_download_limit", 0);
441  }
442 
448  protected function getFileCountThreshold()
449  {
450  return (int) $this->settings->get("bgtask_download_tcount", 0);
451  }
452 
458  protected function getTotalSizeThreshold()
459  {
460  return (int) $this->settings->get("bgtask_download_tsize", 0);
461  }
462 }
$params
Definition: disable.php:11
Background task handler for folder downloads.
static getFinishedJson($a_task_id, $a_cmd, $a_result)
Get json for finished task.
global $DIC
Definition: saml.php:7
getParams()
Gets the params.
$tpl
Definition: ilias.php:10
static initObjectListAction()
init js for background download
copyFile($a_obj_id, $a_title, $a_tmpdir, &$a_current_step)
Copies a file to the specified temporary directory.
Background task handler for zip creation.
static _isInTrash($a_ref_id)
checks wether object is in trash
static getProcessingJson($a_task_id, $a_message, $a_steps)
Get json for processing task.
static getActiveByUserId($a_user_id)
static _lookupTitle($a_id)
lookup object title
calculateRecursive($a_ref_ids, &$a_file_count, &$a_file_size)
Calculates the number and size of the files being downloaded recursively.
static initJS(ilTemplate $a_main_tpl=null)
Init javascript.
static getASCIIFilename($a_filename)
convert utf8 to ascii filename
static _lookupFileSize($a_id)
Quickly looks up the file size from the database and returns the number of bytes. ...
global $ilCtrl
Definition: ilias.php:18
foreach($_POST as $key=> $value) $res
static getFailedJson($a_message)
Get json for failed task.
static _lookupObjId($a_id)
$ilUser
Definition: imgupload.php:18
Class to report exception.
static isActive()
Is folder background download active?
Create styles array
The data for the language used.
static _lookupType($a_id, $a_reference=false)
lookup object type
static makeDir($a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
getTempFolderPath()
Gets the temporary folder path to copy the files and folders to.
settings()
Definition: settings.php:2
static getBlockedJson($a_task_id)
Get json for blocked task.
recurseFolder($a_ref_id, $a_title, $a_tmpdir, &$a_current_step)
Copies a folder and its files to the specified temporary directory.
setTask(ilBackgroundTask $a_task)
Set current task instance.
global $lng
Definition: privfeed.php:17
static _lookupAbsolutePath($obj_id, $a_version=null)
static getInstanceByRefId($a_ref_id, $stop_on_error=true)
get an instance of an Ilias object by reference id
static getInstanceFromTask(ilBackgroundTask $a_task)
Constructor/Factory.
$url
static formatSize($size, $a_mode='short', $a_lng=null)
Returns the specified file size value in a human friendly form.
static getObjectListAction($a_ref_id)
Get object list action.
static renameDuplicateFile($duplicate_filename)
bugfix mantis 24309: add a number in round brackets to the filename (in front of the file-type-extens...