Pārlūkot izejas kodu

merged branch vicb/form/ini-max-size (PR #1542)

Commits
-------

d58ba34 [Validator] Consider the ini directive 'upload_max_filesize' while validating an uploaded file (fixes GH-1441)

Discussion
----------

[Validator] FileValidator support for uploaded files

[Validator] Consider the ini directive 'upload_max_filesize' while validating an uploaded file (fixes GH-1441)

Added validator messages should get translated in all the available languages.
Fabien Potencier 14 gadi atpakaļ
vecāks
revīzija
b9adab9796

+ 14 - 2
src/Symfony/Bundle/FrameworkBundle/Resources/translations/validators.fr.xliff

@@ -60,7 +60,7 @@
             </trans-unit>
             <trans-unit id="15">
                 <source>The file is too large ({{ size }}). Allowed maximum size is {{ limit }}</source>
-                <target>Le fichier est trop lourd ({{ size }}). La taille maximale autorisée est {{ limit }}</target>
+                <target>Le fichier est trop volumineux ({{ size }}). Sa taille ne doit pas dépasser {{ limit }}</target>
             </trans-unit>
             <trans-unit id="16">
                 <source>The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}</source>
@@ -116,7 +116,7 @@
             </trans-unit>
             <trans-unit id="29">
                 <source>The uploaded file was too large. Please try to upload a smaller file</source>
-                <target>Le fichier envoyé est trop gros. Merci d'essayer d'envoyer un fichier plus petit</target>
+                <target>Le fichier téléchargé est trop volumineux. Merci d'essayer d'envoyer un fichier plus petit</target>
             </trans-unit>
             <trans-unit id="30">
                 <source>The CSRF token is invalid. Please try to resubmit the form</source>
@@ -126,6 +126,18 @@
                 <source>The two values should be equal</source>
                 <target>Les deux valeurs doivent être identiques</target>
             </trans-unit>
+            <trans-unit id="32">
+                <source>The file is too large. Allowed maximum size is {{ limit }}</source>
+                <target>Le fichier est trop volumineux. Sa taille ne doit pas dépasser {{ limit }}</target>
+            </trans-unit>
+            <trans-unit id="33">
+                <source>The file is too large</source>
+                <target>Le fichier est trop volumineux</target>
+            </trans-unit>
+            <trans-unit id="34">
+                <source>The file could not be uploaded</source>
+                <target>Le téléchargement de ce fichier est impossible</target>
+            </trans-unit>
         </body>
     </file>
 </xliff>

+ 17 - 4
src/Symfony/Component/HttpFoundation/File/UploadedFile.php

@@ -63,6 +63,17 @@ class UploadedFile extends File
     /**
      * Accepts the information of the uploaded file as provided by the PHP global $_FILES.
      *
+     * The file object is only created when the uploaded file is valid (i.e. when the
+     * isValid() method returns true). Otherwise the only methods that could be called
+     * on an UploadedFile instance are:
+     *
+     *   * getClientOriginalName,
+     *   * getClientMimeType,
+     *   * isValid,
+     *   * getError.
+     *
+     * Calling any other method on an non-valid instance will cause an unpredictable result.
+     *
      * @param string  $path         The full temporary path to the file
      * @param string  $originalName The original file name
      * @param string  $mimeType     The type of the file as provided by PHP
@@ -85,7 +96,9 @@ class UploadedFile extends File
         $this->error = $error ?: UPLOAD_ERR_OK;
         $this->test = (Boolean) $test;
 
-        parent::__construct($path);
+        if (UPLOAD_ERR_OK === $this->error) {
+            parent::__construct($path);
+        }
     }
 
     /**
@@ -162,10 +175,10 @@ class UploadedFile extends File
      */
     public function move($directory, $name = null)
     {
-        if (!$this->test && !is_uploaded_file($this->getPathname())) {
-            throw new FileException(sprintf('The file "%s" has not been uploaded via Http', $this->getPathname()));
+        if ($this->isValid() && ($this->test || is_uploaded_file($this->getPathname()))) {
+            return parent::move($directory, $name);
         }
 
-        return parent::move($directory, $name);
+        throw new FileException(sprintf('The file "%s" has not been uploaded via Http', $this->getPathname()));
     }
 }

+ 4 - 0
src/Symfony/Component/Validator/Constraints/File.php

@@ -22,4 +22,8 @@ class File extends Constraint
     public $notReadableMessage = 'The file is not readable';
     public $maxSizeMessage = 'The file is too large ({{ size }}). Allowed maximum size is {{ limit }}';
     public $mimeTypesMessage = 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}';
+
+    public $uploadIniSizeErrorMessage = 'The file is too large. Allowed maximum size is {{ limit }}';
+    public $uploadFormSizeErrorMessage = 'The file is too large';
+    public $uploadErrorMessage = 'The file could not be uploaded';
 }

+ 28 - 0
src/Symfony/Component/Validator/Constraints/FileValidator.php

