Merge pull request #4052 from Turnerj/feature-max-size-by-upload-type

FEATURE: Added maximum upload file size by type (on 3)
This commit is contained in:
Damian Mooyman 2015-04-01 09:32:56 +13:00
commit 9aa60ed4f3
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); $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 ### 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. 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 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. You can also configure the underlying `[api:Upload]` class, by using the YAML config system.
```yaml ```yaml

View File

@ -305,6 +305,16 @@ class Upload extends Controller {
*/ */
class Upload_Validator { 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 * Information about the temporary file produced
* by the PHP-runtime. * by the PHP-runtime.
@ -360,22 +370,46 @@ class Upload_Validator {
* @return int Filesize in bytes * @return int Filesize in bytes
*/ */
public function getAllowedMaxFileSize($ext = null) { 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); $ext = strtolower($ext);
if(isset($ext) && isset($this->allowedMaxFileSize[$ext])) { if ($ext) {
return $this->allowedMaxFileSize[$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 { } else {
return (isset($this->allowedMaxFileSize['*'])) ? $this->allowedMaxFileSize['*'] : false; 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 * Automatically converts extensions to lowercase
* for easier matching. * for easier matching.
* *
* Example: * Example:
* <code> * <code>
* array('*' => 200, 'jpg' => 1000) * array('*' => 200, 'jpg' => 1000, '[doc]' => '5m')
* </code> * </code>
* *
* @param array|int $rules * @param array|int $rules
@ -384,7 +418,22 @@ class Upload_Validator {
if(is_array($rules) && count($rules)) { if(is_array($rules) && count($rules)) {
// make sure all extensions are lowercase // make sure all extensions are lowercase
$rules = array_change_key_case($rules, CASE_LOWER); $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) { } elseif((int) $rules > 0) {
$this->allowedMaxFileSize['*'] = (int)$rules; $this->allowedMaxFileSize['*'] = (int)$rules;
} }

View File

@ -84,15 +84,100 @@ class UploadTest extends SapphireTest {
'error' => UPLOAD_ERR_OK, 'error' => UPLOAD_ERR_OK,
); );
$v = new UploadTest_Validator();
$v->setAllowedMaxFileSize(array('txt' => 10));
// test upload into default folder // test upload into default folder
$u1 = new Upload(); $u1 = new Upload();
$v = new UploadTest_Validator();
$v->setAllowedMaxFileSize(array('txt' => 10));
$u1->setValidator($v); $u1->setValidator($v);
$result = $u1->load($tmpFile); $result = $u1->load($tmpFile);
$this->assertFalse($result, 'Load failed because size was too big'); $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() { public function testAllowedSizeOnFileWithNoExtension() {