PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/symfony/symfony/src/Symfony/Component/Validator/Constraints/FileValidator.php

https://gitlab.com/Marwamimo/Crowdrise_Web
PHP | 215 lines | 154 code | 38 blank | 23 comment | 26 complexity | cb869cda7114e17243dc354d865915c9 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Validator\Constraints;
  11. use Symfony\Component\HttpFoundation\File\File as FileObject;
  12. use Symfony\Component\HttpFoundation\File\UploadedFile;
  13. use Symfony\Component\Validator\Constraint;
  14. use Symfony\Component\Validator\ConstraintValidator;
  15. use Symfony\Component\Validator\Exception\ConstraintDefinitionException;
  16. use Symfony\Component\Validator\Exception\UnexpectedTypeException;
  17. /**
  18. * @author Bernhard Schussek <bschussek@gmail.com>
  19. *
  20. * @api
  21. */
  22. class FileValidator extends ConstraintValidator
  23. {
  24. const KB_BYTES = 1000;
  25. const MB_BYTES = 1000000;
  26. private static $suffices = array(
  27. 1 => 'bytes',
  28. self::KB_BYTES => 'kB',
  29. self::MB_BYTES => 'MB',
  30. );
  31. /**
  32. * {@inheritdoc}
  33. */
  34. public function validate($value, Constraint $constraint)
  35. {
  36. if (!$constraint instanceof File) {
  37. throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\File');
  38. }
  39. if (null === $value || '' === $value) {
  40. return;
  41. }
  42. if ($value instanceof UploadedFile && !$value->isValid()) {
  43. switch ($value->getError()) {
  44. case UPLOAD_ERR_INI_SIZE:
  45. if ($constraint->maxSize) {
  46. if (ctype_digit((string) $constraint->maxSize)) {
  47. $limitInBytes = (int) $constraint->maxSize;
  48. } elseif (preg_match('/^\d++k$/', $constraint->maxSize)) {
  49. $limitInBytes = $constraint->maxSize * self::KB_BYTES;
  50. } elseif (preg_match('/^\d++M$/', $constraint->maxSize)) {
  51. $limitInBytes = $constraint->maxSize * self::MB_BYTES;
  52. } else {
  53. throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum size', $constraint->maxSize));
  54. }
  55. $limitInBytes = min(UploadedFile::getMaxFilesize(), $limitInBytes);
  56. } else {
  57. $limitInBytes = UploadedFile::getMaxFilesize();
  58. }
  59. $this->buildViolation($constraint->uploadIniSizeErrorMessage)
  60. ->setParameter('{{ limit }}', $limitInBytes)
  61. ->setParameter('{{ suffix }}', 'bytes')
  62. ->addViolation();
  63. return;
  64. case UPLOAD_ERR_FORM_SIZE:
  65. $this->buildViolation($constraint->uploadFormSizeErrorMessage)
  66. ->addViolation();
  67. return;
  68. case UPLOAD_ERR_PARTIAL:
  69. $this->buildViolation($constraint->uploadPartialErrorMessage)
  70. ->addViolation();
  71. return;
  72. case UPLOAD_ERR_NO_FILE:
  73. $this->buildViolation($constraint->uploadNoFileErrorMessage)
  74. ->addViolation();
  75. return;
  76. case UPLOAD_ERR_NO_TMP_DIR:
  77. $this->buildViolation($constraint->uploadNoTmpDirErrorMessage)
  78. ->addViolation();
  79. return;
  80. case UPLOAD_ERR_CANT_WRITE:
  81. $this->buildViolation($constraint->uploadCantWriteErrorMessage)
  82. ->addViolation();
  83. return;
  84. case UPLOAD_ERR_EXTENSION:
  85. $this->buildViolation($constraint->uploadExtensionErrorMessage)
  86. ->addViolation();
  87. return;
  88. default:
  89. $this->buildViolation($constraint->uploadErrorMessage)
  90. ->setCode($value->getError())
  91. ->addViolation();
  92. return;
  93. }
  94. }
  95. if (!is_scalar($value) && !$value instanceof FileObject && !(is_object($value) && method_exists($value, '__toString'))) {
  96. throw new UnexpectedTypeException($value, 'string');
  97. }
  98. $path = $value instanceof FileObject ? $value->getPathname() : (string) $value;
  99. if (!is_file($path)) {
  100. $this->buildViolation($constraint->notFoundMessage)
  101. ->setParameter('{{ file }}', $this->formatValue($path))
  102. ->addViolation();
  103. return;
  104. }
  105. if (!is_readable($path)) {
  106. $this->buildViolation($constraint->notReadableMessage)
  107. ->setParameter('{{ file }}', $this->formatValue($path))
  108. ->addViolation();
  109. return;
  110. }
  111. if ($constraint->maxSize) {
  112. $sizeInBytes = filesize($path);
  113. $limitInBytes = (int) $constraint->maxSize;
  114. if (preg_match('/^\d++k$/', $constraint->maxSize)) {
  115. $limitInBytes *= self::KB_BYTES;
  116. } elseif (preg_match('/^\d++M$/', $constraint->maxSize)) {
  117. $limitInBytes *= self::MB_BYTES;
  118. } elseif (!ctype_digit((string) $constraint->maxSize)) {
  119. throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum size', $constraint->maxSize));
  120. }
  121. if ($sizeInBytes > $limitInBytes) {
  122. // Convert the limit to the smallest possible number
  123. // (i.e. try "MB", then "kB", then "bytes")
  124. $coef = self::MB_BYTES;
  125. $limitAsString = (string) ($limitInBytes / $coef);
  126. // Restrict the limit to 2 decimals (without rounding! we
  127. // need the precise value)
  128. while (self::moreDecimalsThan($limitAsString, 2)) {
  129. $coef /= 1000;
  130. $limitAsString = (string) ($limitInBytes / $coef);
  131. }
  132. // Convert size to the same measure, but round to 2 decimals
  133. $sizeAsString = (string) round($sizeInBytes / $coef, 2);
  134. // If the size and limit produce the same string output
  135. // (due to rounding), reduce the coefficient
  136. while ($sizeAsString === $limitAsString) {
  137. $coef /= 1000;
  138. $limitAsString = (string) ($limitInBytes / $coef);
  139. $sizeAsString = (string) round($sizeInBytes / $coef, 2);
  140. }
  141. $this->buildViolation($constraint->maxSizeMessage)
  142. ->setParameter('{{ file }}', $this->formatValue($path))
  143. ->setParameter('{{ size }}', $sizeAsString)
  144. ->setParameter('{{ limit }}', $limitAsString)
  145. ->setParameter('{{ suffix }}', self::$suffices[$coef])
  146. ->addViolation();
  147. return;
  148. }
  149. }
  150. if ($constraint->mimeTypes) {
  151. if (!$value instanceof FileObject) {
  152. $value = new FileObject($value);
  153. }
  154. $mimeTypes = (array) $constraint->mimeTypes;
  155. $mime = $value->getMimeType();
  156. foreach ($mimeTypes as $mimeType) {
  157. if ($mimeType === $mime) {
  158. return;
  159. }
  160. if ($discrete = strstr($mimeType, '/*', true)) {
  161. if (strstr($mime, '/', true) === $discrete) {
  162. return;
  163. }
  164. }
  165. }
  166. $this->buildViolation($constraint->mimeTypesMessage)
  167. ->setParameter('{{ file }}', $this->formatValue($path))
  168. ->setParameter('{{ type }}', $this->formatValue($mime))
  169. ->setParameter('{{ types }}', $this->formatValues($mimeTypes))
  170. ->addViolation();
  171. }
  172. }
  173. private static function moreDecimalsThan($double, $numberOfDecimals)
  174. {
  175. return strlen((string) $double) > strlen(round($double, $numberOfDecimals));
  176. }
  177. }