Safe Directory Cleaner
Deletes old temporary files according to extension, age, and path safety rules.
Function signature
ogCleanOldDirectoryFiles(base_path, options = array())
Categories
- File and Upload Safety
Parameters
base_pathApproved root directory used to keep path operations contained.optionsOptional policy, formatting, or behavior controls for this helper. Recognized keys: `age_seconds`, `allowed_extensions`, `delete`.Return value
Public-safe status string returned by the function.
- success
- message
- data
Compatibility
Existing function name, slug, path, and call order preserved; advertised metadata corrected to the actual source behavior.
Minimum PHP version: 7.4
Security notes
Use caller-owned allowlists and procedural mysqli prepared execution where SQL plans are returned; validate file paths, MIME policies, and permissions before file or download workflows.
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Deletes old temporary files according to extension, age, and path safety rules.
*
* Primary use case: Cache/temp cleanup jobs.
* Typical inputs: directory, age limit, allowed extensions.
* Typical output: cleanup report.
*
* Implementation note: Never accept arbitrary user paths.
*
* @return array Structured result data with success, message, and data keys.
*/
function ogCleanOldDirectoryFiles($base_path, $options = array()) {
$result = array(
'success' => false,
'message' => '',
'data' => array()
);
$base_path = (string)$base_path;
if (!is_array($options)) {
$options = array();
}
$base_real = realpath($base_path);
if ($base_real === false || !is_dir($base_real)) {
$result['message'] = 'Approved cleanup directory is missing.';
return $result;
}
$age_seconds = 86400;
if (!empty($options['age_seconds'])) {
$age_seconds = (int)$options['age_seconds'];
}
if ($age_seconds < 300) {
$age_seconds = 300;
}
$allowed_extensions = array('tmp', 'cache', 'log');
if (!empty($options['allowed_extensions']) && is_array($options['allowed_extensions'])) {
$allowed_extensions = array();
foreach ($options['allowed_extensions'] as $extension) {
$extension = strtolower(trim((string)$extension, '. '));
if (!empty($extension) && preg_match('/^[a-z0-9]+$/', $extension)) {
$allowed_extensions[] = $extension;
}
}
}
$delete_files = false;
if (!empty($options['delete']) && $options['delete'] === true) {
$delete_files = true;
}
$now = time();
$deleted = array();
$candidates = array();
$skipped = array();
$entries = scandir($base_real);
if ($entries === false) {
$result['message'] = 'Cleanup directory could not be scanned.';
return $result;
}
foreach ($entries as $entry) {
if ($entry == '.' || $entry == '..') {
continue;
}
$file_path = $base_real . DIRECTORY_SEPARATOR . $entry;
if (is_link($file_path) || !is_file($file_path)) {
$skipped[] = $entry;
continue;
}
$extension = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));
if (!in_array($extension, $allowed_extensions, true)) {
continue;
}
$modified = filemtime($file_path);
if ($modified === false || $modified > ($now - $age_seconds)) {
continue;
}
$candidates[] = $entry;
if ($delete_files) {
if (unlink($file_path)) {
$deleted[] = $entry;
} else {
$skipped[] = $entry;
}
}
}
$result['success'] = true;
if ($delete_files) {
$result['message'] = 'Directory cleanup completed.';
} else {
$result['message'] = 'Directory cleanup dry run completed.';
}
$result['data'] = array(
'base_path' => $base_real,
'dry_run' => !$delete_files,
'candidate_count' => count($candidates),
'deleted_count' => count($deleted),
'candidates' => $candidates,
'deleted' => $deleted,
'skipped' => $skipped
);
return $result;
}