Skip to content

Commit

Permalink
[Form] Added test for last commit by kriswallsmith and improved deali…
Browse files Browse the repository at this point in the history
…ng 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.
  • Loading branch information
webmozart committed May 4, 2011
1 parent 4c6f26f commit bf1dfbb
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 186 deletions.
Expand Up @@ -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>
Expand Up @@ -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 %}
Expand Down
Expand Up @@ -26,8 +26,6 @@ public function transform($file)
if (null === $file || '' === $file) {
return array(
'file' => '',
'token' => '',
'name' => '',
);
}

Expand All @@ -37,8 +35,6 @@ public function transform($file)

return array(
'file' => $file,
'token' => '',
'name' => '',
);
}

Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -42,17 +43,19 @@ public function onBindClientData(FilterDataEvent $event)
$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
Expand All @@ -61,14 +64,15 @@ public function onBindClientData(FilterDataEvent $event)
$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);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/Form/Extension/Core/Type/FileType.php
Expand Up @@ -45,7 +45,8 @@ public function buildForm(FormBuilder $builder, array $options)
->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)
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Form/FormInterface.php
Expand Up @@ -50,6 +50,8 @@ function setData($data);

function getData();

function getNormData();

function getClientData();

function isBound();
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Component/HttpFoundation/File/UploadedFile.php
Expand Up @@ -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')));
Expand Down
3 changes: 2 additions & 1 deletion tests/Symfony/Tests/Component/Form/AbstractLayoutTest.php
Expand Up @@ -664,8 +664,9 @@ public function testFile()
./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]
'
);
}
Expand Down
@@ -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.

0 comments on commit bf1dfbb

Please sign in to comment.