diff --git a/plugin/cleandeletedfiles/README.md b/plugin/cleandeletedfiles/README.md
new file mode 100644
index 0000000000..74d1c3604a
--- /dev/null
+++ b/plugin/cleandeletedfiles/README.md
@@ -0,0 +1,4 @@
+CleanDeleted Files Maintenance plugin
+===
+
+This plugin allows the administrator to permanently delete files marked as deleted
\ No newline at end of file
diff --git a/plugin/cleandeletedfiles/admin.php b/plugin/cleandeletedfiles/admin.php
new file mode 100644
index 0000000000..cebf8ac44b
--- /dev/null
+++ b/plugin/cleandeletedfiles/admin.php
@@ -0,0 +1,190 @@
+get_info();
+
+$isPlatformAdmin = api_is_platform_admin();
+
+if ($plugin->isEnabled() && $isPlatformAdmin) {
+ $htmlHeadXtra[] = '';
+
+ $nameTools = $plugin->get_lang("FileList");
+ Display::display_header($nameTools);
+ echo Display::page_header($nameTools);
+
+ $pathList = [
+ "app/courses",
+ "app/upload",
+ ];
+
+ function findDeletedFiles($pathRelative) {
+ global $sizePath;
+ $pathAbsolute = api_get_path(SYS_PATH).$pathRelative;
+ $result = [];
+ if (is_dir($pathAbsolute)) {
+ $dir = dir($pathAbsolute);
+ while ($file = $dir->read()) {
+ if (is_file($pathAbsolute.'/'.$file)) {
+ $filesize = round(filesize($pathAbsolute.'/'.$file)/1024, 1);
+ $pos = strpos($file, "DELETED");
+ if ($pos !== FALSE) {
+ $result[] = [
+ 'path_complete' => $pathAbsolute.'/'.$file,
+ 'path_relative' => $pathRelative.'/'.$file,
+ 'size' => $filesize,
+ ];
+ $sizePath += $filesize;
+ }
+ } else if ($file!='..' && $file!='.') {
+ $result = array_merge($result, findDeletedFiles($pathRelative.'/'.$file));
+ }
+ }
+ }
+ return $result;
+ }
+
+ $sizeTotal = 0;
+ $i = 0;
+ foreach ($pathList as $pathItem) {
+ $sizePath = 0;
+ $filesDeletedList = findDeletedFiles($pathItem);
+ echo Display::page_subheader($plugin->get_lang("path_dir").": ".$pathItem);
+
+ if (count($filesDeletedList) > 0) {
+ echo "
";
+ echo "- ".$plugin->get_lang('FilesDeletedMark').": ".count($filesDeletedList)."";
+ echo "
- ".$plugin->get_lang('FileDirSize').": ";
+ if ($sizePath >= 1024) {
+ echo "".round($sizePath/1024,1)." Mb";
+ } else {
+ echo "".$sizePath." Kb";
+ }
+ echo "
";
+
+ $header = [
+ [
+ '',
+ false,
+ null,
+ ['style' => 'text-align:center']
+ ],
+ [$plugin->get_lang('path_dir'), true],
+ [$plugin->get_lang('size'), true, null, ['style' => 'min-width:85px']],
+ [get_lang('Actions'), false],
+ ];
+
+ $data = [];
+ $deleteIcon = Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL);
+
+ foreach ($filesDeletedList as $value) {
+ $tools = Display::url(
+ $deleteIcon,
+ 'file://'.$value['path_complete'],
+ ['class' => 'delete-file']
+ );
+
+ $row = [
+ '',
+ $value['path_relative'],
+ $value['size'].' '.($value['size'] >= 1024 ? 'Mb' : 'Kb'),
+ $tools
+ ];
+ $data[] = $row;
+ }
+
+ echo Display::return_sortable_table(
+ $header,
+ $data,
+ [],
+ ['per_page' => 100],
+ []
+ );
+ } else {
+ $message = $plugin->get_lang('NoFilesDeleted');
+ echo Display::return_message($message, 'warning', false);
+ }
+ $sizeTotal += $sizePath;
+ echo '
';
+ $i++;
+ }
+
+ if ($sizeTotal >= 1024) {
+ echo $plugin->get_lang('SizeTotalAllDir').": ".round($sizeTotal/1024,1).' Mb';
+ } else {
+ echo $plugin->get_lang('SizeTotalAllDir').": ".$sizeTotal.' Kb';
+ }
+ echo '
';
+ echo ''.
+ $plugin->get_lang("DeleteSelectedFiles").
+ '';
+
+ Display::display_footer();
+}
diff --git a/plugin/cleandeletedfiles/config.php b/plugin/cleandeletedfiles/config.php
new file mode 100644
index 0000000000..672c5b443e
--- /dev/null
+++ b/plugin/cleandeletedfiles/config.php
@@ -0,0 +1,10 @@
+get_info();
diff --git a/plugin/cleandeletedfiles/src/CleanDeletedFilesPlugin.php b/plugin/cleandeletedfiles/src/CleanDeletedFilesPlugin.php
new file mode 100644
index 0000000000..072fb20820
--- /dev/null
+++ b/plugin/cleandeletedfiles/src/CleanDeletedFilesPlugin.php
@@ -0,0 +1,35 @@
+ 'boolean']);
+ $this->isAdminPlugin = true;
+ }
+
+ /**
+ * @return RedirectionPlugin
+ */
+ public static function create()
+ {
+ static $result = null;
+
+ return $result ? $result : $result = new self();
+ }
+}
diff --git a/plugin/cleandeletedfiles/src/ajax.php b/plugin/cleandeletedfiles/src/ajax.php
new file mode 100644
index 0000000000..56102cfbc6
--- /dev/null
+++ b/plugin/cleandeletedfiles/src/ajax.php
@@ -0,0 +1,46 @@
+ "false", "message"=>$plugin->get_lang('ErrorEmptyPath')]);
+ exit;
+ }
+
+ if (unlink($path)) {
+ Display::addFlash($plugin->get_lang("DeletedSuccess"), 'success');
+ echo json_encode(["status" => "true"]);
+ } else {
+ echo json_encode(["status" => "false", "message"=>$plugin->get_lang('ErrorDeleteFile')]);
+ }
+ break;
+ case 'delete-files-list':
+ $list = isset($_REQUEST['list']) ? $_REQUEST['list'] : [];
+ if (empty($list)) {
+ echo json_encode(["status" => "false", "message"=>$plugin->get_lang('ErrorEmptyPath')]);
+ exit;
+ }
+
+ foreach ($list as $value) {
+ if (empty($value)) {
+ continue;
+ }
+ unlink($value);
+ }
+
+ Display::addFlash($plugin->get_lang("DeletedSuccess"), 'success');
+ echo json_encode(["status" => "true"]);
+ break;
+}
\ No newline at end of file