[HttpFoundation] Make File extends \SplFileInfo

This commit is contained in:
Victor Berchet 2011-06-14 10:47:04 +02:00
parent 2ce3cfad18
commit ac0c00c6e8
8 changed files with 268 additions and 309 deletions

View File

@ -20,7 +20,7 @@ use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
* *
* @author Bernhard Schussek <bernhard.schussek@symfony.com> * @author Bernhard Schussek <bernhard.schussek@symfony.com>
*/ */
class File class File extends \SplFileInfo
{ {
/** /**
* A map of mime types and their default extensions. * A map of mime types and their default extensions.
@ -440,13 +440,6 @@ class File
'x-world/x-vrml' => 'wrl', 'x-world/x-vrml' => 'wrl',
); );
/**
* The absolute path to the file without dots.
*
* @var string
*/
protected $path;
/** /**
* Constructs a new file from the given path. * Constructs a new file from the given path.
* *
@ -460,41 +453,7 @@ class File
throw new FileNotFoundException($path); throw new FileNotFoundException($path);
} }
$this->path = realpath($path); parent::__construct($path);
}
/**
* Alias for getPath().
*
* @return string
*/
public function __toString()
{
return (string) $this->path;
}
/**
* Returns the file name.
*
* @return string
*/
public function getName()
{
return basename($this->path);
}
/**
* Returns the file extension.
*
* @return string
*/
public function getExtension()
{
if ($ext = pathinfo($this->getName(), PATHINFO_EXTENSION)) {
return $ext;
}
return '';
} }
/** /**
@ -508,31 +467,7 @@ class File
{ {
$type = $this->getMimeType(); $type = $this->getMimeType();
if (isset(self::$defaultExtensions[$type])) { return isset(static::$defaultExtensions[$type]) ? static::$defaultExtensions[$type] : null;
return self::$defaultExtensions[$type];
}
return null;
}
/**
* Returns the directory of the file.
*
* @return string
*/
public function getDirectory()
{
return dirname($this->path);
}
/**
* Returns the absolute file path, without dots.
*
* @return string
*/
public function getPath()
{
return $this->path;
} }
/** /**
@ -542,28 +477,13 @@ class File
* and the system binary "file" (in this order), depending on which of those * and the system binary "file" (in this order), depending on which of those
* is available on the current operating system. * is available on the current operating system.
* *
* @return string The guessed mime type (i.e. "application/pdf") * @return string|null The guessed mime type (i.e. "application/pdf")
*/ */
public function getMimeType() public function getMimeType()
{ {
$guesser = MimeTypeGuesser::getInstance(); $guesser = MimeTypeGuesser::getInstance();
return $guesser->guess($this->getPath()); return $guesser->guess($this->getPathname());
}
/**
* Returns the size of this file.
*
* @return integer The file size in bytes
*/
public function getSize()
{
if (false === $size = @filesize($this->getPath())) {
$error = error_get_last();
throw new FileException(sprintf('Could not read file size of %s (%s)', $this->getPath(), strip_tags($error['message'])));
}
return $size;
} }
/** /**
@ -571,16 +491,30 @@ class File
* *
* @param string $directory The destination folder * @param string $directory The destination folder
* @param string $name The new file name * @param string $name The new file name
*
* @return File A File object representing the new file
*
* @throws FileException if the target file could not be created
*/ */
public function move($directory, $name = null) public function move($directory, $name = null)
{ {
$newPath = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getName() : $name); if (!is_dir($directory)) {
if (false === @mkdir($directory, 0777, true)) {
if (!@rename($this->getPath(), $newPath)) { throw new FileException(sprintf('Unable to create the "%s" directory', $directory));
$error = error_get_last(); }
throw new FileException(sprintf('Could not move file %s to %s (%s)', $this->getPath(), $newPath, strip_tags($error['message']))); } elseif (!is_writable($directory)) {
throw new FileException(sprintf('Unable to write in the "%s" directory', $directory));
} }
$this->path = realpath($newPath); $target = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getBasename() : basename($name));
if (!@rename($this->getPathname(), $target)) {
$error = error_get_last();
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
}
chmod($target, 0666);
return new File($target);
} }
} }

View File

