1<?php 2/* Copyright (c) 1998-2016 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4/** 5 * This class handles all operations on files for the drafts of a forum object. 6 * 7 * @author Nadia Matuschek <nmatuschek@databay.de> 8 * 9 * @ingroup ModulesForum 10 */ 11class ilFileDataForumDrafts extends ilFileData 12{ 13 protected $obj_id = 0; 14 protected $draft_id = 0; 15 protected $drafts_path = ''; 16 private $lng; 17 private $error; 18 19 public function __construct($obj_id = 0, $draft_id) 20 { 21 global $DIC; 22 $this->lng = $DIC->language(); 23 $this->error = $DIC['ilErr']; 24 25 $this->obj_id = $obj_id; 26 $this->draft_id = $draft_id; 27 28 define('FORUM_DRAFTS_PATH', 'forum/drafts'); 29 parent::__construct(); 30 $this->drafts_path = parent::getPath() . "/" . FORUM_DRAFTS_PATH; 31 32 // IF DIRECTORY ISN'T CREATED CREATE IT 33 if (!$this->__checkPath()) { 34 $this->__initDirectory(); 35 } 36 } 37 38 /** 39 * @return int 40 */ 41 public function getObjId() 42 { 43 return $this->obj_id; 44 } 45 46 /** 47 * @param int $obj_id 48 */ 49 public function setObjId($obj_id) 50 { 51 $this->obj_id = $obj_id; 52 } 53 54 /** 55 * @return int 56 */ 57 public function getDraftId() 58 { 59 return $this->draft_id; 60 } 61 62 /** 63 * @param int $draft_id 64 */ 65 public function setDraftId($draft_id) 66 { 67 $this->draft_id = $draft_id; 68 } 69 70 /** 71 * @return string 72 */ 73 public function getDraftsPath() 74 { 75 return $this->drafts_path; 76 } 77 78 79 /** 80 * @return array 81 */ 82 public function getFiles() 83 { 84 $files = array(); 85 86 foreach (new DirectoryIterator($this->getDraftsPath() . '/' . $this->getDraftId()) as $file) { 87 /** 88 * @var $file SplFileInfo 89 */ 90 91 if ($file->isDir()) { 92 continue; 93 } 94 95 $files[] = array( 96 'path' => $file->getPathname(), 97 'md5' => md5($file->getFilename()), 98 'name' => $file->getFilename(), 99 'size' => $file->getSize(), 100 'ctime' => date('Y-m-d H:i:s', $file->getCTime()) 101 ); 102 } 103 104 return $files; 105 } 106 107 /** 108 * @return array 109 */ 110 public function getFilesOfPost() 111 { 112 $files = array(); 113 114 foreach (new DirectoryIterator($this->getDraftsPath() . '/' . $this->getDraftId()) as $file) { 115 /** 116 * @var $file SplFileInfo 117 */ 118 119 if ($file->isDir()) { 120 continue; 121 } 122 123 $files[$file->getFilename()] = array( 124 'path' => $file->getPathname(), 125 'md5' => md5($file->getFilename()), 126 'name' => $file->getFilename(), 127 'size' => $file->getSize(), 128 'ctime' => date('Y-m-d H:i:s', $file->getCTime()) 129 ); 130 } 131 132 return $files; 133 } 134 135 public function moveFilesOfDraft($forum_path, $new_post_id) 136 { 137 foreach ($this->getFilesOfPost() as $file) { 138 @copy( 139 $file['path'], 140 $forum_path . '/' . $this->obj_id . '_' . $new_post_id . '_' . $file['name'] 141 ); 142 } 143 return true; 144 } 145 146 /** 147 * @return bool 148 */ 149 public function delete() 150 { 151 ilUtil::delDir($this->getDraftsPath() . '/' . $this->getDraftId()); 152 return true; 153 } 154 155 /** 156 * 157 * Store uploaded files in filesystem 158 * 159 * @param array $files Copy of $_FILES array, 160 * @access public 161 * @return bool 162 * 163 */ 164 public function storeUploadedFile($files) 165 { 166 if (isset($files['name']) && is_array($files['name'])) { 167 foreach ($files['name'] as $index => $name) { 168 // remove trailing '/' 169 while (substr($name, -1) == '/') { 170 $name = substr($name, 0, -1); 171 } 172 $filename = ilUtil::_sanitizeFilemame($name); 173 $temp_name = $files['tmp_name'][$index]; 174 $error = $files['error'][$index]; 175 176 if (strlen($filename) && strlen($temp_name) && $error == 0) { 177 $path = $this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $filename; 178 179 $this->__rotateFiles($path); 180 ilUtil::moveUploadedFile($temp_name, $filename, $path); 181 } 182 } 183 184 return true; 185 } elseif (isset($files['name']) && is_string($files['name'])) { 186 // remove trailing '/' 187 while (substr($files['name'], -1) == '/') { 188 $files['name'] = substr($files['name'], 0, -1); 189 } 190 $filename = ilUtil::_sanitizeFilemame($files['name']); 191 $temp_name = $files['tmp_name']; 192 193 $path = $this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $filename; 194 195 $this->__rotateFiles($path); 196 ilUtil::moveUploadedFile($temp_name, $filename, $path); 197 198 return true; 199 } 200 201 return false; 202 } 203 /** 204 * unlink files: expects an array of filenames e.g. array('foo','bar') 205 * @param array filenames to delete 206 * @access public 207 * @return string error message with filename that couldn't be deleted 208 */ 209 public function unlinkFiles($a_filenames) 210 { 211 if (is_array($a_filenames)) { 212 foreach ($a_filenames as $file) { 213 if (!$this->unlinkFile($file)) { 214 return $file; 215 } 216 } 217 } 218 return ''; 219 } 220 /** 221 * unlink one uploaded file expects a filename e.g 'foo' 222 * @param string filename to delete 223 * @access public 224 * @return bool 225 */ 226 public function unlinkFile($a_filename) 227 { 228 if (file_exists($this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $a_filename)) { 229 return unlink($this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $a_filename); 230 } 231 } 232 /** 233 * get absolute path of filename 234 * @param string relative path 235 * @access public 236 * @return string absolute path 237 */ 238 public function getAbsolutePath($a_path) 239 { 240 return $this->getDraftsPath() . '/' . $this->getDraftId(); 241 } 242 243 /** 244 * get file data of a specific attachment 245 * @param string md5 encrypted filename 246 * @access public 247 * @return array filedata 248 */ 249 public function getFileDataByMD5Filename($a_md5_filename) 250 { 251 $files = ilUtil::getDir($this->getDraftsPath() . '/' . $this->getDraftId()); 252 foreach ((array) $files as $file) { 253 if ($file['type'] == 'file' && md5($file['entry']) == $a_md5_filename) { 254 return array( 255 'path' => $this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $file['entry'], 256 'filename' => $file['entry'], 257 'clean_filename' => $file['entry'] 258 ); 259 } 260 } 261 262 return false; 263 } 264 265 /** 266 * get file data of a specific attachment 267 * @param string|array md5 encrypted filename or array of multiple md5 encrypted files 268 * @access public 269 * @return boolean status 270 */ 271 public function unlinkFilesByMD5Filenames($a_md5_filename) 272 { 273 $files = ilUtil::getDir($this->getDraftsPath() . '/' . $this->getDraftId()); 274 if (is_array($a_md5_filename)) { 275 foreach ((array) $files as $file) { 276 if ($file['type'] == 'file' && in_array(md5($file['entry']), $a_md5_filename)) { 277 unlink($this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $file['entry']); 278 } 279 } 280 281 return true; 282 } else { 283 foreach ((array) $files as $file) { 284 if ($file['type'] == 'file' && md5($file['entry']) == $a_md5_filename) { 285 return unlink($this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $file['entry']); 286 } 287 } 288 } 289 290 return false; 291 } 292 293 /** 294 * check if files exist 295 * @param array filenames to check 296 * @access public 297 * @return bool 298 */ 299 public function checkFilesExist($a_files) 300 { 301 if ($a_files) { 302 foreach ($a_files as $file) { 303 if (!file_exists($this->getDraftsPath() . '/' . $this->getDraftId() . '/' . $file)) { 304 return false; 305 } 306 } 307 return true; 308 } 309 return true; 310 } 311 312 // PRIVATE METHODS 313 public function __checkPath() 314 { 315 if (!@file_exists($this->getDraftsPath() . '/' . $this->getDraftId())) { 316 return false; 317 } 318 $this->__checkReadWrite(); 319 320 return true; 321 } 322 /** 323 * check if directory is writable 324 * overwritten method from base class 325 * @access private 326 * @return bool 327 */ 328 public function __checkReadWrite() 329 { 330 if (is_writable($this->getDraftsPath() . '/' . $this->getDraftId()) && is_readable($this->getDraftsPath() . '/' . $this->getDraftId())) { 331 return true; 332 } else { 333 $this->error->raiseError("Forum directory is not readable/writable by webserver", $this->error->FATAL); 334 } 335 } 336 /** 337 * init directory 338 * overwritten method 339 * @access public 340 * @return string path 341 */ 342 public function __initDirectory() 343 { 344 if (is_writable($this->getPath())) { 345 if (ilUtil::makeDirParents($this->getDraftsPath() . "/" . $this->getDraftId())) { 346 if (chmod($this->getDraftsPath() . "/" . $this->getDraftId(), 0755)) { 347 return true; 348 } 349 } 350 } 351 return false; 352 } 353 /** 354 * rotate files with same name 355 * recursive method 356 * @param string filename 357 * @access private 358 * @return bool 359 */ 360 public function __rotateFiles($a_path) 361 { 362 if (file_exists($a_path)) { 363 $this->__rotateFiles($a_path . ".old"); 364 return \ilFileUtils::rename($a_path, $a_path . '.old'); 365 } 366 return true; 367 } 368 369 /** 370 * @param $file $_GET['file'] 371 * @return bool|void 372 */ 373 public function deliverFile($file) 374 { 375 if (!$path = $this->getFileDataByMD5Filename($file)) { 376 return ilUtil::sendFailure($this->lng->txt('error_reading_file'), true); 377 } else { 378 return ilUtil::deliverFile($path['path'], $path['clean_filename']); 379 } 380 } 381 382 public function deliverZipFile() 383 { 384 $zip_file = $this->createZipFile(); 385 if (!$zip_file) { 386 ilUtil::sendFailure($this->lng->txt('error_reading_file'), true); 387 return false; 388 } else { 389 $post = ilForumPostDraft::newInstanceByDraftId($this->getDraftId()); 390 ilUtil::deliverFile($zip_file, $post->getPostSubject() . '.zip', '', false, true, false); 391 ilUtil::delDir($this->getDraftsPath() . '/drafts_zip/' . $this->getDraftId()); 392 exit(); 393 } 394 } 395 396 /** 397 * @return null|string 398 */ 399 public function createZipFile() 400 { 401 $filesOfDraft = $this->getFilesOfPost(); 402 if (count($filesOfDraft)) { 403 ksort($filesOfDraft); 404 405 ilUtil::makeDirParents($this->getDraftsPath() . '/drafts_zip/' . $this->getDraftId()); 406 $tmp_dir = $this->getDraftsPath() . '/drafts_zip/' . $this->getDraftId(); 407 foreach ($filesOfDraft as $file) { 408 @copy($file['path'], $tmp_dir . '/' . $file['name']); 409 } 410 } 411 412 $zip_file = null; 413 if (ilUtil::zip($tmp_dir, $this->getDraftsPath() . '/drafts_zip/' . $this->getDraftId() . '.zip')) { 414 $zip_file = $this->getDraftsPath() . '/drafts_zip/' . $this->getDraftId() . '.zip'; 415 } 416 417 return $zip_file; 418 } 419} 420