[Form][HttpFoundation] Improved File and UploadedFile class
This commit is contained in:
parent
708c780213
commit
8513082007
@ -84,7 +84,8 @@ class FileField extends FieldGroup
|
||||
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['file']->move($this->getTmpDir());
|
||||
$data['file']->rename($this->getTmpName($data['token']));
|
||||
$data['original_name'] = $data['file']->getOriginalName();
|
||||
$data['file'] = '';
|
||||
break;
|
||||
@ -123,13 +124,23 @@ class FileField extends FieldGroup
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute temporary file path for the given token
|
||||
* Returns the absolute temporary path to the uploaded file
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
protected function getTmpPath($token)
|
||||
{
|
||||
return realpath($this->getOption('tmp_dir')) . '/' . $this->getTmpName($token);
|
||||
return $this->getTmpDir() . DIRECTORY_SEPARATOR . $this->getTmpName($token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the temporary directory where files are stored
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
protected function getTmpDir()
|
||||
{
|
||||
return realpath($this->getOption('tmp_dir'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -438,12 +438,42 @@ class File
|
||||
'x-world/x-vrml' => 'wrl',
|
||||
);
|
||||
|
||||
/**
|
||||
* Stores the absolute path to the document root directory
|
||||
* @var string
|
||||
*/
|
||||
static protected $documentRoot;
|
||||
|
||||
/**
|
||||
* The absolute path to the file without dots
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Sets the path t the document root directory
|
||||
*
|
||||
* @param string $documentRoot
|
||||
*/
|
||||
static public function setDocumentRoot($documentRoot)
|
||||
{
|
||||
if (!is_dir($documentRoot)) {
|
||||
throw new \LogicException($documentRoot . ' is no directory');
|
||||
}
|
||||
|
||||
self::$documentRoot = realpath($documentRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path to the document root directory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static public function getDocumentRoot()
|
||||
{
|
||||
return self::$documentRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new file from the given path.
|
||||
*
|
||||
@ -533,6 +563,26 @@ class File
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path relative to the document root
|
||||
*
|
||||
* You can set the document root using the static method setDocumentRoot().
|
||||
* If the file is outside of the document root, this method returns an
|
||||
* empty string.
|
||||
*
|
||||
* @return string The relative file path
|
||||
*/
|
||||
public function getWebPath()
|
||||
{
|
||||
$root = self::$documentRoot;
|
||||
|
||||
if (strpos($this->path, $root) === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return str_replace(array($root, DIRECTORY_SEPARATOR), array('', '/'), $this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the file.
|
||||
*
|
||||
@ -564,16 +614,40 @@ class File
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file to a new location.
|
||||
* Moves the file to a new directory and gives it a new filename
|
||||
*
|
||||
* @param string $newPath
|
||||
* @param string $directory The new directory
|
||||
* @param string $filename The new file name
|
||||
* @throws FileException When the file could not be moved
|
||||
*/
|
||||
public function move($newPath)
|
||||
protected function doMove($directory, $filename)
|
||||
{
|
||||
$newPath = $directory . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
if (!rename($this->getPath(), $newPath)) {
|
||||
throw new FileException(sprintf('Could not move file %s to %s', $this->getPath(), $newPath));
|
||||
}
|
||||
|
||||
$this->path = realpath($newPath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file to a new location.
|
||||
*
|
||||
* @param string $directory
|
||||
*/
|
||||
public function move($directory)
|
||||
{
|
||||
$this->doMove($directory, $this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the file
|
||||
*
|
||||
* @param string $name The new file name
|
||||
*/
|
||||
public function rename($name)
|
||||
{
|
||||
$this->doMove($this->getDirectory(), $name);
|
||||
}
|
||||
}
|
@ -20,10 +20,34 @@ use Symfony\Component\HttpFoundation\File\Exception\FileException;
|
||||
*/
|
||||
class UploadedFile extends File
|
||||
{
|
||||
/**
|
||||
* The original name of the uploaded file
|
||||
* @var string
|
||||
*/
|
||||
protected $originalName;
|
||||
|
||||
/**
|
||||
* The mime type provided by the uploader
|
||||
* @var string
|
||||
*/
|
||||
protected $mimeType;
|
||||
|
||||
/**
|
||||
* The file size provided by the uploader
|
||||
* @var integer
|
||||
*/
|
||||
protected $size;
|
||||
|
||||
/**
|
||||
* The UPLOAD_ERR_XXX constant provided by the uploader
|
||||
* @var integer
|
||||
*/
|
||||
protected $error;
|
||||
|
||||
/**
|
||||
* Whether the uploaded file has already been moved
|
||||
* @var boolean
|
||||
*/
|
||||
protected $moved = false;
|
||||
|
||||
/**
|
||||
@ -35,7 +59,7 @@ class UploadedFile extends File
|
||||
* @param string $type The type of the file as provided by PHP
|
||||
* @param integer $size The file size
|
||||
* @param string $error The error constant of the upload. Should be
|
||||
* one of PHP's UPLOAD_XXX constants.
|
||||
* one of PHP's UPLOAD_ERR_XXX constants.
|
||||
*/
|
||||
public function __construct($path, $originalName, $mimeType, $size, $error)
|
||||
{
|
||||
@ -62,13 +86,7 @@ class UploadedFile extends File
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the file.
|
||||
*
|
||||
* The mime type is guessed using the functions finfo(), mime_content_type()
|
||||
* and the system binary "file" (in this order), depending on which of those
|
||||
* is available on the current operating system.
|
||||
*
|
||||
* @returns string The guessed mime type, e.g. "application/pdf"
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getMimeType()
|
||||
{
|
||||
@ -105,13 +123,13 @@ class UploadedFile extends File
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file to a new location.
|
||||
*
|
||||
* @param string $newPath
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function move($newPath)
|
||||
protected function doMove($directory, $filename)
|
||||
{
|
||||
if (!$this->moved) {
|
||||
$newPath = $directory . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
if (!move_uploaded_file($this->getPath(), $newPath)) {
|
||||
throw new FileException(sprintf('Could not move file %s to %s', $this->getPath(), $newPath));
|
||||
}
|
||||
@ -119,7 +137,19 @@ class UploadedFile extends File
|
||||
$this->moved = true;
|
||||
$this->path = realpath($newPath);
|
||||
} else {
|
||||
parent::move($newPath);
|
||||
parent::doMove($directory, $filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function move($directory)
|
||||
{
|
||||
if (!$this->moved) {
|
||||
$this->doMove($directory, $this->originalName);
|
||||
} else {
|
||||
parent::move($directory);
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
namespace Symfony\Tests\Component\Form;
|
||||
|
||||
use Symfony\Component\Form\FileField;
|
||||
use Symfony\Component\HttpFoundation\File\File;
|
||||
|
||||
class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -44,15 +45,20 @@ class FileFieldTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function testBindUploadsNewFiles()
|
||||
{
|
||||
$tmpPath = realpath(self::$tmpDir) . '/' . md5(session_id() . '$secret$' . '12345');
|
||||
$tmpDir = realpath(self::$tmpDir);
|
||||
$tmpName = md5(session_id() . '$secret$' . '12345');
|
||||
$tmpPath = $tmpDir . DIRECTORY_SEPARATOR . $tmpName;
|
||||
$that = $this;
|
||||
|
||||
$file = $this->getMock('Symfony\Component\HttpFoundation\File\UploadedFile', array(), array(), '', false);
|
||||
$file->expects($this->once())
|
||||
->method('move')
|
||||
->with($this->equalTo($tmpPath))
|
||||
->will($this->returnCallback(function ($path) use ($that) {
|
||||
$that->createTmpFile($path);
|
||||
->with($this->equalTo($tmpDir));
|
||||
$file->expects($this->once())
|
||||
->method('rename')
|
||||
->with($this->equalTo($tmpName))
|
||||
->will($this->returnCallback(function ($directory) use ($that, $tmpPath) {
|
||||
$that->createTmpFile($tmpPath);
|
||||
}));
|
||||
$file->expects($this->any())
|
||||
->method('getOriginalName')
|
||||
|
@ -20,6 +20,20 @@ class FileTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.gif', $this->file->getPath());
|
||||
}
|
||||
|
||||
public function testGetWebPathReturnsPathRelativeToDocumentRoot()
|
||||
{
|
||||
File::setDocumentRoot(__DIR__);
|
||||
|
||||
$this->assertEquals('/Fixtures/test.gif', $this->file->getWebPath());
|
||||
}
|
||||
|
||||
public function testGetWebPathReturnsEmptyPathIfOutsideDocumentRoot()
|
||||
{
|
||||
File::setDocumentRoot(__DIR__.'/Fixtures/directory');
|
||||
|
||||
$this->assertEquals('', $this->file->getWebPath());
|
||||
}
|
||||
|
||||
public function testGetNameReturnsNameWithExtension()
|
||||
{
|
||||
$this->assertEquals('test.gif', $this->file->getName());
|
||||
@ -62,13 +76,33 @@ class FileTest extends \PHPUnit_Framework_TestCase
|
||||
public function testMove()
|
||||
{
|
||||
$path = __DIR__.'/Fixtures/test.copy.gif';
|
||||
$targetPath = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'test.target.gif';
|
||||
$targetDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'directory';
|
||||
$targetPath = $targetDir.DIRECTORY_SEPARATOR.'test.copy.gif';
|
||||
@unlink($path);
|
||||
@unlink($targetPath);
|
||||
copy(__DIR__.'/Fixtures/test.gif', $path);
|
||||
|
||||
$file = new File($path);
|
||||
$file->move($targetPath);
|
||||
$file->move($targetDir);
|
||||
|
||||
$this->assertTrue(file_exists($targetPath));
|
||||
$this->assertFalse(file_exists($path));
|
||||
$this->assertEquals($targetPath, $file->getPath());
|
||||
|
||||
@unlink($path);
|
||||
@unlink($targetPath);
|
||||
}
|
||||
|
||||
public function testRename()
|
||||
{
|
||||
$path = __DIR__.'/Fixtures/test.copy.gif';
|
||||
$targetPath = __DIR__.'/Fixtures/test.target.gif';
|
||||
@unlink($path);
|
||||
@unlink($targetPath);
|
||||
copy(__DIR__.'/Fixtures/test.gif', $path);
|
||||
|
||||
$file = new File($path);
|
||||
$file->rename('test.target.gif');
|
||||
|
||||
$this->assertTrue(file_exists($targetPath));
|
||||
$this->assertFalse(file_exists($path));
|
||||
|
Reference in New Issue
Block a user