[Form] Added proper error handling to FileField

This commit is contained in:
Bernhard Schussek 2010-12-14 21:43:19 +01:00 committed by Fabien Potencier
parent fd3f4f86a5
commit 242be933d5
3 changed files with 214 additions and 30 deletions

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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' => ''
));
}
}