Удаление старых изображений. Плагинчик.

По мотивам вот этого топика написал плагин, который удаляет старые, неиспользуемые, изображения.
В отличии от предыдущего скрипта, мой использует Ajax, так что количество файлов в папке не на что не влияет.

Установка: создаем плагин, вставляем код, ставим галочку в системных событиях на «OnPageNotFound». Далее в браузере пишем: site.com/clean_image, жмякаем на «Просканировать и удалить». Дожидаемся окончания работы скрипта.

Скрипт не идеальный, но вродь работает)
Логика скрипта проста: сначала собираем массив файлов, потом проверяем упоминание в основных таблицах: в шаблонах, в контенте, в чанках, в ТВшках. Если упоминание есть — значит файл используется. Если нет — удаляем.

//<?php
	if ($_REQUEST['q']=='clean_image')
	{
			
		if ((!isset($_GET['num'])) and ($_SESSION['files'])) unset($_SESSION['files']);		
		
		$dir = "assets/images"; // относительный путь
		$fullpath = MODX_BASE_PATH.$dir; // Полный путь
		
		function GetListFiles($folder,&$all_files,$ldir)
		{
			$fp=opendir($folder);
			while($cv_file=readdir($fp)) {
				if(is_file($folder."/".$cv_file)) {
					$all_files[]=str_replace(MODX_BASE_PATH,'',$folder."/".$cv_file);
					}elseif($cv_file!="." && $cv_file!=".." && is_dir($folder."/".$cv_file)){
					GetListFiles($folder."/".$cv_file,$all_files,$ldir);
				}
			}
			closedir($fp);
		}
		if (!$_SESSION['files']) 
		{
			$all_files=array();
			GetListFiles($fullpath,$all_files,$dir);
			$_SESSION['files'] = $all_files;
		}
	
		$cf = count($_SESSION['files']);
		$num = $_GET['num'];
		
		if ((isset($num)) and ($cf>$_GET['num']))
		{
			
			$file = $_SESSION['files'][$num];
			$num = $num + 1;
			$c = 0;
			// Content
			$c = $modx->db->getValue('select count(*) from '.$modx->getFullTableName('site_content').' where `content` like "%'.$file.'%" and `deleted`=0');
			if ($c>0)
			{
				echo $num;
				exit();
			}
			
			// TV
			$fmtv = str_replace('/','\/',$file); // fix for multiTV
			$c = $modx->db->getValue('select count(*) from '.$modx->getFullTableName('site_tmplvar_contentvalues').' where `value` like "%'.$file.'%" or `value` like "%'.$fmtv.'%"');
			if ($c>0)
			{
				echo $num;
				exit();
			}
			
			// Chunks
			$c = $modx->db->getValue('select count(*) from '.$modx->getFullTableName('site_htmlsnippets').' where `snippet` like "%'.$file.'%"');
			if ($c>0)
			{
				echo $num;
				exit();
			}
			
			// Templates
			$c = $modx->db->getValue('select count(*) from '.$modx->getFullTableName('site_templates').' where `content` like "%'.$file.'%"');
			if ($c>0)
			{
				echo $num;
				exit();
			}			
			
			// Удаление фотографии
			//if (file_exists($file)) $d = unlink($file);
			
			echo $num.'|'.$file;
			exit();
		}
	?>		
	<html>
		<head>
			<title>Удаление старых фотографий</title>
		</head>
		<body>
			<h2>Удаление старых фотографий</h2>
			<? if (isset($_POST[files])) 
				{
					$cdf = 0;
					foreach ($_POST[files] as $file) 
					{
						if (file_exists($file)) 
						{
							$d = unlink($file);
							$cdf++;
						}
					}
					echo '<p>Количество удаленных файлов - <b>'.$cdf.'</b></p>';
				}
				else
				{
					echo '<p>Обработка фотографий <span id="cur_step">0</span> из <span id="count_all">'.$cf.'</span></p>';				
				
				}
			?>
			
			
			<p style="color:green;" id="succes"></p>
			<div id="files" style="display:none;">
				<p><b>Удалить следующие файлы:</b></p>
				<form method="post">
				<ul></ul>
					<input type="submit" value="удалить">
				</form>
			</div>
			<form method="get" id="removeImage" action="clean_image">
				<input type="hidden" name="num" value="0" id="num">
				<input type="submit" value="Начать сканирование" id="removeImageButton">
			</form>
			
			<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
			<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
			<script>
				$(function(){
					$(document).on("submit","#removeImage",function(e){
						e.preventDefault();	
						$('#removeImageButton').hide();
						removeImage();
					});
					function removeImage()
					{
						
						var m_method=$('#removeImage').attr('method');
						var m_action=$('#removeImage').attr('action');
						var m_data=$('#removeImage').serialize();
						
						$.ajax({
							type: m_method,
							url: m_action,
							data: m_data,
							resetForm: 'true',
							success: function(result)
							{
								//console.log(result);
				
								var count_all = parseInt($('#count_all').html());
								res = result.split('|');
								
								var cur_step = res[0];
								var del = parseInt($('#del').html());
								
								if (res[1])
								{
									del = del + 1;
									$('#files').show();
									$('#files ul').append('<li><label><input type="checkbox" name="files[]" value="'+res[1]+'" checked="checked"><a href="'+res[1]+'" target="_blank">'+res[1]+'</a></label></li>');
								}
				
								$('#del').html(del);
								
								$('#num').val(cur_step);
								$('#cur_step').html(cur_step);
								if (count_all>cur_step) removeImage();				
								else 
								{
									$('#succes').html('Сканирование успешно завершено!');
									
								}
							}
						});
					}
				});
			</script>
		</body>
	</html>
	<?
	exit();
	}					