@ -23,33 +23,42 @@ use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;
*/ */
class UploadedFile extends File class UploadedFile extends File
{ {
/**
* Whether the test mode is activated.
*
* Local files are used in test mode hence the code should not enforce HTTP uploads.
*
* @var Boolean
*/
private $test = false;
/** /**
* The original name of the uploaded file. * The original name of the uploaded file.
* *
* @var string * @var string
*/ */
protected $originalName; private $originalName;
/** /**
* The mime type provided by the uploader. * The mime type provided by the uploader.
* *
* @var string * @var string
*/ */
protected $mimeType; private $mimeType;
/** /**
* The file size provided by the uploader. * The file size provided by the uploader.
* *
* @var integer * @var string
*/ */
protected $size; private $size;
/** /**
* The UPLOAD_ERR_XXX constant provided by the uploader. * The UPLOAD_ERR_XXX constant provided by the uploader.
* *
* @var integer * @var integer
*/ */
protected $error; private $error;
/** /**
* Accepts the information of the uploaded file as provided by the PHP global $_FILES. * Accepts the information of the uploaded file as provided by the PHP global $_FILES.
@ -59,69 +68,65 @@ class UploadedFile extends File
* @param string $mimeType The type of the file as provided by PHP * @param string $mimeType The type of the file as provided by PHP
* @param integer $size The file size * @param integer $size The file size
* @param integer $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants) * @param integer $error The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants)
* @param Boolean $test Whether the test mode is active
* *
* @throws FileException If file_uploads is disabled * @throws FileException If file_uploads is disabled
* @throws FileNotFoundException If the file does not exist * @throws FileNotFoundException If the file does not exist
*/ */
public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null) public function __construct($path, $originalName, $mimeType = null, $size = null, $error = null, $test = false)
{ {
if (!ini_get('file_uploads')) { 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'))); 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')));
} }
if (!is_file($path)) {
throw new FileNotFoundException($path);
}
$this->path = realpath($path);
$this->originalName = basename($originalName); $this->originalName = basename($originalName);
$this->mimeType = $mimeType ?: 'application/octet-stream'; $this->mimeType = $mimeType ?: 'application/octet-stream';
$this->size = $size; $this->size = $size;
$this->error = $error ?: UPLOAD_ERR_OK; $this->error = $error ?: UPLOAD_ERR_OK;
$this->test = (Boolean) $test;
parent::__construct($path);
} }
/** /**
* {@inheritDoc} * Returns the original file name.
*/
public function getMimeType()
{
return parent::getMimeType() ?: $this->mimeType;
}
/**
* {@inheritDoc}
*/
public function getSize()
{
return null === $this->size ? parent::getSize() : $this->size;
}
/**
* {@inheritDoc}
*/
public function getExtension()
{
if ($ext = pathinfo($this->getOriginalName(), PATHINFO_EXTENSION)) {
return $ext;
}
return '';
}
/**
* Gets the original uploaded name.
* *
* Warning: This name is not safe as it can have been manipulated by the end-user. * It is extracted from the request from which the file has been uploaded.
* Moreover, it can contain characters that are not allowed in file names. * Then is should not be considered as a safe value.
* Never use it in a path.
* *
* @return string * @return string|null The original name
*/ */
public function getOriginalName() public function getClientOriginalName()
{ {
return $this->originalName; return $this->originalName;
} }
/**
* Returns the file mime type.
*
* It is extracted from the request from which the file has been uploaded.
* Then is should not be considered as a safe value.
*
* @return string|null The mime type
*/
public function getClientMimeType()
{
return $this->mimeType;
}
/**
* Returns the file size.
*
* It is extracted from the request from which the file has been uploaded.
* Then is should not be considered as a safe value.
*
* @return integer|null The file size
*/
public function getClientSize()
{
return $this->size;
}
/** /**
* Returns the upload error. * Returns the upload error.
* *
@ -146,17 +151,21 @@ class UploadedFile extends File
} }
/** /**
* {@inheritDoc} * Moves the file to a new location.
*
* @param string $directory The destination folder
* @param string $name The new file name
*
* @return File A File object representing the new file
*
* @throws FileException if the file has not been uploaded via Http
*/ */
public function move($directory, $name = null) public function move($directory, $name = null)
{ {
$newPath = $directory.DIRECTORY_SEPARATOR.(null === $name ? $this->getName() : $name); if (!$this->test && !is_uploaded_file($this->getPathname())) {
throw new FileException(sprintf('The file "%s" has not been uploaded via Http', $this->getPathname()));
if (!@move_uploaded_file($this->getPath(), $newPath)) {
$error = error_get_last();
throw new FileException(sprintf('Could not move file %s to %s (%s)', $this->getPath(), $newPath, strip_tags($error['message'])));
} }
$this->path = realpath($newPath); return parent::move($directory, $name);
} }
} }