@@ -16,6 +16,7 @@ use Symfony\Component\Validator\ConstraintValidator;
 use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
 use Symfony\Component\Validator\Exception\UnexpectedTypeException;
 use Symfony\Component\HttpFoundation\File\File as FileObject;
+use Symfony\Component\HttpFoundation\File\UploadedFile;
 
 class FileValidator extends ConstraintValidator
 {
@@ -25,6 +26,33 @@ class FileValidator extends ConstraintValidator
             return true;
         }
 
+        if ($value instanceof UploadedFile && !$value->isValid()) {
+            switch ($value->getError()) {
+                case UPLOAD_ERR_INI_SIZE:
+                    $maxSize = trim(ini_get('upload_max_filesize'));
+                    switch (strtolower(substr($maxSize, -1))) {
+                        case 'g':
+                            $maxSize *= 1024;
+                        case 'm':
+                            $maxSize *= 1024;
+                        case 'k':
+                            $maxSize *= 1024;
+                    }
+                    $maxSize = $constraint->maxSize ? min($maxSize, $constraint->maxSize) : $maxSize;
+                    $this->setMessage($constraint->uploadIniSizeErrorMessage, array('{{ limit }}' => $maxSize.' bytes'));
+
+                    return false;
+                case UPLOAD_ERR_FORM_SIZE:
+                    $this->setMessage($constraint->uploadFormSizeErrorMessage);
+
+                    return false;
+                default:
+                    $this->setMessage($constraint->uploadErrorMessage);
+
+                    return false;
+            }
+        }
+
         if (!is_scalar($value) && !$value instanceof FileObject && !(is_object($value) && method_exists($value, '__toString'))) {
             throw new UnexpectedTypeException($value, 'string');
         }

+ 28 - 0
tests/Symfony/Tests/Component/HttpFoundation/File/UploadedFileTest.php

@@ -190,4 +190,32 @@ class UploadedFileTest extends \PHPUnit_Framework_TestCase
 
         $this->assertTrue($file->isValid());
     }
+
+    /**
+     * @dataProvider uploadedFileErrorProvider
+     */
+    public function testIsInvalidOnUploadError($error)
+    {
+        $file = new UploadedFile(
+            __DIR__.'/Fixtures/test.gif',
+            'original.gif',
+            null,
+            filesize(__DIR__.'/Fixtures/test.gif'),
+            $error
+        );
+
+        $this->assertFalse($file->isValid());
+    }
+
+
+    public function uploadedFileErrorProvider()
+    {
+        return array(
+            array(UPLOAD_ERR_INI_SIZE),
+            array(UPLOAD_ERR_FORM_SIZE),
+            array(UPLOAD_ERR_PARTIAL),
+            array(UPLOAD_ERR_NO_TMP_DIR),
+            array(UPLOAD_ERR_EXTENSION),
+        );
+    }
 }

+ 34 - 0
tests/Symfony/Tests/Component/Validator/Constraints/FileValidatorTest.php

@@ -14,6 +14,7 @@ namespace Symfony\Tests\Component\Validator\Constraints;
 use Symfony\Component\Validator\Constraints\File;
 use Symfony\Component\Validator\Constraints\FileValidator;
 use Symfony\Component\HttpFoundation\File\File as FileObject;
+use Symfony\Component\HttpFoundation\File\UploadedFile;
 
 class FileValidatorTest extends \PHPUnit_Framework_TestCase
 {
@@ -60,6 +61,12 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue($this->validator->isValid($this->path, new File()));
     }
 
+    public function testValidUploadedfile()
+    {
+        $file = new UploadedFile($this->path, 'originalName');
+        $this->assertTrue($this->validator->isValid($file, new File()));
+    }
+
     public function testTooLargeBytes()
     {
         fwrite($this->file, str_repeat('0', 11));
@@ -196,6 +203,33 @@ class FileValidatorTest extends \PHPUnit_Framework_TestCase
         ));
     }
 
+    /**
+     * @dataProvider uploadedFileErrorProvider
+     */
+    public function testUploadedFileError($error, $message)
+    {
+        $file = new UploadedFile('/path/to/file', 'originalName', 'mime', 0, $error);
+
+        $options[$message] = 'myMessage';
+
+        $constraint = new File($options);
+
+        $this->assertFalse($this->validator->isValid($file, $constraint));
+        $this->assertEquals($this->validator->getMessageTemplate(), 'myMessage');
+
+    }
+
+    public function uploadedFileErrorProvider()
+    {
+        return array(
+            array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage'),
+            array(UPLOAD_ERR_FORM_SIZE, 'uploadFormSizeErrorMessage'),
+            array(UPLOAD_ERR_PARTIAL, 'uploadErrorMessage'),
+            array(UPLOAD_ERR_NO_TMP_DIR, 'uploadErrorMessage'),
+            array(UPLOAD_ERR_EXTENSION, 'uploadErrorMessage'),
+        );
+    }
+
     protected function assertFileValid($filename, File $constraint, $valid = true)
     {
         $this->assertEquals($this->validator->isValid($filename, $constraint), $valid);