diff --git a/get_data.lib.php b/get_data.lib.php index 5a62561..8d631b4 100644 --- a/get_data.lib.php +++ b/get_data.lib.php @@ -373,17 +373,30 @@ function upload_dir() { return $dir; } +/* + * A size in megabytes from the configuration, in bytes. An empty, missing + * or bad value, or one that is not above zero, gives $default_mb. + */ +function config_megabytes($key, $default_mb) { + $value = trim((string)config($key, '')); + if (!is_numeric($value) || (float)$value <= 0) + $value = $default_mb; + return (int)((float)$value * 1024 * 1024); +} + /* * The largest image a story can have, in bytes, from UPLOAD_MAX_MB (1 MB * by default). NULL means no limit, which UPLOAD_MAX_MB=none gives. */ function upload_max_bytes() { - $value = strtolower(trim((string)config('UPLOAD_MAX_MB', ''))); - if ($value === 'none') + if (strtolower(trim((string)config('UPLOAD_MAX_MB', ''))) === 'none') return NULL; - if (!is_numeric($value) || (float)$value <= 0) - $value = 1; - return (int)((float)$value * 1024 * 1024); + return config_megabytes('UPLOAD_MAX_MB', 1); +} + +// The most that the upload directory holds, in bytes, from UPLOAD_DIR_LIMIT_MB (100 MB by default) +function upload_dir_limit_bytes() { + return config_megabytes('UPLOAD_DIR_LIMIT_MB', 100); } // The same in megabytes for a message, such as "1" or "2.5" @@ -408,8 +421,7 @@ define('UPLOAD_MAX_AGE', 86400); 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) + if (upload_dir_size() + (int)@filesize($tmp_file) > upload_dir_limit_bytes()) return FALSE; $name = bin2hex(random_bytes(16)); $file = upload_dir() . '/' . $name; diff --git a/tests/php/Unit/UploadTest.php b/tests/php/Unit/UploadTest.php index 3b1c63f..e8196d6 100644 --- a/tests/php/Unit/UploadTest.php +++ b/tests/php/Unit/UploadTest.php @@ -136,6 +136,18 @@ class UploadTest extends TestCase { $this->assertSame(2 + 2 + 5, upload_dir_size()); } + public function testTheUploadDirLimitComesFromTheConfiguration(): void { + $this->setEnv('UPLOAD_DIR_LIMIT_MB', '2.5'); + $this->assertSame((int)(2.5 * 1024 * 1024), upload_dir_limit_bytes()); + } + + public function testAnEmptyOrBadUploadDirLimitMeansTheDefault(): void { + foreach (array('', ' ', 'lots', '0', '-2', 'none') as $value) { + $this->setEnv('UPLOAD_DIR_LIMIT_MB', $value); + $this->assertSame(100 * 1024 * 1024, upload_dir_limit_bytes(), "'$value'"); + } + } + public function testStoreUploadPrunesAndDropsTheLastUploadFirst(): void { $last = $this->pending(); $files = $this->others();