mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
API CHANGE #5107 Upload now uses Upload_Validator to separate the validation rules from the File loading done in the Upload class (from r100057)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@105549 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
d8478a8f59
commit
75b98970e4
@ -14,11 +14,16 @@ class Upload extends Controller {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A File object
|
* A File object
|
||||||
*
|
|
||||||
* @var File
|
* @var File
|
||||||
*/
|
*/
|
||||||
protected $file;
|
protected $file;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An instance of Upload_Validator
|
||||||
|
* @var Upload_Validator
|
||||||
|
*/
|
||||||
|
protected $validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information about the temporary file produced
|
* Information about the temporary file produced
|
||||||
* by the PHP-runtime.
|
* by the PHP-runtime.
|
||||||
@ -26,26 +31,6 @@ class Upload extends Controller {
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $tmpFile;
|
protected $tmpFile;
|
||||||
|
|
||||||
/**
|
|
||||||
* Restrict filesize for either all filetypes
|
|
||||||
* or a specific extension, with extension-name
|
|
||||||
* as array-key and the size-restriction in bytes as array-value.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
public $allowedMaxFileSize = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Collection of extensions.
|
|
||||||
* Extension-names are treated case-insensitive.
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
* <code>
|
|
||||||
* array("jpg","GIF")
|
|
||||||
* </code>
|
|
||||||
*/
|
|
||||||
public $allowedExtensions = array();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processing errors that can be evaluated,
|
* Processing errors that can be evaluated,
|
||||||
@ -63,6 +48,21 @@ class Upload extends Controller {
|
|||||||
*/
|
*/
|
||||||
public static $uploads_folder = "Uploads";
|
public static $uploads_folder = "Uploads";
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
parent::__construct();
|
||||||
|
$this->validator = new Upload_Validator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a different instance than {@link Upload_Validator}
|
||||||
|
* for this upload session.
|
||||||
|
*
|
||||||
|
* @param object $validator
|
||||||
|
*/
|
||||||
|
public function setValidator($validator) {
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Save an file passed from a form post into this object.
|
* Save an file passed from a form post into this object.
|
||||||
*
|
*
|
||||||
@ -145,7 +145,6 @@ class Upload extends Controller {
|
|||||||
*/
|
*/
|
||||||
public function loadIntoFile($tmpFile, $file, $folderPath = false) {
|
public function loadIntoFile($tmpFile, $file, $folderPath = false) {
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
|
|
||||||
return $this->load($tmpFile, $folderPath);
|
return $this->load($tmpFile, $folderPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,44 +159,13 @@ class Upload extends Controller {
|
|||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function validate($tmpFile) {
|
public function validate($tmpFile) {
|
||||||
// we don't validate for empty upload fields yet
|
$validator = $this->validator;
|
||||||
if(!isset($tmpFile['name']) || empty($tmpFile['name'])) return true;
|
$validator->setTmpFile($tmpFile);
|
||||||
|
$isValid = $validator->validate();
|
||||||
if(isset($tmpFile['tmp_name']) && !is_uploaded_file($tmpFile['tmp_name']) && !SapphireTest::is_running_test()) {
|
if($validator->getErrors()) {
|
||||||
$this->errors[] = _t('File.NOVALIDUPLOAD', 'File is not a valid upload');
|
$this->errors = array_merge($this->errors, $validator->getErrors());
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return $isValid;
|
||||||
$pathInfo = pathinfo($tmpFile['name']);
|
|
||||||
// filesize validation
|
|
||||||
if(!$this->isValidSize($tmpFile)) {
|
|
||||||
$this->errors[] = sprintf(
|
|
||||||
_t(
|
|
||||||
'File.TOOLARGE',
|
|
||||||
'Filesize is too large, maximum %s allowed.',
|
|
||||||
PR_MEDIUM,
|
|
||||||
'Argument 1: Filesize (e.g. 1MB)'
|
|
||||||
),
|
|
||||||
File::format_size($this->getAllowedMaxFileSize($pathInfo['extension']))
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// extension validation
|
|
||||||
if(!$this->isValidExtension($tmpFile)) {
|
|
||||||
$this->errors[] = sprintf(
|
|
||||||
_t(
|
|
||||||
'File.INVALIDEXTENSION',
|
|
||||||
'Extension is not allowed (valid: %s)',
|
|
||||||
PR_MEDIUM,
|
|
||||||
'Argument 1: Comma-separated list of valid extensions'
|
|
||||||
),
|
|
||||||
implode(',',$this->allowedExtensions)
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -219,6 +187,167 @@ class Upload extends Controller {
|
|||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get maximum file size for all or specified file extension.
|
||||||
|
*
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::getAllowedMaxFileSize() instead
|
||||||
|
*
|
||||||
|
* @param string $ext
|
||||||
|
* @return int Filesize in bytes
|
||||||
|
*/
|
||||||
|
public function getAllowedMaxFileSize($ext = null) {
|
||||||
|
user_error('Upload::getAllowedMaxFileSize() is deprecated. Please use Upload_Validator::getAllowedMaxFileSize() instead', E_USER_NOTICE);
|
||||||
|
return $this->validator->getAllowedMaxFileSize($ext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set filesize maximums (in bytes).
|
||||||
|
* Automatically converts extensions to lowercase
|
||||||
|
* for easier matching.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <code>
|
||||||
|
* array('*' => 200, 'jpg' => 1000)
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::setAllowedMaxFileSize() instead
|
||||||
|
*
|
||||||
|
* @param array|int $rules
|
||||||
|
*/
|
||||||
|
public function setAllowedMaxFileSize($rules) {
|
||||||
|
user_error('Upload::setAllowedMaxFileSize() is deprecated. Please use Upload_Validator::setAllowedMaxFileSize() instead', E_USER_NOTICE);
|
||||||
|
$this->validator->setAllowedMaxFileSize($rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::getAllowedExtensions() instead
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getAllowedExtensions() {
|
||||||
|
user_error('Upload::getAllowedExtensions() is deprecated. Please use Upload_Validator::getAllowedExtensions() instead', E_USER_NOTICE);
|
||||||
|
return $this->validator->getAllowedExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::setAllowedExtensions() instead
|
||||||
|
* @param array $rules
|
||||||
|
*/
|
||||||
|
public function setAllowedExtensions($rules) {
|
||||||
|
user_error('Upload::setAllowedExtensions() is deprecated. Please use Upload_Validator::setAllowedExtensions() instead', E_USER_NOTICE);
|
||||||
|
$this->validator->setAllowedExtensions($rules);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the bytesize of an uploaded
|
||||||
|
* file is valid - can be defined on an
|
||||||
|
* extension-by-extension basis in {$allowedMaxFileSize}
|
||||||
|
*
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::isValidExtension() instead
|
||||||
|
*
|
||||||
|
* @param array $tmpFile
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isValidSize($tmpFile) {
|
||||||
|
user_error('Upload::isValidSize() is deprecated. Please use Upload_Validator::isValidSize() instead', E_USER_NOTICE);
|
||||||
|
$validator = new Upload_Validator();
|
||||||
|
$validator->setTmpFile($tmpFile);
|
||||||
|
return $validator->isValidSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the temporary file has a valid extension
|
||||||
|
*
|
||||||
|
* @deprecated 2.5 Please use Upload_Validator::isValidExtension() instead
|
||||||
|
*
|
||||||
|
* @param array $tmpFile
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isValidExtension($tmpFile) {
|
||||||
|
user_error('Upload::isValidExtension() is deprecated. Please use Upload_Validator::isValidExtension() instead', E_USER_NOTICE);
|
||||||
|
$validator = new Upload_Validator();
|
||||||
|
$validator->setTmpFile($tmpFile);
|
||||||
|
return $validator->isValidExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear out all errors (mostly set by {loadUploaded()})
|
||||||
|
*/
|
||||||
|
public function clearErrors() {
|
||||||
|
$this->errors = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines wether previous operations caused an error.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isError() {
|
||||||
|
return (count($this->errors));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all errors that occurred while processing so far
|
||||||
|
* (mostly set by {loadUploaded()})
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getErrors() {
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
class Upload_Validator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about the temporary file produced
|
||||||
|
* by the PHP-runtime.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $tmpFile;
|
||||||
|
|
||||||
|
protected $errors = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restrict filesize for either all filetypes
|
||||||
|
* or a specific extension, with extension-name
|
||||||
|
* as array-key and the size-restriction in bytes as array-value.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $allowedMaxFileSize = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Collection of extensions.
|
||||||
|
* Extension-names are treated case-insensitive.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* <code>
|
||||||
|
* array("jpg","GIF")
|
||||||
|
* </code>
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public $allowedExtensions = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all errors that occurred while validating
|
||||||
|
* the temporary file.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getErrors() {
|
||||||
|
return $this->errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set information about temporary file produced by PHP.
|
||||||
|
* @param array $tmpFile
|
||||||
|
*/
|
||||||
|
public function setTmpFile($tmpFile) {
|
||||||
|
$this->tmpFile = $tmpFile;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get maximum file size for all or specified file extension.
|
* Get maximum file size for all or specified file extension.
|
||||||
*
|
*
|
||||||
@ -251,7 +380,7 @@ class Upload extends Controller {
|
|||||||
// 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;
|
$this->allowedMaxFileSize = $rules;
|
||||||
} elseif((int)$rules > 0) {
|
} elseif((int) $rules > 0) {
|
||||||
$this->allowedMaxFileSize['*'] = (int)$rules;
|
$this->allowedMaxFileSize['*'] = (int)$rules;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -280,53 +409,70 @@ class Upload extends Controller {
|
|||||||
* file is valid - can be defined on an
|
* file is valid - can be defined on an
|
||||||
* extension-by-extension basis in {$allowedMaxFileSize}
|
* extension-by-extension basis in {$allowedMaxFileSize}
|
||||||
*
|
*
|
||||||
* @param array $tmpFile
|
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isValidSize($tmpFile) {
|
public function isValidSize() {
|
||||||
$pathInfo = pathinfo($tmpFile['name']);
|
$pathInfo = pathinfo($this->tmpFile['name']);
|
||||||
$extension = isset($pathInfo['extension']) ? strtolower($pathInfo['extension']) : null;
|
$extension = isset($pathInfo['extension']) ? strtolower($pathInfo['extension']) : null;
|
||||||
$maxSize = $this->getAllowedMaxFileSize($extension);
|
$maxSize = $this->getAllowedMaxFileSize($extension);
|
||||||
return (!$tmpFile['size'] || !$maxSize || (int)$tmpFile['size'] < $maxSize);
|
return (!$this->tmpFile['size'] || !$maxSize || (int) $this->tmpFile['size'] < $maxSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the temporary file has a valid extension
|
* Determines if the temporary file has a valid extension
|
||||||
*
|
|
||||||
* @param array $tmpFile
|
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isValidExtension($tmpFile) {
|
public function isValidExtension() {
|
||||||
$pathInfo = pathinfo($tmpFile['name']);
|
$pathInfo = pathinfo($this->tmpFile['name']);
|
||||||
return (!count($this->allowedExtensions) || in_array(strtolower($pathInfo['extension']), $this->allowedExtensions));
|
return (!count($this->allowedExtensions) || in_array(strtolower($pathInfo['extension']), $this->allowedExtensions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear out all errors (mostly set by {loadUploaded()})
|
* Run through the rules for this validator checking against
|
||||||
*/
|
* the temporary file set by {@link setTmpFile()} to see if
|
||||||
public function clearErrors() {
|
* the file is deemed valid or not.
|
||||||
$this->errors = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines wether previous operations caused an error.
|
|
||||||
*
|
*
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function isError() {
|
public function validate() {
|
||||||
return (count($this->errors));
|
// we don't validate for empty upload fields yet
|
||||||
|
if(!isset($this->tmpFile['name']) || empty($this->tmpFile['name'])) return true;
|
||||||
|
|
||||||
|
if(isset($this->tmpFile['tmp_name']) && !is_uploaded_file($this->tmpFile['tmp_name']) && !SapphireTest::is_running_test()) {
|
||||||
|
$this->errors[] = _t('File.NOVALIDUPLOAD', 'File is not a valid upload');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pathInfo = pathinfo($this->tmpFile['name']);
|
||||||
|
// filesize validation
|
||||||
|
if(!$this->isValidSize()) {
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
_t(
|
||||||
|
'File.TOOLARGE',
|
||||||
|
'Filesize is too large, maximum %s allowed.',
|
||||||
|
PR_MEDIUM,
|
||||||
|
'Argument 1: Filesize (e.g. 1MB)'
|
||||||
|
),
|
||||||
|
File::format_size($this->getAllowedMaxFileSize($pathInfo['extension']))
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extension validation
|
||||||
|
if(!$this->isValidExtension()) {
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
_t(
|
||||||
|
'File.INVALIDEXTENSION',
|
||||||
|
'Extension is not allowed (valid: %s)',
|
||||||
|
PR_MEDIUM,
|
||||||
|
'Argument 1: Comma-separated list of valid extensions'
|
||||||
|
),
|
||||||
|
implode(',', $this->allowedExtensions)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
}
|
||||||
* Return all errors that occurred while processing so far
|
|
||||||
* (mostly set by {loadUploaded()})
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getErrors() {
|
|
||||||
return $this->errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
?>
|
|
@ -24,8 +24,11 @@ class UploadTest extends SapphireTest {
|
|||||||
'error' => UPLOAD_ERR_OK,
|
'error' => UPLOAD_ERR_OK,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$v = new UploadTest_Validator();
|
||||||
|
|
||||||
// test upload into default folder
|
// test upload into default folder
|
||||||
$u1 = new Upload();
|
$u1 = new Upload();
|
||||||
|
$u1->setValidator($v);
|
||||||
$u1->load($tmpFile);
|
$u1->load($tmpFile);
|
||||||
$file1 = $u1->getFile();
|
$file1 = $u1->getFile();
|
||||||
$this->assertTrue(
|
$this->assertTrue(
|
||||||
@ -65,4 +68,47 @@ class UploadTest extends SapphireTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
?>
|
class UploadTest_Validator extends Upload_Validator implements TestOnly {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looser check validation that doesn't do is_upload_file()
|
||||||
|
* checks as we're faking a POST request that PHP didn't generate
|
||||||
|
* itself.
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function validate() {
|
||||||
|
$pathInfo = pathinfo($this->tmpFile['name']);
|
||||||
|
// filesize validation
|
||||||
|
|
||||||
|
if(!$this->isValidSize()) {
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
_t(
|
||||||
|
'File.TOOLARGE',
|
||||||
|
'Filesize is too large, maximum %s allowed.',
|
||||||
|
PR_MEDIUM,
|
||||||
|
'Argument 1: Filesize (e.g. 1MB)'
|
||||||
|
),
|
||||||
|
File::format_size($this->getAllowedMaxFileSize($pathInfo['extension']))
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// extension validation
|
||||||
|
if(!$this->isValidExtension()) {
|
||||||
|
$this->errors[] = sprintf(
|
||||||
|
_t(
|
||||||
|
'File.INVALIDEXTENSION',
|
||||||
|
'Extension is not allowed (valid: %s)',
|
||||||
|
PR_MEDIUM,
|
||||||
|
'Argument 1: Comma-separated list of valid extensions'
|
||||||
|
),
|
||||||
|
implode(',', $this->allowedExtensions)
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user