View File

@ -120,7 +120,7 @@ EOF;
if (is_array($value)) { if (is_array($value)) {
$filtered[$key] = $this->filterFiles($value); $filtered[$key] = $this->filterFiles($value);
} elseif ($value instanceof UploadedFile) { } elseif ($value instanceof UploadedFile) {
// create an already-moved uploaded file // Create a test mode UploadedFile
$filtered[$key] = new UploadedFile($value->getPath(), $value->getName(), $value->getMimeType(), $value->getSize(), $value->getError(), true); $filtered[$key] = new UploadedFile($value->getPath(), $value->getName(), $value->getMimeType(), $value->getSize(), $value->getError(), true);
} else { } else {
$filtered[$key] = $value; $filtered[$key] = $value;

View File

@ -29,11 +29,7 @@ class FileValidator extends ConstraintValidator
throw new UnexpectedTypeException($value, 'string'); throw new UnexpectedTypeException($value, 'string');
} }
if ($value instanceof FileObject && null === $value->getPath()) { $path = $value instanceof FileObject ? $value->getPathname() : (string) $value;
return true;
}
$path = $value instanceof FileObject ? $value->getPath() : (string) $value;
if (!file_exists($path)) { if (!file_exists($path)) {
$this->setMessage($constraint->notFoundMessage, array('{{ file }}' => $path)); $this->setMessage($constraint->notFoundMessage, array('{{ file }}' => $path));
@ -66,9 +62,9 @@ class FileValidator extends ConstraintValidator
if ($size > $limit) { if ($size > $limit) {
$this->setMessage($constraint->maxSizeMessage, array( $this->setMessage($constraint->maxSizeMessage, array(
'{{ size }}' => $size . $suffix, '{{ size }}' => $size . $suffix,
'{{ limit }}' => $limit . $suffix, '{{ limit }}' => $limit . $suffix,
'{{ file }}' => $path, '{{ file }}' => $path,
)); ));
return false; return false;
@ -82,9 +78,9 @@ class FileValidator extends ConstraintValidator
if (!in_array($value->getMimeType(), (array) $constraint->mimeTypes)) { if (!in_array($value->getMimeType(), (array) $constraint->mimeTypes)) {
$this->setMessage($constraint->mimeTypesMessage, array( $this->setMessage($constraint->mimeTypesMessage, array(
'{{ type }}' => '"'.$value->getMimeType().'"', '{{ type }}' => '"'.$value->getMimeType().'"',
'{{ types }}' => '"'.implode('", "', (array) $constraint->mimeTypes).'"', '{{ types }}' => '"'.implode('", "', (array) $constraint->mimeTypes).'"',
'{{ file }}' => $path, '{{ file }}' => $path,
)); ));
return false; return false;

View File

@ -30,18 +30,26 @@ class FileTypeTest extends TypeTestCase
private function createUploadedFileMock($name, $originalName, $valid) private function createUploadedFileMock($name, $originalName, $valid)
{ {
$file = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile') $file = $this
->getMockBuilder('Symfony\Component\HttpFoundation\File\UploadedFile')
->disableOriginalConstructor() ->disableOriginalConstructor()
->getMock(); ->getMock()
$file->expects($this->any()) ;
->method('getName') $file
->will($this->returnValue($name)); ->expects($this->any())
$file->expects($this->any()) ->method('getBasename')
->method('getOriginalName') ->will($this->returnValue($name))
->will($this->returnValue($originalName)); ;
$file->expects($this->any()) $file
->expects($this->any())
->method('getClientOriginalName')
->will($this->returnValue($originalName))
;
$file
->expects($this->any())
->method('isValid') ->method('isValid')
->will($this->returnValue($valid)); ->will($this->returnValue($valid))
;
return $file; return $file;
} }

View File

@ -19,49 +19,15 @@ class FileTest extends \PHPUnit_Framework_TestCase
{ {
protected $file; protected $file;
protected function setUp()
{
$this->file = new File(__DIR__.'/Fixtures/test.gif');
}
public function testGetPathReturnsAbsolutePath()
{
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.gif', $this->file->getPath());
}
public function test__toString()
{
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.gif', (string) $this->file);
}
public function testGetNameReturnsNameWithExtension()
{
$this->assertEquals('test.gif', $this->file->getName());
}
public function testGetExtensionReturnsEmptyString()
{
$file = new File(__DIR__.'/Fixtures/test');
$this->assertEquals('', $file->getExtension());
}
public function testGetExtensionReturnsExtensionWithDot()
{
$this->assertEquals('gif', $this->file->getExtension());
}
public function testGetDirectoryReturnsDirectoryName()
{
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures', $this->file->getDirectory());
}
public function testGetMimeTypeUsesMimeTypeGuessers() public function testGetMimeTypeUsesMimeTypeGuessers()
{ {
$guesser = $this->createMockGuesser($this->file->getPath(), 'image/gif'); $file = new File(__DIR__.'/Fixtures/test.gif');
$guesser = $this->createMockGuesser($file->getPathname(), 'image/gif');
MimeTypeGuesser::getInstance()->register($guesser); MimeTypeGuesser::getInstance()->register($guesser);
$this->assertEquals('image/gif', $this->file->getMimeType()); $this->assertEquals('image/gif', $file->getMimeType());
} }
public function testGuessExtensionWithoutGuesser() public function testGuessExtensionWithoutGuesser()
@ -74,7 +40,7 @@ class FileTest extends \PHPUnit_Framework_TestCase
public function testGuessExtensionIsBasedOnMimeType() public function testGuessExtensionIsBasedOnMimeType()
{ {
$file = new File(__DIR__.'/Fixtures/test'); $file = new File(__DIR__.'/Fixtures/test');
$guesser = $this->createMockGuesser($file->getPath(), 'image/gif'); $guesser = $this->createMockGuesser($file->getPathname(), 'image/gif');
MimeTypeGuesser::getInstance()->register($guesser); MimeTypeGuesser::getInstance()->register($guesser);
@ -88,100 +54,77 @@ class FileTest extends \PHPUnit_Framework_TestCase
new File(__DIR__.'/Fixtures/not_here'); new File(__DIR__.'/Fixtures/not_here');
} }
public function testSizeReturnsFileSize()
{
$this->assertEquals(filesize($this->file->getPath()), $this->file->getSize());
}
public function testSizeFailing()
{
$dir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'directory';
$path = $dir.DIRECTORY_SEPARATOR.'test.copy.gif';
@unlink($path);
copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new File($path);
@unlink($path);
try {
$file->getSize();
$this->fail('File::getSize should throw an exception.');
} catch (FileException $e) {
}
}
public function testMove() public function testMove()
{ {
$path = __DIR__.'/Fixtures/test.copy.gif'; $path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'directory'; $targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.DIRECTORY_SEPARATOR.'test.copy.gif'; $targetPath = $targetDir.'/test.copy.gif';
@unlink($path); @unlink($path);
@unlink($targetPath); @unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path); copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new File($path); $file = new File($path);
$file->move($targetDir); $movedFile = $file->move($targetDir);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\File\File', $movedFile);
$this->assertTrue(file_exists($targetPath)); $this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path)); $this->assertFalse(file_exists($path));
$this->assertEquals($targetPath, $file->getPath()); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($path);
@unlink($targetPath); @unlink($targetPath);
} }
public function testMoveWithNewName() public function testMoveWithNewName()
{ {
$path = __DIR__.'/Fixtures/test.copy.gif'; $path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'directory'; $targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.DIRECTORY_SEPARATOR.'test.newname.gif'; $targetPath = $targetDir.'/test.newname.gif';
@unlink($path); @unlink($path);
@unlink($targetPath); @unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path); copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new File($path); $file = new File($path);
$file->move($targetDir, 'test.newname.gif'); $movedFile = $file->move($targetDir, 'test.newname.gif');
$this->assertTrue(file_exists($targetPath)); $this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path)); $this->assertFalse(file_exists($path));
$this->assertEquals($targetPath, $file->getPath()); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($path);
@unlink($targetPath); @unlink($targetPath);
} }
public function testMoveFailing() public function testMoveToAnUnexistentDirectory()
{ {
$path = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.copy.gif'; $sourcePath = __DIR__.'/Fixtures/test.copy.gif';
$targetPath = '/thisfolderwontexist'; $targetDir = __DIR__.'/Fixtures/directory/sub';
@unlink($path); $targetPath = $targetDir.'/test.copy.gif';
@unlink($sourcePath);
@unlink($targetPath); @unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path); @rmdir($targetDir);
copy(__DIR__.'/Fixtures/test.gif', $sourcePath);
$file = new File($path); $file = new File($sourcePath);
$movedFile = $file->move($targetDir);
try { $this->assertFileExists($targetPath);
$file->move($targetPath); $this->assertFileNotExists($sourcePath);
$this->fail('File::move should throw an exception.'); $this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
} catch (FileException $e) {
}
$this->assertFileExists($path); @unlink($sourcePath);
$this->assertFileNotExists($path.$targetPath.'test.gif');
$this->assertEquals($path, $file->getPath());
@unlink($path);
@unlink($targetPath); @unlink($targetPath);
@rmdir($targetDir);
} }
protected function createMockGuesser($path, $mimeType) protected function createMockGuesser($path, $mimeType)
{ {
$guesser = $this->getMock('Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface'); $guesser = $this->getMock('Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface');
$guesser->expects($this->once()) $guesser
->method('guess') ->expects($this->once())
->with($this->equalTo($path)) ->method('guess')
->will($this->returnValue($mimeType)); ->with($this->equalTo($path))
->will($this->returnValue($mimeType))
;
return $guesser; return $guesser;
} }
} }

