Table Of Contents
Safe Deletion Strategy
Here's how to delete files and directories with multiple safety checks:
<?php
// Safe file deletion with validation
function deleteFileSafely(string $filepath): bool {
// Validate file exists
if (!file_exists($filepath)) {
return true; // Already deleted
}
// Ensure it's actually a file, not a directory
if (!is_file($filepath)) {
throw new InvalidArgumentException("Path is not a file: $filepath");
}
// Check if file is writable (can be deleted)
if (!is_writable($filepath)) {
throw new RuntimeException("File is not writable/deletable: $filepath");
}
// Perform deletion
if (!unlink($filepath)) {
throw new RuntimeException("Failed to delete file: $filepath");
}
return true;
}
// Delete file with backup option
function deleteWithBackup(string $filepath, string $backupDir = 'trash'): bool {
if (!file_exists($filepath)) {
return true;
}
// Create backup directory if needed
if (!is_dir($backupDir)) {
mkdir($backupDir, 0755, true);
}
// Create backup filename with timestamp
$filename = basename($filepath);
$timestamp = date('Y-m-d_H-i-s');
$backupPath = $backupDir . DIRECTORY_SEPARATOR . $timestamp . '_' . $filename;
// Move to backup instead of permanent deletion
if (!rename($filepath, $backupPath)) {
throw new RuntimeException("Failed to move file to backup: $filepath");
}
return true;
}
// Safe directory deletion (recursive)
function deleteDirectorySafely(string $dirPath): bool {
if (!is_dir($dirPath)) {
return true; // Already deleted or doesn't exist
}
// Prevent deletion of critical system directories
$protectedPaths = ['/', '/usr', '/var', '/etc', '/home', '/root'];
$realPath = realpath($dirPath);
foreach ($protectedPaths as $protected) {
if (strpos($realPath, $protected) === 0 && strlen($realPath) <= strlen($protected) + 10) {
throw new RuntimeException("Attempted to delete protected directory: $dirPath");
}
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dirPath, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::CHILD_FIRST
);
// Delete all files and subdirectories
foreach ($iterator as $file) {
if ($file->isDir()) {
if (!rmdir($file->getRealPath())) {
throw new RuntimeException("Cannot delete directory: " . $file->getRealPath());
}
} else {
if (!unlink($file->getRealPath())) {
throw new RuntimeException("Cannot delete file: " . $file->getRealPath());
}
}
}
// Delete the main directory
if (!rmdir($dirPath)) {
throw new RuntimeException("Cannot delete main directory: $dirPath");
}
return true;
}
// Delete files older than specified days
function deleteOldFiles(string $directory, int $daysOld, string $pattern = '*'): array {
$deletedFiles = [];
$cutoffTime = time() - ($daysOld * 24 * 60 * 60);
$files = glob($directory . DIRECTORY_SEPARATOR . $pattern);
foreach ($files as $file) {
if (is_file($file) && filemtime($file) < $cutoffTime) {
try {
deleteFileSafely($file);
$deletedFiles[] = basename($file);
} catch (Exception $e) {
error_log("Failed to delete old file $file: " . $e->getMessage());
}
}
}
return $deletedFiles;
}
// Clean up temporary files
function cleanupTempFiles(array $tempDirs = ['tmp', 'temp', 'cache/temp']): array {
$cleaned = [];
foreach ($tempDirs as $dir) {
if (!is_dir($dir)) {
continue;
}
$files = glob($dir . DIRECTORY_SEPARATOR . '*');
foreach ($files as $file) {
if (is_file($file)) {
try {
deleteFileSafely($file);
$cleaned[] = $file;
} catch (Exception $e) {
error_log("Failed to clean temp file $file: " . $e->getMessage());
}
}
}
}
return $cleaned;
}
// Delete files by extension
function deleteFilesByExtension(string $directory, array $extensions): array {
$deletedFiles = [];
foreach ($extensions as $ext) {
$pattern = $directory . DIRECTORY_SEPARATOR . '*.' . ltrim($ext, '.');
$files = glob($pattern);
foreach ($files as $file) {
if (is_file($file)) {
try {
deleteFileSafely($file);
$deletedFiles[] = basename($file);
} catch (Exception $e) {
error_log("Failed to delete file $file: " . $e->getMessage());
}
}
}
}
return $deletedFiles;
}
// Secure deletion with multiple passes (basic)
function secureDelete(string $filepath): bool {
if (!file_exists($filepath) || !is_file($filepath)) {
return true;
}
$filesize = filesize($filepath);
$handle = fopen($filepath, 'r+b');
if (!$handle) {
throw new RuntimeException("Cannot open file for secure deletion: $filepath");
}
// Overwrite with random data (3 passes)
for ($pass = 0; $pass < 3; $pass++) {
fseek($handle, 0);
for ($i = 0; $i < $filesize; $i += 1024) {
$chunk = str_repeat(chr(random_int(0, 255)), min(1024, $filesize - $i));
fwrite($handle, $chunk);
}
fflush($handle);
}
fclose($handle);
// Final deletion
return deleteFileSafely($filepath);
}
// Batch delete with confirmation
function batchDelete(array $files, bool $requireConfirmation = true): array {
$results = ['deleted' => [], 'failed' => [], 'skipped' => []];
if ($requireConfirmation && !empty($files)) {
echo "About to delete " . count($files) . " files:\n";
foreach ($files as $file) {
echo " - $file\n";
}
echo "Continue? (y/N): ";
$confirmation = trim(fgets(STDIN));
if (strtolower($confirmation) !== 'y') {
$results['skipped'] = $files;
return $results;
}
}
foreach ($files as $file) {
try {
deleteFileSafely($file);
$results['deleted'][] = $file;
} catch (Exception $e) {
$results['failed'][] = ['file' => $file, 'error' => $e->getMessage()];
}
}
return $results;
}
// Usage examples
try {
// Delete single file safely
deleteFileSafely('unwanted.txt');
// Delete with backup
deleteWithBackup('important.txt', 'backup_folder');
// Delete entire directory
deleteDirectorySafely('old_project');
// Clean up old files (older than 30 days)
$deletedOld = deleteOldFiles('uploads', 30);
echo "Deleted " . count($deletedOld) . " old files\n";
// Clean temporary files
$cleanedTemp = cleanupTempFiles();
echo "Cleaned " . count($cleanedTemp) . " temporary files\n";
// Delete specific file types
$deletedLogs = deleteFilesByExtension('logs', ['log', 'tmp']);
echo "Deleted log files: " . implode(', ', $deletedLogs) . "\n";
// Secure delete sensitive file
secureDelete('sensitive_data.txt');
// Batch delete with confirmation
$filesToDelete = ['file1.txt', 'file2.txt', 'file3.txt'];
$batchResults = batchDelete($filesToDelete, false);
print_r($batchResults);
} catch (Exception $e) {
echo "Deletion error: " . $e->getMessage() . "\n";
}
Safety Measures
Safe file deletion requires multiple protection layers:
- Validation: Check file exists and is actually a file/directory
- Permissions: Verify write permissions before attempting deletion
- Protection: Prevent deletion of system-critical directories
- Backup Options: Move to trash/backup instead of permanent deletion
Critical Safety Checks:
- File/directory existence validation
- Permission verification
- Protected path prevention
- Error handling and logging
- Optional backup before deletion
Best Practices:
- Always validate before deletion
- Use backup/trash system for important files
- Log deletion operations
- Implement confirmation for batch operations
- Consider secure deletion for sensitive data
Essential for file cleanup, temporary file management, and safe data removal operations.
Share this article
Add Comment
No comments yet. Be the first to comment!