19declare(strict_types=1);
37 if (!defined(
'MAILPATH')) {
38 define(
'MAILPATH',
'mail');
42 $this->
ilias = $DIC[
'ilias'];
43 $this->db =
$DIC->database();
44 $this->tmp_directory =
$DIC->filesystem()->temp();
45 $this->storage_directory =
$DIC->filesystem()->storage();
53 if (is_writable($this->
getPath())
70 $max_size = $this->
ilias->getSetting(
'mail_maxsize_attach',
'');
71 if ($max_size ===
'') {
75 return (
float) $this->
ilias->getSetting(
'mail_maxsize_attach',
'0') * 1024;
85 return $this->mail_path .
'/' . $this->user_id .
'_';
94 $res = $this->db->queryF(
95 'SELECT path FROM mail_attachment WHERE mail_id = %s',
100 if ($this->db->numRows(
$res) !== 1) {
101 throw new OutOfBoundsException();
104 $row = $this->db->fetchAssoc(
$res);
106 $relative_path = $row[
'path'];
110 foreach ($files as $file) {
111 if ($file[
'type'] ===
'file' && md5($file[
'entry']) === $md5FileHash) {
113 'path' => $this->
getMailPath() .
'/' . $relative_path .
'/' . $file[
'entry'],
114 'filename' => $file[
'entry'],
119 throw new OutOfBoundsException();
125 $query = $this->db->query(
126 'SELECT path FROM mail_attachment WHERE mail_id = ' . $this->db->quote($mail_id,
'integer')
129 while ($row = $this->db->fetchObject($query)) {
140 if (is_readable(
$path)) {
152 foreach ($a_attachments as $file) {
154 if (!copy(
$path, $this->
getMailPath() .
'/' . $this->user_id .
'_' . $file)) {
155 return 'ERROR: ' . $this->
getMailPath() .
'/' . $this->user_id .
'_' . $file .
' cannot be created';
164 if (is_writable($this->mail_path) && is_readable($this->mail_path)) {
168 $this->
ilias->raiseError(
169 'Mail directory is not readable/writable by webserver: ' .
171 $this->
ilias->error_obj->FATAL
182 return $this->getUnsentFiles();
188 private function getUnsentFiles(): array
192 $iter =
new RegexIterator(
new DirectoryIterator($this->mail_path),
"/^{$this->user_id}_(.+)$/");
193 foreach ($iter as $file) {
195 if (!$file->isFile()) {
199 [$uid, $rest] = explode(
'_', $file->getFilename(), 2);
200 if ($uid === (
string) $this->user_id) {
203 'size' => $file->getSize(),
204 'ctime' => $file->getCTime(),
215 throw new DomainException(
217 'Mail upload limit reached for user with id %s',
226 $abs_path = $this->
getMailPath() .
'/' . $this->user_id .
'_' . $name;
228 $fp = fopen($abs_path,
'wb+');
229 if (!is_resource($fp)) {
230 throw new RuntimeException(
232 'Could not read file: %s',
238 if (fwrite($fp, $a_content) ===
false) {
240 throw new RuntimeException(
242 'Could not write file: %s',
265 $this->
getMailPath() .
'/' . $this->user_id .
'_' . $file[
'name']
268 return $file[
'name'];
273 @copy($a_abs_path, $this->
getMailPath() .
'/' . $this->user_id .
'_' . $a_new_name);
280 if (is_file($a_path)) {
293 foreach ($a_filenames as $file) {
304 if (is_file($this->mail_path .
'/' . basename($this->user_id .
'_' . $a_filename))) {
305 return unlink($this->mail_path .
'/' . basename($this->user_id .
'_' . $a_filename));
324 public function saveFiles(
int $a_mail_id, array $a_attachments): void
326 if (!is_numeric($a_mail_id) || $a_mail_id < 1) {
327 throw new InvalidArgumentException(
'The passed mail_id must be a valid integer!');
330 foreach ($a_attachments as $attachment) {
331 $this->
saveFile($a_mail_id, $attachment);
337 static $fsstorage_cache = [];
339 $fsstorage_cache[$a_mail_id][$a_usr_id] =
new ilFSStorageMail($a_mail_id, $a_usr_id);
341 return $fsstorage_cache[$a_mail_id][$a_usr_id];
347 public function saveFile(
int $a_mail_id,
string $a_attachment): bool
358 $this->mail_path .
'/' . $this->user_id .
'_' . $a_attachment,
368 if ($a_files !== []) {
369 foreach ($a_files as $file) {
370 if (!is_file($this->mail_path .
'/' . $this->user_id .
'_' . $file)) {
382 $this->db->manipulateF(
384 INSERT INTO mail_attachment
385 ( mail_id, path) VALUES (%s, %s)',
387 [$a_mail_id, $storage->getRelativePathExMailDirectory()]
393 $res = $this->db->query(
394 'SELECT path FROM mail_attachment WHERE mail_id = ' . $this->db->quote($a_mail_id,
'integer')
398 while ($row = $this->db->fetchObject(
$res)) {
399 $path = (string) $row->path;
403 $res = $this->db->query(
404 'SELECT COUNT(mail_id) count_mail_id FROM mail_attachment WHERE path = ' .
405 $this->db->quote(
$path,
'text')
409 while ($row = $this->db->fetchObject(
$res)) {
410 $cnt_mail_id = (
int) $row->count_mail_id;
413 if ($cnt_mail_id === 1) {
418 $this->db->manipulateF(
419 'DELETE FROM mail_attachment WHERE mail_id = %s',
438 $umf = ini_get(
'upload_max_filesize');
440 $pms = ini_get(
'post_max_size');
443 $multiplier_a = [
'K' => 1024,
'M' => 1024 * 1024,
'G' => 1024 * 1024 * 1024];
445 $umf_parts = preg_split(
451 $pms_parts = preg_split(
458 if ((is_countable($umf_parts) ? count($umf_parts) : 0) === 2) {
459 $umf = (float) $umf_parts[0] * $multiplier_a[$umf_parts[1]];
461 if ((is_countable($pms_parts) ? count($pms_parts) : 0) === 2) {
462 $pms = (float) $pms_parts[0] * $multiplier_a[$pms_parts[1]];
466 $max_filesize = min($umf, $pms);
468 if (!$max_filesize) {
469 $max_filesize = max($umf, $pms);
472 $this->mail_max_upload_file_size = (
int) $max_filesize;
475 public function onUserDelete(): void
479 $iter =
new RegexIterator(
481 '/^' . $this->user_id .
'_/'
483 foreach ($iter as $file) {
485 if ($file->isFile()) {
486 @unlink($file->getPathname());
489 }
catch (Exception) {
494 SELECT DISTINCT(ma1.path)
495 FROM mail_attachment ma1
497 ON mail.mail_id = ma1.mail_id
498 WHERE mail.user_id = %s
499 AND (SELECT COUNT(tmp.path) FROM mail_attachment tmp WHERE tmp.path = ma1.path) = 1
501 $res = $this->db->queryF(
506 while ($row = $this->db->fetchAssoc(
$res)) {
509 $iter =
new RecursiveIteratorIterator(
510 new RecursiveDirectoryIterator(
$path),
511 RecursiveIteratorIterator::CHILD_FIRST
513 foreach ($iter as $file) {
515 if ($file->isDir()) {
516 @rmdir($file->getPathname());
518 @unlink($file->getPathname());
522 }
catch (Exception) {
527 $this->db->manipulateF(
534 WHERE mail.user_id = %s AND mail.mail_id = mail_attachment.mail_id
549 bool $is_draft =
false
560 if ($download_filename ===
'') {
561 $download_filename =
'attachments';
565 $relative_processing_directory = basename($processing_directory);
567 $absolute_zip_directory = $processing_directory .
'/' . $download_filename;
568 $relative_zip_directory = $relative_processing_directory .
'/' . $download_filename;
570 $this->tmp_directory->createDir($relative_zip_directory);
574 $source = str_replace(
583 $source = str_replace(
'//',
'/', $source);
584 if (!$this->storage_directory->has($source)) {
588 $target = $relative_zip_directory .
'/' .
$filename;
590 $stream = $this->storage_directory->readStream($source);
591 $this->tmp_directory->writeStream($target, $stream);
594 $path_to_zip_file = $processing_directory .
'/' . $download_filename .
'.zip';
597 $this->tmp_directory->deleteDir($relative_zip_directory);
600 $processing_directory .
'/' . $download_filename .
'.zip',
getAbsoluteAttachmentPoolPathPrefix()
deleteAttachmentDirectory(string $a_rel_path)
__construct(public int $user_id=0)
unlinkFiles(array $a_filenames)
static getStorage(int $a_mail_id, int $a_usr_id)
getAttachmentPath(string $a_filename, int $a_mail_id)
storeUploadedFile(array $file)
Filesystem $storage_directory
saveFile(int $a_mail_id, string $a_attachment)
Save attachment file in a specific mail directory .../mail/<calculated_path>/mail_<mail_id>_<user_id>...
checkFilesExist(array $a_files)
unlinkFile(string $a_filename)
assignAttachmentsToDirectory(int $a_mail_id, int $a_sent_mail_id)
Filesystem $tmp_directory
saveFiles(int $a_mail_id, array $a_attachments)
Saves all attachment files in a specific mail directory .../mail/<calculated_path>/mail_<mail_id>_<us...
getAttachmentPathByMailId(int $mail_id)
deassignAttachmentFromDirectory(int $a_mail_id)
int $mail_max_upload_file_size
deliverAttachmentsAsZip(string $basename, int $mail_id, array $files=[], bool $is_draft=false)
copyAttachmentFile(string $a_abs_path, string $a_new_name)
adoptAttachments(array $a_attachments, int $a_mail_id)
getAbsoluteAttachmentPoolPathByFilename(string $filename)
Resolves a path for a passed filename in regards of a user's mail attachment pool,...
initAttachmentMaxUploadSize()
storeAsAttachment(string $a_filename, string $a_content)
getAttachmentsTotalSizeLimit()
getAttachmentPathAndFilenameByMd5Hash(string $md5FileHash, int $mail_id)
rotateFiles(string $a_path)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static deliverFileAttached(string $path_to_file, ?string $download_file_name=null, ?string $mime_type=null, bool $delete_file=false)
static getASCIIFilename(string $a_filename)
static getDir(string $a_dir, bool $a_rec=false, ?string $a_sub_dir="")
get directory
static zip(string $a_dir, string $a_file, bool $compress_content=false)
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static rename(string $a_source, string $a_target)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static getValidFilename(string $a_filename)
static _sanitizeFilemame(string $a_filename)
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
The filesystem interface provides the public interface for the Filesystem service API consumer.
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
Interface Observer \BackgroundTasks Contains several chained tasks and infos about them.
Class ilObjForumAdministration.
PREG_SPLIT_NO_EMPTY PREG_SPLIT_DELIM_CAPTURE