P.S. Все действия производятся на свой страх и риск. Автор поста не несет ответственности за случайное удаление нужных фотографий. Ну и перед чисткой делайте бэкап)

UPD: Добавил возможность выбора удаляемых файлов с помощью checkbox-ов, и сделал небольшой фикс для мультиТВ, ибо как выяснилось он иногда как-то странно пути пишет.

17 комментариев

avatar
Отличное дополнение, обязательно воспользуюсь.
Ещё бы сделал одну доработку — файлы не удалять, а складывать в отдельную папку и рядом класть файлик текстовый — с путями всех «удаляемых» файлов.
Это позволит увидеть все неиспользуемые файлы, которые можно как удалить, так и сделать бекап если могут понадобиться в будущем. Как вариант подобное реализовать выбором галочки перед удалением.
avatar
Ну можно просто закомментить 74-ую строчку, тогда список будет выведен, а удаление производится не будет. Ну а так, я с дичайшего похмелья, поэтому в таком вот, полусыром виде) На счет галочек — в принципе можно дописать, но уже завтра тогда. Там три строчки по-сути дописать надо)
avatar
Нет смысла. Перед удалением в любом случае надо бэкапиться.
И лучше это делать другим инструментом, чтобы 100% быть уверенным в результате.
avatar
Когда же вы уже начитиесь писать емкие скрипты под CLI, а не извращаться с ajax
avatar
всему свое время)
avatar
А если файл прописан в CSS?)
avatar
ручками))) или вы храните все картинки в css? :D
avatar
я имел ввиду, например, фон страницы. он прописывается жестко в css

плагин же его удалит, если его в тв нету
avatar
а зачем хранить файлы дизайна в папке images? для этого есть отдельный каталог — templates, в который данный плагин не смотрит и собственно ничего не удалит.
avatar
логично. про templates как-то не задумывался, обычно все картинки (и оформление в частности) в images лежат
avatar
:) лучше перенести в templates и не давать доступа менеджеру к элементам дизайна.
avatar
Это же жутко неудобно, когда картинки дизайна вдруг видимы в браузере для менеджеров?

Лично я не пользуюсь /assets/templates потому что у 100% моих сайтов дизайн заменяется или натягивается только целиком, папки в корне /css /img /js не мешают
avatar
а кто сказал, что менеджет может смотреть в папку templates. По дефолту файловый менеджер смотрит в корень папки images
avatar
Не может. В папку images — может. Я про /assets/images говорил
avatar
Плагин нужный и полезный, ещё думаю нужна проверка поля Веб-ссылка (если например там ссылка на картинку идёт). Этим плагином можно файлы неиспользуемые удалить если путь assets/images заменить на assets/files?
avatar
а по логике эти поля и проверяются, в самом плагине поиск по таблицам)

модифицируйте на свой страх и риск :D
avatar
Вы забыли $_POST[files] кавычки в двух местах.
Надо $_POST['files']
И заработало)
Комментарий отредактирован 2023-02-21 09:44:37 пользователем isadovskiy
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.