FEATURE - Added maximum upload file size by type

This support is on both an instance level and a global default level.
This commit is contained in:
Turnerj 2015-03-31 21:57:32 +10:30
parent 43f49e8434
commit ae8dbe309b
3 changed files with 167 additions and 10 deletions

View File

@ -148,6 +148,16 @@ NOTE: this only sets the configuration for your UploadField, this does NOT chang
$this->getValidator()->setAllowedMaxFileSize($size);
```
You can also specify a default global maximum file size setting in your config for different file types. This is overridden when specifying the max allowed file size on the UploadField instance.
```yaml
Upload_Validator:
default_max_file_size:
'[image]': '1m'
'[doc]': '5m'
'jpeg': 2000
```
### Preview dimensions
Set the dimensions of the image preview. By default the max width is set to 80 and the max height is set to 60.
@ -297,6 +307,19 @@ Certain default values for the above can be configured using the YAML config sys
The above settings can also be set on a per-instance basis by using `setConfig` with the appropriate key.
The `Upload_Validator` class has configuration options for setting the `default_max_file_size`.
```yaml
Upload_Validator:
default_max_file_size:
'[image]': '1m'
'[doc]': '5m'
'jpeg': 2000
```
You can specify the file extension or the app category (as specified in the `File` class) in square brackets. It supports setting the file size in bytes or using the syntax supported by `File::ini2bytes()`.
You can also configure the underlying `[api:Upload]` class, by using the YAML config system.
```yaml

View File

