Limit the images that previews keep.

A preview that fails the captcha or the form token keeps no image. A session keeps one image, the directory has a size limit, and abandoned images go at the next upload.
This commit is contained in:
tim
2026-09-26 15:27:51 +02:00
parent fe30a0aaa1
commit c4fcef21aa
8 changed files with 215 additions and 42 deletions
+41 -1
View File
@@ -377,11 +377,22 @@ function is_upload_name($name) {
return is_string($name) && preg_match('/^[0-9a-f]{32}\z/', $name);
}
// Upload files older than this are abandoned previews
define('UPLOAD_MAX_AGE', 86400);
/*
* Move a file from $_FILES into the upload directory, and remember it
* in the session. Returns the new path, or FALSE.
* in the session. Returns the new path, or FALSE. A session keeps one
* upload: a new one replaces the last. Abandoned uploads are removed
* first, and nothing is kept if the directory would grow past
* UPLOAD_DIR_LIMIT_MB (100 MB by default).
*/
function store_upload($tmp_file) {
prune_uploads();
remove_pending_upload();
$limit = (float)config('UPLOAD_DIR_LIMIT_MB', 100) * 1024 * 1024;
if (upload_dir_size() + (int)@filesize($tmp_file) > $limit)
return FALSE;
$name = bin2hex(random_bytes(16));
$file = upload_dir() . '/' . $name;
if (!move_uploaded_file($tmp_file, $file))
@@ -390,6 +401,35 @@ function store_upload($tmp_file) {
return $file;
}
// The upload files, name => path; nothing else in the directory counts
function upload_files() {
$files = array();
foreach (glob(upload_dir() . '/*') ?: array() as $file) {
if (is_upload_name(basename($file)) && is_file($file))
$files[basename($file)] = $file;
}
return $files;
}
function upload_dir_size() {
return array_sum(array_map(function ($file) { return (int)@filesize($file); }, upload_files()));
}
// Remove the uploads that are older than UPLOAD_MAX_AGE
function prune_uploads() {
foreach (upload_files() as $file) {
if (@filemtime($file) < time() - UPLOAD_MAX_AGE)
@unlink($file);
}
}
// Remove the file of this session's upload, and forget it
function remove_pending_upload() {
if ($file = pending_upload())
@unlink($file);
unset($_SESSION['pending_upload']);
}
/*
* Return the path of the image this session uploaded earlier, or FALSE.
*/