PageRenderTime 55ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php

http://github.com/symfony/symfony
PHP | 161 lines | 90 code | 26 blank | 45 comment | 12 complexity | e0a02ad4c80a3dd92068021f09b75ba9 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\Serializer\Normalizer;
  11. use Symfony\Component\HttpFoundation\File\File;
  12. use Symfony\Component\Mime\MimeTypeGuesserInterface;
  13. use Symfony\Component\Mime\MimeTypes;
  14. use Symfony\Component\Serializer\Exception\InvalidArgumentException;
  15. use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
  16. /**
  17. * Normalizes an {@see \SplFileInfo} object to a data URI.
  18. * Denormalizes a data URI to a {@see \SplFileObject} object.
  19. *
  20. * @author Kévin Dunglas <dunglas@gmail.com>
  21. */
  22. class DataUriNormalizer implements NormalizerInterface, DenormalizerInterface, CacheableSupportsMethodInterface
  23. {
  24. private static $supportedTypes = [
  25. \SplFileInfo::class => true,
  26. \SplFileObject::class => true,
  27. File::class => true,
  28. ];
  29. /**
  30. * @var MimeTypeGuesserInterface|null
  31. */
  32. private $mimeTypeGuesser;
  33. public function __construct(MimeTypeGuesserInterface $mimeTypeGuesser = null)
  34. {
  35. if (!$mimeTypeGuesser && class_exists(MimeTypes::class)) {
  36. $mimeTypeGuesser = MimeTypes::getDefault();
  37. }
  38. $this->mimeTypeGuesser = $mimeTypeGuesser;
  39. }
  40. /**
  41. * {@inheritdoc}
  42. */
  43. public function normalize($object, string $format = null, array $context = [])
  44. {
  45. if (!$object instanceof \SplFileInfo) {
  46. throw new InvalidArgumentException('The object must be an instance of "\SplFileInfo".');
  47. }
  48. $mimeType = $this->getMimeType($object);
  49. $splFileObject = $this->extractSplFileObject($object);
  50. $data = '';
  51. $splFileObject->rewind();
  52. while (!$splFileObject->eof()) {
  53. $data .= $splFileObject->fgets();
  54. }
  55. if ('text' === explode('/', $mimeType, 2)[0]) {
  56. return sprintf('data:%s,%s', $mimeType, rawurlencode($data));
  57. }
  58. return sprintf('data:%s;base64,%s', $mimeType, base64_encode($data));
  59. }
  60. /**
  61. * {@inheritdoc}
  62. */
  63. public function supportsNormalization($data, string $format = null)
  64. {
  65. return $data instanceof \SplFileInfo;
  66. }
  67. /**
  68. * {@inheritdoc}
  69. *
  70. * Regex adapted from Brian Grinstead code.
  71. *
  72. * @see https://gist.github.com/bgrins/6194623
  73. *
  74. * @throws InvalidArgumentException
  75. * @throws NotNormalizableValueException
  76. */
  77. public function denormalize($data, string $type, string $format = null, array $context = [])
  78. {
  79. if (!preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) {
  80. throw new NotNormalizableValueException('The provided "data:" URI is not valid.');
  81. }
  82. try {
  83. switch ($type) {
  84. case 'Symfony\Component\HttpFoundation\File\File':
  85. if (!class_exists(File::class)) {
  86. throw new InvalidArgumentException(sprintf('Cannot denormalize to a "%s" without the HttpFoundation component installed. Try running "composer require symfony/http-foundation".', File::class));
  87. }
  88. return new File($data, false);
  89. case 'SplFileObject':
  90. case 'SplFileInfo':
  91. return new \SplFileObject($data);
  92. }
  93. } catch (\RuntimeException $exception) {
  94. throw new NotNormalizableValueException($exception->getMessage(), $exception->getCode(), $exception);
  95. }
  96. throw new InvalidArgumentException(sprintf('The class parameter "%s" is not supported. It must be one of "SplFileInfo", "SplFileObject" or "Symfony\Component\HttpFoundation\File\File".', $type));
  97. }
  98. /**
  99. * {@inheritdoc}
  100. */
  101. public function supportsDenormalization($data, string $type, string $format = null)
  102. {
  103. return isset(self::$supportedTypes[$type]);
  104. }
  105. /**
  106. * {@inheritdoc}
  107. */
  108. public function hasCacheableSupportsMethod(): bool
  109. {
  110. return __CLASS__ === static::class;
  111. }
  112. /**
  113. * Gets the mime type of the object. Defaults to application/octet-stream.
  114. */
  115. private function getMimeType(\SplFileInfo $object): string
  116. {
  117. if ($object instanceof File) {
  118. return $object->getMimeType();
  119. }
  120. if ($this->mimeTypeGuesser && $mimeType = $this->mimeTypeGuesser->guessMimeType($object->getPathname())) {
  121. return $mimeType;
  122. }
  123. return 'application/octet-stream';
  124. }
  125. /**
  126. * Returns the \SplFileObject instance associated with the given \SplFileInfo instance.
  127. */
  128. private function extractSplFileObject(\SplFileInfo $object): \SplFileObject
  129. {
  130. if ($object instanceof \SplFileObject) {
  131. return $object;
  132. }
  133. return $object->openFile();
  134. }
  135. }