View File

@ -32,11 +32,10 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
UPLOAD_ERR_OK UPLOAD_ERR_OK
); );
$this->assertAttributeEquals('application/octet-stream', 'mimeType', $file); $this->assertEquals('application/octet-stream', $file->getClientMimeType());
if (extension_loaded('fileinfo')) { if (extension_loaded('fileinfo')) {
$this->assertEquals('image/gif', $file->getMimeType()); $this->assertEquals('image/gif', $file->getMimeType());
} else {
$this->assertEquals('application/octet-stream', $file->getMimeType());
} }
} }
@ -50,8 +49,7 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
UPLOAD_ERR_OK UPLOAD_ERR_OK
); );
$this->assertAttributeEquals('application/octet-stream', 'mimeType', $file); $this->assertEquals('application/octet-stream', $file->getClientMimeType());
$this->assertEquals('application/octet-stream', $file->getMimeType());
} }
public function testErrorIsOkByDefault() public function testErrorIsOkByDefault()
@ -67,7 +65,7 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(UPLOAD_ERR_OK, $file->getError()); $this->assertEquals(UPLOAD_ERR_OK, $file->getError());
} }
public function testGetOriginalName() public function testGetClientOriginalName()
{ {
$file = new UploadedFile( $file = new UploadedFile(
__DIR__.'/Fixtures/test.gif', __DIR__.'/Fixtures/test.gif',
@ -77,10 +75,54 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
null null
); );
$this->assertEquals('original.gif', $file->getOriginalName()); $this->assertEquals('original.gif', $file->getClientOriginalName());
} }
public function testGetOriginalNameSanitizeFilename() /**
* @expectedException Symfony\Component\HttpFoundation\File\Exception\FileException
*/
public function testMoveLocalFileIsNotAllowed()
{
$file = new UploadedFile(
__DIR__.'/Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/Fixtures/test.gif'),
UPLOAD_ERR_OK
);
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
}
public function testMoveLocalFileIsAllowedInTestMode()
{
$path = __DIR__.'/Fixtures/test.copy.gif';
$targetDir = __DIR__.'/Fixtures/directory';
$targetPath = $targetDir.'/test.copy.gif';
@unlink($path);
@unlink($targetPath);
copy(__DIR__.'/Fixtures/test.gif', $path);
$file = new UploadedFile(
$path,
'original.gif',
'image/gif',
filesize($path),
UPLOAD_ERR_OK,
true
);
$movedFile = $file->move(__DIR__.'/Fixtures/directory');
$this->assertTrue(file_exists($targetPath));
$this->assertFalse(file_exists($path));
$this->assertEquals(realpath($targetPath), $movedFile->getRealPath());
@unlink($targetPath);
}
public function testGetClientOriginalNameSanitizeFilename()
{ {
$file = new UploadedFile( $file = new UploadedFile(
__DIR__.'/Fixtures/test.gif', __DIR__.'/Fixtures/test.gif',
@ -90,6 +132,6 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
null null
); );
$this->assertEquals('original.gif', $file->getOriginalName()); $this->assertEquals('original.gif', $file->getClientOriginalName());
} }
} }

