[Form] Added proper error handling to FileField
This commit is contained in:
parent
fd3f4f86a5
commit
242be933d5
@ -3,6 +3,7 @@
|
||||
namespace Symfony\Component\Form;
|
||||
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Symfony\Component\Form\Exception\FormException;
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
@ -18,6 +19,26 @@ use Symfony\Component\HttpFoundation\File\File;
|
||||
*/
|
||||
class FileField extends FieldGroup
|
||||
{
|
||||
/**
|
||||
* Whether the size of the uploaded file exceeds the upload_max_filesize
|
||||
* directive in php.ini
|
||||
* @var boolean
|
||||
*/
|
||||
protected $iniSizeExceeded = false;
|
||||
|
||||
/**
|
||||
* Whether the size of the uploaded file exceeds the MAX_FILE_SIZE
|
||||
* directive specified in the HTML form
|
||||
* @var boolean
|
||||
*/
|
||||
protected $formSizeExceeded = false;
|
||||
|
||||
/**
|
||||
* Whether the file was completely uploaded
|
||||
* @var boolean
|
||||
*/
|
||||
protected $uploadComplete = true;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -45,9 +66,29 @@ class FileField extends FieldGroup
|
||||
protected function preprocessData(array $data)
|
||||
{
|
||||
if ($data['file']) {
|
||||
$data['file']->move($this->getTmpPath($data['token']));
|
||||
$data['original_name'] = $data['file']->getOriginalName();
|
||||
$data['file'] = '';
|
||||
switch ($data['file']->getError()) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$this->iniSizeExceeded = true;
|
||||
break;
|
||||
case UPLOAD_ERR_FORM_SIZE:
|
||||
$this->formSizeExceeded = true;
|
||||
break;
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$this->uploadComplete = false;
|
||||
break;
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
throw new FormException('Could not upload a file because a temporary directory is missing (UPLOAD_ERR_NO_TMP_DIR)');
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
throw new FormException('Could not write file to disk (UPLOAD_ERR_CANT_WRITE)');
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
throw new FormException('A PHP extension stopped the file upload (UPLOAD_ERR_EXTENSION)');
|
||||
case UPLOAD_ERR_OK:
|
||||
default:
|
||||
$data['file']->move($this->getTmpPath($data['token']));
|
||||
$data['original_name'] = $data['file']->getOriginalName();
|
||||
$data['file'] = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
@ -120,4 +161,36 @@ class FileField extends FieldGroup
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the size of the uploaded file exceeds the
|
||||
* upload_max_filesize directive in php.ini
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isIniSizeExceeded()
|
||||
{
|
||||
return $this->iniSizeExceeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the size of the uploaded file exceeds the
|
||||
* MAX_FILE_SIZE directive specified in the HTML form
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isFormSizeExceeded()
|
||||
{
|
||||
return $this->formSizeExceeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file was completely uploaded
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function isUploadComplete()
|
||||
{
|
||||
return $this->uploadComplete;
|
||||
}
|
||||
}
|
||||
|
@ -74,4 +74,22 @@
|
||||
</constraint>
|
||||
</getter>
|
||||
</class>
|
||||
|
||||
<class name="Symfony\Component\Form\FileField">
|
||||
<getter property="iniSizeExceeded">
|
||||
<constraint name="AssertFalse">
|
||||
<option name="message">The file is too large. Please upload a smaller file</option>
|
||||
</constraint>
|
||||
</getter>
|
||||
<getter property="formSizeExceeded">
|
||||
<constraint name="AssertFalse">
|
||||
<option name="message">The file is too large. Please upload a smaller file</option>
|
||||
</constraint>
|
||||
</getter>
|
||||
<getter property="uploadComplete">
|
||||
<constraint name="AssertTrue">
|
||||
<option name="message">The file was only partially uploaded. Please try again</option>
|
||||
</constraint>
|
||||
</getter>
|
||||
</class>
|
||||
</constraint-mapping>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
namespace Symfony\Tests\Component\Form;
|
||||
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
use Symfony\Component\Form\FileField;
|
||||
|
||||
class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
@ -11,6 +10,8 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
protected static $tmpDir;
|
||||
|
||||
protected $field;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$tmpDir = sys_get_temp_dir();
|
||||
@ -19,6 +20,14 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
@session_start();
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->field = new FileField('file', array(
|
||||
'secret' => '$secret$',
|
||||
'tmp_dir' => self::$tmpDir,
|
||||
));
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
foreach (self::$tmpFiles as $key => $file) {
|
||||
@ -35,11 +44,6 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testBindUploadsNewFiles()
|
||||
{
|
||||
$field = new FileField('file', array(
|
||||
'secret' => '$secret$',
|
||||
'tmp_dir' => self::$tmpDir,
|
||||
));
|
||||
|
||||
$tmpPath = realpath(self::$tmpDir) . '/' . md5(session_id() . '$secret$' . '12345');
|
||||
$that = $this;
|
||||
|
||||
@ -54,7 +58,7 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
->method('getOriginalName')
|
||||
->will($this->returnValue('original_name.jpg'));
|
||||
|
||||
$field->bind(array(
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => '',
|
||||
@ -65,21 +69,19 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
'file' => '',
|
||||
'token' => '12345',
|
||||
'original_name' => 'original_name.jpg',
|
||||
), $field->getDisplayedData());
|
||||
$this->assertEquals($tmpPath, $field->getData());
|
||||
), $this->field->getDisplayedData());
|
||||
$this->assertEquals($tmpPath, $this->field->getData());
|
||||
$this->assertFalse($this->field->isIniSizeExceeded());
|
||||
$this->assertFalse($this->field->isFormSizeExceeded());
|
||||
$this->assertTrue($this->field->isUploadComplete());
|
||||
}
|
||||
|
||||
public function testBindKeepsUploadedFilesOnErrors()
|
||||
{
|
||||
$field = new FileField('file', array(
|
||||
'secret' => '$secret$',
|
||||
'tmp_dir' => self::$tmpDir,
|
||||
));
|
||||
|
||||
$tmpPath = self::$tmpDir . '/' . md5(session_id() . '$secret$' . '12345');
|
||||
$this->createTmpFile($tmpPath);
|
||||
|
||||
$field->bind(array(
|
||||
$this->field->bind(array(
|
||||
'file' => '',
|
||||
'token' => '12345',
|
||||
'original_name' => 'original_name.jpg',
|
||||
@ -90,25 +92,20 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
'file' => '',
|
||||
'token' => '12345',
|
||||
'original_name' => 'original_name.jpg',
|
||||
), $field->getDisplayedData());
|
||||
$this->assertEquals(realpath($tmpPath), realpath($field->getData()));
|
||||
), $this->field->getDisplayedData());
|
||||
$this->assertEquals(realpath($tmpPath), realpath($this->field->getData()));
|
||||
}
|
||||
|
||||
public function testBindKeepsOldFileIfNotOverwritten()
|
||||
{
|
||||
$field = new FileField('file', array(
|
||||
'secret' => '$secret$',
|
||||
'tmp_dir' => self::$tmpDir,
|
||||
));
|
||||
|
||||
$oldPath = tempnam(sys_get_temp_dir(), 'FileFieldTest');
|
||||
$this->createTmpFile($oldPath);
|
||||
|
||||
$field->setData($oldPath);
|
||||
$this->field->setData($oldPath);
|
||||
|
||||
$this->assertEquals($oldPath, $field->getData());
|
||||
$this->assertEquals($oldPath, $this->field->getData());
|
||||
|
||||
$field->bind(array(
|
||||
$this->field->bind(array(
|
||||
'file' => '',
|
||||
'token' => '12345',
|
||||
'original_name' => '',
|
||||
@ -119,7 +116,103 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
'file' => '',
|
||||
'token' => '12345',
|
||||
'original_name' => '',
|
||||
), $field->getDisplayedData());
|
||||
$this->assertEquals($oldPath, $field->getData());
|
||||
), $this->field->getDisplayedData());
|
||||
$this->assertEquals($oldPath, $this->field->getData());
|
||||
}
|
||||
|
||||
public function testBindHandlesUploadErrIniSize()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_INI_SIZE));
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
|
||||
$this->assertTrue($this->field->isIniSizeExceeded());
|
||||
}
|
||||
|
||||
public function testBindHandlesUploadErrFormSize()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_FORM_SIZE));
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
|
||||
$this->assertTrue($this->field->isFormSizeExceeded());
|
||||
}
|
||||
|
||||
public function testBindHandlesUploadErrPartial()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_PARTIAL));
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
|
||||
$this->assertFalse($this->field->isUploadComplete());
|
||||
}
|
||||
|
||||
public function testBindThrowsExceptionOnUploadErrNoTmpDir()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_NO_TMP_DIR));
|
||||
|
||||
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
}
|
||||
|
||||
public function testBindThrowsExceptionOnUploadErrCantWrite()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_CANT_WRITE));
|
||||
|
||||
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
}
|
||||
|
||||
public function testBindThrowsExceptionOnUploadErrExtension()
|
||||
{
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->any())
|
||||
->method('getError')
|
||||
->will($this->returnValue(UPLOAD_ERR_EXTENSION));
|
||||
|
||||
$this->setExpectedException('Symfony\Component\Form\Exception\FormException');
|
||||
|
||||
$this->field->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '12345',
|
||||
'original_name' => ''
|
||||
));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user