@ -305,6 +305,16 @@ class Upload extends Controller {
*/
class Upload_Validator {
/**
* Contains a list of the max file sizes shared by
* all upload fields. This is then duplicated into the
* "allowedMaxFileSize" instance property on construct.
*
* @config
* @var array
*/
private static $default_max_file_size = array();
/**
* Information about the temporary file produced
* by the PHP-runtime.
@ -360,22 +370,46 @@ class Upload_Validator {
* @return int Filesize in bytes
*/
public function getAllowedMaxFileSize($ext = null) {
// Check if there is any defined instance max file sizes
if (empty($this->allowedMaxFileSize)) {
// Set default max file sizes if there isn't
$fileSize = Config::inst()->get('Upload_Validator', 'default_max_file_size');
if (isset($fileSize)) {
$this->setAllowedMaxFileSize($fileSize);
} else {
// When no default is present, use maximum set by PHP
$maxUpload = File::ini2bytes(ini_get('upload_max_filesize'));
$maxPost = File::ini2bytes(ini_get('post_max_size'));
$this->setAllowedMaxFileSize(min($maxUpload, $maxPost));
}
}
$ext = strtolower($ext);
if(isset($ext) && isset($this->allowedMaxFileSize[$ext])) {
return $this->allowedMaxFileSize[$ext];
if ($ext) {
if (isset($this->allowedMaxFileSize[$ext])) {
return $this->allowedMaxFileSize[$ext];
}
$category = File::get_app_category($ext);
if ($category && isset($this->allowedMaxFileSize['[' . $category . ']'])) {
return $this->allowedMaxFileSize['[' . $category . ']'];
}
return false;
} else {
return (isset($this->allowedMaxFileSize['*'])) ? $this->allowedMaxFileSize['*'] : false;
}
}
/**
* Set filesize maximums (in bytes).
* Set filesize maximums (in bytes or INI format).
* Automatically converts extensions to lowercase
* for easier matching.
*
* Example:
* <code>
* array('*' => 200, 'jpg' => 1000)
* array('*' => 200, 'jpg' => 1000, '[doc]' => '5m')
* </code>
*
* @param array|int $rules
@ -384,7 +418,22 @@ class Upload_Validator {
if(is_array($rules) && count($rules)) {
// make sure all extensions are lowercase
$rules = array_change_key_case($rules, CASE_LOWER);
$this->allowedMaxFileSize = $rules;
$finalRules = array();
$tmpSize = 0;
foreach ($rules as $rule => $value) {
if (is_numeric($value)) {
$tmpSize = $value;
} else {
$tmpSize = File::ini2bytes($value);
}
$finalRules[$rule] = (int)$tmpSize;
}
$this->allowedMaxFileSize = $finalRules;
} elseif(is_string($rules)) {
$this->allowedMaxFileSize['*'] = File::ini2bytes($rules);
} elseif((int) $rules > 0) {
$this->allowedMaxFileSize['*'] = (int)$rules;
}

View File

@ -83,16 +83,101 @@ class UploadTest extends SapphireTest {
'extension' => 'txt',
'error' => UPLOAD_ERR_OK,
);
$v = new UploadTest_Validator();
$v->setAllowedMaxFileSize(array('txt' => 10));
// test upload into default folder
$u1 = new Upload();
$v = new UploadTest_Validator();
$v->setAllowedMaxFileSize(array('txt' => 10));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertFalse($result, 'Load failed because size was too big');
$v->setAllowedMaxFileSize(array('[doc]' => 10));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertFalse($result, 'Load failed because size was too big');
$v->setAllowedMaxFileSize(array('txt' => 200000));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertTrue($result, 'Load failed with setting max file size');
// check max file size set by app category
$tmpFileName = 'UploadTest-testUpload.jpg';
$tmpFilePath = TEMP_FOLDER . '/' . $tmpFileName;
file_put_contents($tmpFilePath, $tmpFileContent . $tmpFileContent);
$tmpFile = array(
'name' => $tmpFileName,
'type' => 'image/jpeg',
'size' => filesize($tmpFilePath),
'tmp_name' => $tmpFilePath,
'extension' => 'jpg',
'error' => UPLOAD_ERR_OK,
);
$v->setAllowedMaxFileSize(array('[image]' => '40k'));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertTrue($result, 'Load failed with setting max file size');
$v->setAllowedMaxFileSize(array('[image]' => '1k'));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertFalse($result, 'Load failed because size was too big');
$v->setAllowedMaxFileSize(array('[image]' => 1000));
$u1->setValidator($v);
$result = $u1->load($tmpFile);
$this->assertFalse($result, 'Load failed because size was too big');
}
public function testGetAllowedMaxFileSize() {
Config::nest();
// Check the max file size uses the config values
$configMaxFileSizes = array(
'[image]' => '1k',
'txt' => 1000
);
Config::inst()->update('Upload_Validator', 'default_max_file_size', $configMaxFileSizes);
$v = new UploadTest_Validator();
$retrievedSize = $v->getAllowedMaxFileSize('[image]');
$this->assertEquals(1024, $retrievedSize, 'Max file size check on default values failed (config category set check)');
$retrievedSize = $v->getAllowedMaxFileSize('txt');
$this->assertEquals(1000, $retrievedSize, 'Max file size check on default values failed (config extension set check)');
// Check instance values for max file size
$maxFileSizes = array(
'[doc]' => 2000,
'txt' => '4k'
);
$v = new UploadTest_Validator();
$v->setAllowedMaxFileSize($maxFileSizes);
$retrievedSize = $v->getAllowedMaxFileSize('[doc]');
$this->assertEquals(2000, $retrievedSize, 'Max file size check on instance values failed (instance category set check)');
// Check that the instance values overwrote the default values
// ie. The max file size will not exist for [image]
$retrievedSize = $v->getAllowedMaxFileSize('[image]');
$this->assertFalse($retrievedSize, 'Max file size check on instance values failed (config overridden check)');
// Check a category that has not been set before
$retrievedSize = $v->getAllowedMaxFileSize('[zip]');
$this->assertFalse($retrievedSize, 'Max file size check on instance values failed (category not set check)');
// Check a file extension that has not been set before
$retrievedSize = $v->getAllowedMaxFileSize('mp3');
$this->assertFalse($retrievedSize, 'Max file size check on instance values failed (extension not set check)');
$retrievedSize = $v->getAllowedMaxFileSize('txt');
$this->assertEquals(4096, $retrievedSize, 'Max file size check on instance values failed (instance extension set check)');
Config::unnest();
}
public function testAllowedSizeOnFileWithNoExtension() {