View File

@ -13,6 +13,7 @@ namespace Symfony\Tests\Component\Validator\Constraints;
use Symfony\Component\Validator\Constraints\File; use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\Validator\Constraints\FileValidator; use Symfony\Component\Validator\Constraints\FileValidator;
use Symfony\Component\HttpFoundation\File\File as FileObject;
class FileValidatorTest extends \PHPUnit_Framework_TestCase class FileValidatorTest extends \PHPUnit_Framework_TestCase
{ {
@ -42,10 +43,11 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertTrue($this->validator->isValid('', new File())); $this->assertTrue($this->validator->isValid('', new File()));
} }
/**
* @expectedException Symfony\Component\Validator\Exception\UnexpectedTypeException
*/
public function testExpectsStringCompatibleTypeOrFile() public function testExpectsStringCompatibleTypeOrFile()
{ {
$this->setExpectedException('Symfony\Component\Validator\Exception\UnexpectedTypeException');
$this->validator->isValid(new \stdClass(), new File()); $this->validator->isValid(new \stdClass(), new File());
} }
@ -59,16 +61,16 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
fwrite($this->file, str_repeat('0', 11)); fwrite($this->file, str_repeat('0', 11));
$constraint = new File(array( $constraint = new File(array(
'maxSize' => 10, 'maxSize' => 10,
'maxSizeMessage' => 'myMessage', 'maxSizeMessage' => 'myMessage',
)); ));
$this->assertFalse($this->validator->isValid($this->path, $constraint)); $this->assertFileValid($this->path, $constraint, false);
$this->assertEquals($this->validator->getMessageTemplate(), 'myMessage'); $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
$this->assertEquals($this->validator->getMessageParameters(), array( $this->assertEquals($this->validator->getMessageParameters(), array(
'{{ limit }}' => '10 bytes', '{{ limit }}' => '10 bytes',
'{{ size }}' => '11 bytes', '{{ size }}' => '11 bytes',
'{{ file }}' => $this->path, '{{ file }}' => $this->path,
)); ));
} }
@ -77,16 +79,16 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
fwrite($this->file, str_repeat('0', 1400)); fwrite($this->file, str_repeat('0', 1400));
$constraint = new File(array( $constraint = new File(array(
'maxSize' => '1k', 'maxSize' => '1k',
'maxSizeMessage' => 'myMessage', 'maxSizeMessage' => 'myMessage',
)); ));
$this->assertFalse($this->validator->isValid($this->path, $constraint)); $this->assertFileValid($this->path, $constraint, false);
$this->assertEquals($this->validator->getMessageTemplate(), 'myMessage'); $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
$this->assertEquals($this->validator->getMessageParameters(), array( $this->assertEquals($this->validator->getMessageParameters(), array(
'{{ limit }}' => '1 kB', '{{ limit }}' => '1 kB',
'{{ size }}' => '1.4 kB', '{{ size }}' => '1.4 kB',
'{{ file }}' => $this->path, '{{ file }}' => $this->path,
)); ));
} }
@ -95,27 +97,28 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
fwrite($this->file, str_repeat('0', 1400000)); fwrite($this->file, str_repeat('0', 1400000));
$constraint = new File(array( $constraint = new File(array(
'maxSize' => '1M', 'maxSize' => '1M',
'maxSizeMessage' => 'myMessage', 'maxSizeMessage' => 'myMessage',
)); ));
$this->assertFalse($this->validator->isValid($this->path, $constraint)); $this->assertFileValid($this->path, $constraint, false);
$this->assertEquals($this->validator->getMessageTemplate(), 'myMessage'); $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
$this->assertEquals($this->validator->getMessageParameters(), array( $this->assertEquals($this->validator->getMessageParameters(), array(
'{{ limit }}' => '1 MB', '{{ limit }}' => '1 MB',
'{{ size }}' => '1.4 MB', '{{ size }}' => '1.4 MB',
'{{ file }}' => $this->path, '{{ file }}' => $this->path,
)); ));
} }
/**
* @expectedException Symfony\Component\Validator\Exception\ConstraintDefinitionException
*/
public function testInvalidMaxSize() public function testInvalidMaxSize()
{ {
$constraint = new File(array( $constraint = new File(array(
'maxSize' => '1abc', 'maxSize' => '1abc',
)); ));
$this->setExpectedException('Symfony\Component\Validator\Exception\ConstraintDefinitionException');
$this->validator->isValid($this->path, $constraint); $this->validator->isValid($this->path, $constraint);
} }
@ -125,7 +128,7 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
'notFoundMessage' => 'myMessage', 'notFoundMessage' => 'myMessage',
)); ));
$this->assertFalse($this->validator->isValid('foobar', $constraint)); $this->assertFileValid('foobar', $constraint, false);
$this->assertEquals($this->validator->getMessageTemplate(), 'myMessage'); $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
$this->assertEquals($this->validator->getMessageParameters(), array( $this->assertEquals($this->validator->getMessageParameters(), array(
'{{ file }}' => 'foobar', '{{ file }}' => 'foobar',
@ -134,13 +137,21 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
public function testValidMimeType() public function testValidMimeType()
{ {
$file = $this->getMock('Symfony\Component\HttpFoundation\File\File', array(), array(), '', false); $file = $this
$file->expects($this->any()) ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
->method('getPath') ->disableOriginalConstructor()
->will($this->returnValue($this->path)); ->getMock()
$file->expects($this->any()) ;
->method('getMimeType') $file
->will($this->returnValue('image/jpg')); ->expects($this->once())
->method('getPathname')
->will($this->returnValue($this->path))
;
$file
->expects($this->once())
->method('getMimeType')
->will($this->returnValue('image/jpg'))
;
$constraint = new File(array( $constraint = new File(array(
'mimeTypes' => array('image/png', 'image/jpg'), 'mimeTypes' => array('image/png', 'image/jpg'),
@ -151,13 +162,21 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
public function testInvalidMimeType() public function testInvalidMimeType()
{ {
$file = $this->getMock('Symfony\Component\HttpFoundation\File\File', array(), array(), '', false); $file = $this
$file->expects($this->any()) ->getMockBuilder('Symfony\Component\HttpFoundation\File\File')
->method('getPath') ->disableOriginalConstructor()
->will($this->returnValue($this->path)); ->getMock()
$file->expects($this->any()) ;
->method('getMimeType') $file
->will($this->returnValue('application/pdf')); ->expects($this->once())
->method('getPathname')
->will($this->returnValue($this->path))
;
$file
->expects($this->exactly(2))
->method('getMimeType')
->will($this->returnValue('application/pdf'))
;
$constraint = new File(array( $constraint = new File(array(
'mimeTypes' => array('image/png', 'image/jpg'), 'mimeTypes' => array('image/png', 'image/jpg'),
@ -167,9 +186,17 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($this->validator->isValid($file, $constraint)); $this->assertFalse($this->validator->isValid($file, $constraint));
$this->assertEquals($this->validator->getMessageTemplate(), 'myMessage'); $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
$this->assertEquals($this->validator->getMessageParameters(), array( $this->assertEquals($this->validator->getMessageParameters(), array(
'{{ type }}' => '"application/pdf"', '{{ type }}' => '"application/pdf"',
'{{ types }}' => '"image/png", "image/jpg"', '{{ types }}' => '"image/png", "image/jpg"',
'{{ file }}' => $this->path, '{{ file }}' => $this->path,
)); ));
} }
}
protected function assertFileValid($filename, File $constraint, $valid = true)
{
$this->assertEquals($this->validator->isValid($filename, $constraint), $valid);
if (file_exists($filename)) {
$this->assertEquals($this->validator->isValid(new FileObject($filename), $constraint), $valid);
}
}
}