[Form] Added test for last commit by kriswallsmith and improved dealing with original names
The form component should now guarantee to always pass an UploadedFile object to your model. There you can call getOriginalName() to retrieve the original name of the uploaded file. For security reasons, the real file name is a generated hash value.
This commit is contained in:
parent
4c6f26f008
commit
bf1dfbbe99
@ -8,4 +8,5 @@
|
||||
|
||||
<?php echo $view['form']->widget($form['token']) ?>
|
||||
<?php echo $view['form']->widget($form['name']) ?>
|
||||
<?php echo $view['form']->widget($form['originalName']) ?>
|
||||
</div>
|
||||
|
@ -221,6 +221,7 @@
|
||||
{{ form_widget(form.file) }}
|
||||
{{ form_widget(form.token) }}
|
||||
{{ form_widget(form.name) }}
|
||||
{{ form_widget(form.originalName) }}
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
{% endblock file_widget %}
|
||||
|
@ -26,8 +26,6 @@ class FileToArrayTransformer implements DataTransformerInterface
|
||||
if (null === $file || '' === $file) {
|
||||
return array(
|
||||
'file' => '',
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
);
|
||||
}
|
||||
|
||||
@ -37,8 +35,6 @@ class FileToArrayTransformer implements DataTransformerInterface
|
||||
|
||||
return array(
|
||||
'file' => $file,
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Form\Extension\Core\EventListener;
|
||||
|
||||
use Symfony\Component\Form\Events;
|
||||
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||
use Symfony\Component\Form\Event\FilterDataEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
@ -42,17 +43,19 @@ class FixFileUploadListener implements EventSubscriberInterface
|
||||
$form = $event->getForm();
|
||||
$data = $event->getData();
|
||||
|
||||
if (!is_array($data)) {
|
||||
return;
|
||||
if (null === $data) {
|
||||
$data = array();
|
||||
}
|
||||
|
||||
// TODO should be disableable
|
||||
if (!is_array($data)) {
|
||||
throw new UnexpectedTypeException($data, 'array');
|
||||
}
|
||||
|
||||
// TESTME
|
||||
$data = array_merge(array(
|
||||
$data = array_replace(array(
|
||||
'file' => '',
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
'originalName' => '',
|
||||
), $data);
|
||||
|
||||
// Newly uploaded file
|
||||
@ -61,14 +64,15 @@ class FixFileUploadListener implements EventSubscriberInterface
|
||||
$directory = $this->storage->getTempDir($data['token']);
|
||||
$data['file']->move($directory);
|
||||
$data['name'] = $data['file']->getName();
|
||||
$data['originalName'] = $data['file']->getOriginalName();
|
||||
}
|
||||
|
||||
// Existing uploaded file
|
||||
if (!$data['file'] && $data['token'] && $data['name']) {
|
||||
$path = $this->storage->getTempDir($data['token']) . DIRECTORY_SEPARATOR . $data ['name'];
|
||||
$path = $this->storage->getTempDir($data['token']) . DIRECTORY_SEPARATOR . $data['name'];
|
||||
|
||||
if (file_exists($path)) {
|
||||
$data['file'] = new File($path);
|
||||
$data['file'] = new UploadedFile($path, $data['originalName'], null, null, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,8 @@ class FileType extends AbstractType
|
||||
->addEventSubscriber(new FixFileUploadListener($this->storage), 10)
|
||||
->add('file', 'field')
|
||||
->add('token', 'hidden')
|
||||
->add('name', 'hidden');
|
||||
->add('name', 'hidden')
|
||||
->add('originalName', 'hidden');
|
||||
}
|
||||
|
||||
public function buildViewBottomUp(FormView $view, FormInterface $form)
|
||||
|
@ -50,6 +50,8 @@ interface FormInterface extends \ArrayAccess, \Traversable, \Countable
|
||||
|
||||
function getData();
|
||||
|
||||
function getNormData();
|
||||
|
||||
function getClientData();
|
||||
|
||||
function isBound();
|
||||
|
@ -71,7 +71,8 @@ class UploadedFile extends File
|
||||
* @throws FileException If file_uploads is disabled
|
||||
* @throws FileNotFoundException If the file does not exist
|
||||
*/
|
||||
public function __construct($path, $originalName, $mimeType, $size, $error, $moved = false)
|
||||
public function __construct($path, $originalName, $mimeType = null,
|
||||
$size = null, $error = null, $moved = false)
|
||||
{
|
||||
if (!ini_get('file_uploads')) {
|
||||
throw new FileException(sprintf('Unable to create UploadedFile because "file_uploads" is disabled in your php.ini file (%s)', get_cfg_var('cfg_file_path')));
|
||||
|
@ -664,8 +664,9 @@ abstract class AbstractLayoutTest extends \PHPUnit_Framework_TestCase
|
||||
./input[@type="file"][@id="na&me_file"]
|
||||
/following-sibling::input[@type="hidden"][@id="na&me_token"]
|
||||
/following-sibling::input[@type="hidden"][@id="na&me_name"]
|
||||
/following-sibling::input[@type="hidden"][@id="na&me_originalName"]
|
||||
]
|
||||
[count(./input)=3]
|
||||
[count(./input)=4]
|
||||
'
|
||||
);
|
||||
}
|
||||
|
@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Tests\Component\Form\Extension\Core\EventListener;
|
||||
|
||||
use Symfony\Component\Form\Event\FilterDataEvent;
|
||||
use Symfony\Component\Form\Extension\Core\EventListener\FixFileUploadListener;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
|
||||
class FixFileUploadListenerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
private $storage;
|
||||
|
||||
private $destination;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->storage = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\TemporaryStorage')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
public function testValidNewlyUploadedFile()
|
||||
{
|
||||
$passedToken = null;
|
||||
|
||||
$this->storage->expects($this->any())
|
||||
->method('getTempDir')
|
||||
->will($this->returnCallback(function ($token) use (&$passedToken) {
|
||||
$passedToken = $token;
|
||||
|
||||
return __DIR__.DIRECTORY_SEPARATOR.'tmp';
|
||||
}));
|
||||
|
||||
$file = $this->createUploadedFileMock('randomhash', 'original.jpg', true);
|
||||
$file->expects($this->once())
|
||||
->method('move')
|
||||
->with(__DIR__.DIRECTORY_SEPARATOR.'tmp');
|
||||
|
||||
$data = array(
|
||||
'file' => $file,
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
'originalName' => '',
|
||||
);
|
||||
|
||||
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
|
||||
$event = new FilterDataEvent($form, $data);
|
||||
|
||||
$filter = new FixFileUploadListener($this->storage);
|
||||
$filter->onBindClientData($event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'file' => $file,
|
||||
'name' => 'randomhash',
|
||||
'originalName' => 'original.jpg',
|
||||
'token' => $passedToken,
|
||||
), $event->getData());
|
||||
}
|
||||
|
||||
public function testExistingUploadedFile()
|
||||
{
|
||||
$test = $this;
|
||||
|
||||
$this->storage->expects($this->any())
|
||||
->method('getTempDir')
|
||||
->will($this->returnCallback(function ($token) use ($test) {
|
||||
$test->assertSame('abcdef', $token);
|
||||
|
||||
return __DIR__.DIRECTORY_SEPARATOR.'Fixtures';
|
||||
}));
|
||||
|
||||
$data = array(
|
||||
'file' => '',
|
||||
'token' => 'abcdef',
|
||||
'name' => 'randomhash',
|
||||
'originalName' => 'original.jpg',
|
||||
);
|
||||
|
||||
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
|
||||
$event = new FilterDataEvent($form, $data);
|
||||
|
||||
$filter = new FixFileUploadListener($this->storage);
|
||||
$filter->onBindClientData($event);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'file' => new UploadedFile(
|
||||
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'randomhash',
|
||||
'original.jpg',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true // already moved
|
||||
),
|
||||
'name' => 'randomhash',
|
||||
'originalName' => 'original.jpg',
|
||||
'token' => 'abcdef',
|
||||
), $event->getData());
|
||||
}
|
||||
|
||||
public function testNullAndExistingFile()
|
||||
{
|
||||
$existingData = array(
|
||||
'file' => new UploadedFile(
|
||||
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'randomhash',
|
||||
'original.jpg',
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true // already moved
|
||||
),
|
||||
'name' => 'randomhash',
|
||||
'originalName' => 'original.jpg',
|
||||
'token' => 'abcdef',
|
||||
);
|
||||
|
||||
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
|
||||
$form->expects($this->any())
|
||||
->method('getNormData')
|
||||
->will($this->returnValue($existingData));
|
||||
|
||||
$event = new FilterDataEvent($form, null);
|
||||
|
||||
$filter = new FixFileUploadListener($this->storage);
|
||||
$filter->onBindClientData($event);
|
||||
|
||||
$this->assertSame($existingData, $event->getData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException Symfony\Component\Form\Exception\UnexpectedTypeException
|
||||
*/
|
||||
public function testExpectNullOrArray()
|
||||
{
|
||||
$form = $this->getMock('Symfony\Tests\Component\Form\FormInterface');
|
||||
$event = new FilterDataEvent($form, 'foobar');
|
||||
|
||||
$filter = new FixFileUploadListener($this->storage);
|
||||
$filter->onBindClientData($event);
|
||||
}
|
||||
|
||||
private function createUploadedFileMock($name, $originalName, $valid)
|
||||
{
|
||||
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$file->expects($this->any())
|
||||
->method('getName')
|
||||
->will($this->returnValue($name));
|
||||
$file->expects($this->any())
|
||||
->method('getOriginalName')
|
||||
->will($this->returnValue($originalName));
|
||||
$file->expects($this->any())
|
||||
->method('isValid')
|
||||
->will($this->returnValue($valid));
|
||||
|
||||
return $file;
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 35 B |
@ -1,172 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Tests\Component\Form\Extension\Core\Type;
|
||||
|
||||
use Symfony\Component\Form\FileField;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
class FileTypeTest extends TypeTestCase
|
||||
{
|
||||
public static $tmpFiles = array();
|
||||
|
||||
protected static $tmpDir;
|
||||
|
||||
protected $form;
|
||||
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
self::$tmpDir = sys_get_temp_dir().DIRECTORY_SEPARATOR.'symfony-test';
|
||||
|
||||
if (!file_exists(self::$tmpDir)) {
|
||||
mkdir(self::$tmpDir, 0777, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->form = $this->factory->create('file');
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
foreach (self::$tmpFiles as $key => $file) {
|
||||
@unlink($file);
|
||||
unset(self::$tmpFiles[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function createTmpFile($path)
|
||||
{
|
||||
self::$tmpFiles[] = $path;
|
||||
file_put_contents($path, 'foobar');
|
||||
}
|
||||
|
||||
public function testSubmitUploadsNewFiles()
|
||||
{
|
||||
$tmpDir = self::$tmpDir;
|
||||
$generatedToken = '';
|
||||
|
||||
$this->storage->expects($this->atLeastOnce())
|
||||
->method('getTempDir')
|
||||
->will($this->returnCallback(function ($token) use ($tmpDir, &$generatedToken) {
|
||||
// A 6-digit token is generated by FileUploader and passed
|
||||
// to getTempDir()
|
||||
$generatedToken = $token;
|
||||
|
||||
return $tmpDir;
|
||||
}));
|
||||
|
||||
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$file->expects($this->once())
|
||||
->method('move')
|
||||
->with($this->equalTo($tmpDir));
|
||||
$file->expects($this->any())
|
||||
->method('isValid')
|
||||
->will($this->returnValue(true));
|
||||
$file->expects($this->any())
|
||||
->method('getName')
|
||||
->will($this->returnValue('original_name.jpg'));
|
||||
$file->expects($this->any())
|
||||
->method('getPath')
|
||||
->will($this->returnValue($tmpDir.'/original_name.jpg'));
|
||||
|
||||
$this->form->bind(array(
|
||||
'file' => $file,
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
));
|
||||
|
||||
$this->assertRegExp('/^\d{6}$/', $generatedToken);
|
||||
$this->assertEquals(array(
|
||||
'file' => $file,
|
||||
'token' => $generatedToken,
|
||||
'name' => 'original_name.jpg',
|
||||
), $this->form->getClientData());
|
||||
$this->assertEquals($tmpDir.'/original_name.jpg', $this->form->getData());
|
||||
}
|
||||
|
||||
public function testSubmitKeepsUploadedFilesOnErrors()
|
||||
{
|
||||
$tmpDir = self::$tmpDir;
|
||||
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
|
||||
$this->createTmpFile($tmpPath);
|
||||
|
||||
$this->storage->expects($this->atLeastOnce())
|
||||
->method('getTempDir')
|
||||
->with($this->equalTo('123456'))
|
||||
->will($this->returnValue($tmpDir));
|
||||
|
||||
$this->form->bind(array(
|
||||
'file' => null,
|
||||
'token' => '123456',
|
||||
'name' => 'original_name.jpg',
|
||||
));
|
||||
|
||||
$this->assertTrue(file_exists($tmpPath));
|
||||
|
||||
$file = new File($tmpPath);
|
||||
|
||||
$this->assertEquals(array(
|
||||
'file' => $file,
|
||||
'token' => '123456',
|
||||
'name' => 'original_name.jpg',
|
||||
), $this->form->getClientData());
|
||||
$this->assertEquals(realpath($tmpPath), realpath($this->form->getData()));
|
||||
}
|
||||
|
||||
public function testSubmitEmpty()
|
||||
{
|
||||
$this->storage->expects($this->never())
|
||||
->method('getTempDir');
|
||||
|
||||
$this->form->bind(array(
|
||||
'file' => '',
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'file' => '',
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
), $this->form->getClientData());
|
||||
$this->assertEquals(null, $this->form->getData());
|
||||
}
|
||||
|
||||
public function testSubmitEmptyKeepsExistingFiles()
|
||||
{
|
||||
$tmpPath = self::$tmpDir . DIRECTORY_SEPARATOR . 'original_name.jpg';
|
||||
$this->createTmpFile($tmpPath);
|
||||
$file = new File($tmpPath);
|
||||
|
||||
$this->storage->expects($this->never())
|
||||
->method('getTempDir');
|
||||
|
||||
$this->form->setData($tmpPath);
|
||||
$this->form->bind(array(
|
||||
'file' => '',
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
));
|
||||
|
||||
$this->assertEquals(array(
|
||||
'file' => $file,
|
||||
'token' => '',
|
||||
'name' => '',
|
||||
), $this->form->getClientData());
|
||||
$this->assertEquals(realpath($tmpPath), realpath($this->form->getData()));
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user