Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Validator\Constraints; Chris@0: Chris@0: use Symfony\Component\Validator\Constraint; Chris@0: use Symfony\Component\Validator\Exception\ConstraintDefinitionException; Chris@0: use Symfony\Component\Validator\Exception\RuntimeException; Chris@0: use Symfony\Component\Validator\Exception\UnexpectedTypeException; Chris@0: Chris@0: /** Chris@0: * Validates whether a value is a valid image file and is valid Chris@0: * against minWidth, maxWidth, minHeight and maxHeight constraints. Chris@0: * Chris@0: * @author Benjamin Dulau Chris@0: * @author Bernhard Schussek Chris@0: */ Chris@0: class ImageValidator extends FileValidator Chris@0: { Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public function validate($value, Constraint $constraint) Chris@0: { Chris@0: if (!$constraint instanceof Image) { Chris@0: throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Image'); Chris@0: } Chris@0: Chris@17: $violations = \count($this->context->getViolations()); Chris@0: Chris@0: parent::validate($value, $constraint); Chris@0: Chris@17: $failed = \count($this->context->getViolations()) !== $violations; Chris@0: Chris@0: if ($failed || null === $value || '' === $value) { Chris@0: return; Chris@0: } Chris@0: Chris@0: if (null === $constraint->minWidth && null === $constraint->maxWidth Chris@0: && null === $constraint->minHeight && null === $constraint->maxHeight Chris@14: && null === $constraint->minPixels && null === $constraint->maxPixels Chris@0: && null === $constraint->minRatio && null === $constraint->maxRatio Chris@0: && $constraint->allowSquare && $constraint->allowLandscape && $constraint->allowPortrait Chris@0: && !$constraint->detectCorrupted) { Chris@0: return; Chris@0: } Chris@0: Chris@0: $size = @getimagesize($value); Chris@0: Chris@14: if (empty($size) || (0 === $size[0]) || (0 === $size[1])) { Chris@0: $this->context->buildViolation($constraint->sizeNotDetectedMessage) Chris@0: ->setCode(Image::SIZE_NOT_DETECTED_ERROR) Chris@0: ->addViolation(); Chris@0: Chris@0: return; Chris@0: } Chris@0: Chris@0: $width = $size[0]; Chris@0: $height = $size[1]; Chris@0: Chris@0: if ($constraint->minWidth) { Chris@0: if (!ctype_digit((string) $constraint->minWidth)) { Chris@14: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid minimum width.', $constraint->minWidth)); Chris@0: } Chris@0: Chris@0: if ($width < $constraint->minWidth) { Chris@0: $this->context->buildViolation($constraint->minWidthMessage) Chris@0: ->setParameter('{{ width }}', $width) Chris@0: ->setParameter('{{ min_width }}', $constraint->minWidth) Chris@0: ->setCode(Image::TOO_NARROW_ERROR) Chris@0: ->addViolation(); Chris@0: Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($constraint->maxWidth) { Chris@0: if (!ctype_digit((string) $constraint->maxWidth)) { Chris@14: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum width.', $constraint->maxWidth)); Chris@0: } Chris@0: Chris@0: if ($width > $constraint->maxWidth) { Chris@0: $this->context->buildViolation($constraint->maxWidthMessage) Chris@0: ->setParameter('{{ width }}', $width) Chris@0: ->setParameter('{{ max_width }}', $constraint->maxWidth) Chris@0: ->setCode(Image::TOO_WIDE_ERROR) Chris@0: ->addViolation(); Chris@0: Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($constraint->minHeight) { Chris@0: if (!ctype_digit((string) $constraint->minHeight)) { Chris@0: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid minimum height', $constraint->minHeight)); Chris@0: } Chris@0: Chris@0: if ($height < $constraint->minHeight) { Chris@0: $this->context->buildViolation($constraint->minHeightMessage) Chris@0: ->setParameter('{{ height }}', $height) Chris@0: ->setParameter('{{ min_height }}', $constraint->minHeight) Chris@0: ->setCode(Image::TOO_LOW_ERROR) Chris@0: ->addViolation(); Chris@0: Chris@0: return; Chris@0: } Chris@0: } Chris@0: Chris@0: if ($constraint->maxHeight) { Chris@0: if (!ctype_digit((string) $constraint->maxHeight)) { Chris@0: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum height', $constraint->maxHeight)); Chris@0: } Chris@0: Chris@0: if ($height > $constraint->maxHeight) { Chris@0: $this->context->buildViolation($constraint->maxHeightMessage) Chris@0: ->setParameter('{{ height }}', $height) Chris@0: ->setParameter('{{ max_height }}', $constraint->maxHeight) Chris@0: ->setCode(Image::TOO_HIGH_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: } Chris@0: Chris@14: $pixels = $width * $height; Chris@14: Chris@14: if (null !== $constraint->minPixels) { Chris@14: if (!ctype_digit((string) $constraint->minPixels)) { Chris@14: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid minimum amount of pixels', $constraint->minPixels)); Chris@14: } Chris@14: Chris@14: if ($pixels < $constraint->minPixels) { Chris@14: $this->context->buildViolation($constraint->minPixelsMessage) Chris@14: ->setParameter('{{ pixels }}', $pixels) Chris@14: ->setParameter('{{ min_pixels }}', $constraint->minPixels) Chris@14: ->setParameter('{{ height }}', $height) Chris@14: ->setParameter('{{ width }}', $width) Chris@14: ->setCode(Image::TOO_FEW_PIXEL_ERROR) Chris@14: ->addViolation(); Chris@14: } Chris@14: } Chris@14: Chris@14: if (null !== $constraint->maxPixels) { Chris@14: if (!ctype_digit((string) $constraint->maxPixels)) { Chris@14: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum amount of pixels', $constraint->maxPixels)); Chris@14: } Chris@14: Chris@14: if ($pixels > $constraint->maxPixels) { Chris@14: $this->context->buildViolation($constraint->maxPixelsMessage) Chris@14: ->setParameter('{{ pixels }}', $pixels) Chris@14: ->setParameter('{{ max_pixels }}', $constraint->maxPixels) Chris@14: ->setParameter('{{ height }}', $height) Chris@14: ->setParameter('{{ width }}', $width) Chris@14: ->setCode(Image::TOO_MANY_PIXEL_ERROR) Chris@14: ->addViolation(); Chris@14: } Chris@14: } Chris@14: Chris@0: $ratio = round($width / $height, 2); Chris@0: Chris@0: if (null !== $constraint->minRatio) { Chris@0: if (!is_numeric((string) $constraint->minRatio)) { Chris@0: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid minimum ratio', $constraint->minRatio)); Chris@0: } Chris@0: Chris@0: if ($ratio < $constraint->minRatio) { Chris@0: $this->context->buildViolation($constraint->minRatioMessage) Chris@0: ->setParameter('{{ ratio }}', $ratio) Chris@0: ->setParameter('{{ min_ratio }}', $constraint->minRatio) Chris@0: ->setCode(Image::RATIO_TOO_SMALL_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: } Chris@0: Chris@0: if (null !== $constraint->maxRatio) { Chris@0: if (!is_numeric((string) $constraint->maxRatio)) { Chris@0: throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum ratio', $constraint->maxRatio)); Chris@0: } Chris@0: Chris@0: if ($ratio > $constraint->maxRatio) { Chris@0: $this->context->buildViolation($constraint->maxRatioMessage) Chris@0: ->setParameter('{{ ratio }}', $ratio) Chris@0: ->setParameter('{{ max_ratio }}', $constraint->maxRatio) Chris@0: ->setCode(Image::RATIO_TOO_BIG_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: } Chris@0: Chris@0: if (!$constraint->allowSquare && $width == $height) { Chris@0: $this->context->buildViolation($constraint->allowSquareMessage) Chris@0: ->setParameter('{{ width }}', $width) Chris@0: ->setParameter('{{ height }}', $height) Chris@0: ->setCode(Image::SQUARE_NOT_ALLOWED_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: Chris@0: if (!$constraint->allowLandscape && $width > $height) { Chris@0: $this->context->buildViolation($constraint->allowLandscapeMessage) Chris@0: ->setParameter('{{ width }}', $width) Chris@0: ->setParameter('{{ height }}', $height) Chris@0: ->setCode(Image::LANDSCAPE_NOT_ALLOWED_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: Chris@0: if (!$constraint->allowPortrait && $width < $height) { Chris@0: $this->context->buildViolation($constraint->allowPortraitMessage) Chris@0: ->setParameter('{{ width }}', $width) Chris@0: ->setParameter('{{ height }}', $height) Chris@0: ->setCode(Image::PORTRAIT_NOT_ALLOWED_ERROR) Chris@0: ->addViolation(); Chris@0: } Chris@0: Chris@0: if ($constraint->detectCorrupted) { Chris@17: if (!\function_exists('imagecreatefromstring')) { Chris@0: throw new RuntimeException('Corrupted images detection requires installed and enabled GD extension'); Chris@0: } Chris@0: Chris@0: $resource = @imagecreatefromstring(file_get_contents($value)); Chris@0: Chris@0: if (false === $resource) { Chris@0: $this->context->buildViolation($constraint->corruptedMessage) Chris@0: ->setCode(Image::CORRUPTED_IMAGE_ERROR) Chris@0: ->addViolation(); Chris@0: Chris@0: return; Chris@0: } Chris@0: Chris@0: imagedestroy($resource); Chris@0: } Chris@0: } Chris@0: }