Skip to content

Commit

Permalink
Display a nice upload limit message
Browse files Browse the repository at this point in the history
  • Loading branch information
Jérémy Derussé committed Oct 2, 2014
1 parent d318e09 commit b6e29e9
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 37 deletions.
75 changes: 42 additions & 33 deletions src/Symfony/Component/Validator/Constraints/FileValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ public function validate($value, Constraint $constraint)
$limitInBytes = UploadedFile::getMaxFilesize();
}

list($sizeAsString, $limitAsString, $suffix) = $this->factorizeSizes(0, $limitInBytes, true);
$this->buildViolation($constraint->uploadIniSizeErrorMessage)
->setParameter('{{ limit }}', $limitInBytes)
->setParameter('{{ suffix }}', 'bytes')
->setParameter('{{ limit }}', $limitAsString)
->setParameter('{{ suffix }}', $suffix)
->setCode(UPLOAD_ERR_INI_SIZE)
->addViolation();

Expand Down Expand Up @@ -150,41 +151,12 @@ public function validate($value, Constraint $constraint)
$limitInBytes = $constraint->maxSize;

if ($sizeInBytes > $limitInBytes) {
// Convert the limit to the smallest possible number
// (i.e. try "MB", then "kB", then "bytes")
if ($constraint->binaryFormat) {
$coef = self::MIB_BYTES;
$coefFactor = self::KIB_BYTES;
} else {
$coef = self::MB_BYTES;
$coefFactor = self::KB_BYTES;
}

$limitAsString = (string) ($limitInBytes / $coef);

// Restrict the limit to 2 decimals (without rounding! we
// need the precise value)
while (self::moreDecimalsThan($limitAsString, 2)) {
$coef /= $coefFactor;
$limitAsString = (string) ($limitInBytes / $coef);
}

// Convert size to the same measure, but round to 2 decimals
$sizeAsString = (string) round($sizeInBytes / $coef, 2);

// If the size and limit produce the same string output
// (due to rounding), reduce the coefficient
while ($sizeAsString === $limitAsString) {
$coef /= $coefFactor;
$limitAsString = (string) ($limitInBytes / $coef);
$sizeAsString = (string) round($sizeInBytes / $coef, 2);
}

list($sizeAsString, $limitAsString, $suffix) = $this->factorizeSizes($sizeInBytes, $limitInBytes, $constraint->binaryFormat);
$this->buildViolation($constraint->maxSizeMessage)
->setParameter('{{ file }}', $this->formatValue($path))
->setParameter('{{ size }}', $sizeAsString)
->setParameter('{{ limit }}', $limitAsString)
->setParameter('{{ suffix }}', self::$suffices[$coef])
->setParameter('{{ suffix }}', $suffix)
->setCode(File::TOO_LARGE_ERROR)
->addViolation();

Expand Down Expand Up @@ -225,4 +197,41 @@ private static function moreDecimalsThan($double, $numberOfDecimals)
{
return strlen((string) $double) > strlen(round($double, $numberOfDecimals));
}

/**
* Convert the limit to the smallest possible number
* (i.e. try "MB", then "kB", then "bytes")
*/
private function factorizeSizes($size, $limit, $binaryFormat)
{
if ($binaryFormat) {
$coef = self::MIB_BYTES;
$coefFactor = self::KIB_BYTES;
} else {
$coef = self::MB_BYTES;
$coefFactor = self::KB_BYTES;
}

$limitAsString = (string) ($limit / $coef);

// Restrict the limit to 2 decimals (without rounding! we
// need the precise value)
while (self::moreDecimalsThan($limitAsString, 2)) {
$coef /= $coefFactor;
$limitAsString = (string) ($limit / $coef);
}

// Convert size to the same measure, but round to 2 decimals
$sizeAsString = (string) round($size / $coef, 2);

// If the size and limit produce the same string output
// (due to rounding), reduce the coefficient
while ($sizeAsString === $limitAsString) {
$coef /= $coefFactor;
$limitAsString = (string) ($limit / $coef);
$sizeAsString = (string) round($size / $coef, 2);
}

return array($sizeAsString, $limitAsString, self::$suffices[$coef]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,8 @@ public function uploadedFileErrorProvider()
if (class_exists('Symfony\Component\HttpFoundation\File\UploadedFile')) {
// when no maxSize is specified on constraint, it should use the ini value
$tests[] = array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', array(
'{{ limit }}' => UploadedFile::getMaxFilesize(),
'{{ suffix }}' => 'bytes',
'{{ limit }}' => UploadedFile::getMaxFilesize() / 1048576,
'{{ suffix }}' => 'MiB',
));

// it should use the smaller limitation (maxSize option in this case)
Expand All @@ -458,8 +458,8 @@ public function uploadedFileErrorProvider()
// it correctly parses the maxSize option and not only uses simple string comparison
// 1000M should be bigger than the ini value
$tests[] = array(UPLOAD_ERR_INI_SIZE, 'uploadIniSizeErrorMessage', array(
'{{ limit }}' => UploadedFile::getMaxFilesize(),
'{{ suffix }}' => 'bytes',
'{{ limit }}' => UploadedFile::getMaxFilesize() / 1048576,
'{{ suffix }}' => 'MiB',
), '1000M');
}

Expand Down

0 comments on commit b6e29e9

Please sign in to comment.