Pull to refresh

Удаление директории в PHP

Доброго времени суток, дорогие читатели. Сегодня хотелось бы поговорить на тему удаления директории в PHP. Казалось бы, что операция не является сложной, однако некоторые нюансы имеют место быть. Давайте рассмотрим способы, как можно это сделать.

В PHP для этого предусмотрена функция rmdir(). В качестве аргумента она принимает путь до директории, которую Вы хотите удалить. Однако, директория должна быть пустая — это главное условие (если не считать того, что у пользователя, от которого работает веб-сервер, должны быть права на запись для директории). Если в директории будут размещены файлы, то мы получим ошибку при вызове функции. Соответственно, приходим к выводу, что директорию перед использованием функции rmdir() необходимо предварительно очистить.

В сети советуют написать функцию, которой в качестве аргумента будет передаваться путь к директории, которую нам необходимо удалить. В теле функции необходимо организовать листинг содержимого директории, в рамках которого осуществляется проверка — является ли файл директорией. Если файл является директорией, то по данному условию функция вызывает себя. Это необходимо для зачистки вложенных директорий, и это будет работать на всех уровнях вложенности. В ином случае, для файла применяется функция unlink() — она предназначена для удаления файла. За рамками данной проверки на последнем шаге мы удаляем директорию.

Пример реализации:

function recursiveRemoveDir($dir) {

	$includes = glob($dir.'/*');

	foreach ($includes as $include) {

		if(is_dir($include)) {

			recursiveRemoveDir($include);
		}

		else {

			unlink($include);
		}
	}

	rmdir($dir);
}

//Удалим из текущей директории директорию tmp
recursiveRemoveDir('tmp');

Какие проблемы у данного кода?

В простых случаях директория со всеми вложениями удалится. Но предположим, что в нашей директории присутствует скрытый файл, который начинается с точки, например, .htaccess. Функция glob() представляет из себя glob-подстановку UNIX, в которой по умолчанию не участвуют скрытые файлы (DOTFILES). Например, если мы зайдем в nix-терминал и будем использовать bash, то мы столкнемся с той же проблемой (речь именно о скрытых файлах в рамках glob). Для решения вопроса в bash существует команда shopt -s dotglob — она разрешает glob-подстановку скрытых файлов. В PHP же это можно решить добавлением дополнительно параметра GLOB_BRACE для glob() и расширением паттерна из первого параметра функции.

$includes = glob('tmp/{,.}*', GLOB_BRACE);

И тут так же есть проблема — мы столкнемся с бесконечным циклом, так как в массив войдут значения . и .. — что является на системном уровне текущей и родительской директорией. Придем мы к бесконечному циклу (а не к удалению всех родительских директорий), потому что . в рамках сортировки по умолчанию в сформированном массиве будет первее .. — то есть каждый раз мы будет обращаться к одной и той же директории. Для решения проблемы сформируем массив из данных системных директорий и в цикле удалим их индексы из основного массива. Также существует проблема символьных ссылок. Допустим, что в удаляемой директории размещена ссылка на другую директорию, в удалении содержимого которой мы абсолютно не заинтересованы. Для решения проблемы, перед созданием рекурсии, необходимо организовать проверку на то, что сущность не является ссылкой.

В итоге, функция обретает следующий вид:

function recursiveRemoveDir($dir) {

	$includes = glob($dir.'/{,.}*', GLOB_BRACE);
	$systemDots = preg_grep('/\.+$/', $includes);

	foreach ($systemDots as $index => $dot) {
		
		unset($includes[$index]);
	}

	foreach ($includes as $include) {

		if(is_dir($include) && !is_link($include)) {

			recursiveRemoveDir($include);
		}

		else {

			unlink($include);
		}
	}

	rmdir($dir);
}

//Удалим из текущей директории директорию tmp
recursiveRemoveDir('tmp');

Код рабочий, но на самом деле можно было сделать и проще. В PHP существует класс FilesystemIterator, который уже по умолчанию имеет необходимые нам настройки. В конструктор передается путь до директории, листинг которой нам нужен. Нам достаточно просто создать объект.

function recursiveRemoveDir($dir) {

	$includes = new FilesystemIterator($dir);

	foreach ($includes as $include) {

		if(is_dir($include) && !is_link($include)) {

			recursiveRemoveDir($include);
		}

		else {

			unlink($include);
		}
	}

	rmdir($dir);
}


//Удалим из текущей директории директорию tmp
recursiveRemoveDir('tmp');

В заключение хотелось бы отметить еще один быстрый способ. Корректность его использования весьма сомнительна — отправить команду на выполнение в SHELL.

system("rm -rf tmp");

Обращаю внимание на высокий расход памяти и на то, что зачастую администраторы запрещают использовать на сервере такого рода функции в целях безопасности.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.