Skip to content
Browse files

[Form] Added proper error handling to FileField

  • Loading branch information...
1 parent fd3f4f8 commit 242be933d5cd73fed2049a29ed8c5ae069320e47 @webmozart webmozart committed with fabpot Dec 14, 2010
View
79 src/Symfony/Component/Form/FileField.php
@@ -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.
@@ -19,6 +20,26 @@
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}
*/
protected function configure()
@@ -45,9 +66,29 @@ protected function configure()
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 @@ public function isMultipart()
{
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
18 src/Symfony/Component/Form/Resources/config/validation.xml
@@ -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
147 tests/Symfony/Tests/Component/Form/FileFieldTest.php
@@ -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 @@ public static function setUpBeforeClass()
@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 @@ public function createTmpFile($path)
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 @@ public function testBindUploadsNewFiles()
->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 @@ public function testBindUploadsNewFiles()
'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 @@ public function testBindKeepsUploadedFilesOnErrors()
'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 @@ public function testBindKeepsOldFileIfNotOverwritten()
'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' => ''
+ ));
}
}

0 comments on commit 242be93

Please sign in to comment.
Something went wrong with that request. Please try again.