mirror of
https://github.com/Intervention/image.git
synced 2025-08-21 05:01:20 +02:00
Implement DataUri::class
This commit is contained in:
@@ -10,6 +10,7 @@
|
|||||||
- Alignment::class
|
- Alignment::class
|
||||||
- DriverInterface::handleImageInput()
|
- DriverInterface::handleImageInput()
|
||||||
- DriverInterface::handleColorInput()
|
- DriverInterface::handleColorInput()
|
||||||
|
- DataUri::class
|
||||||
|
|
||||||
## API Changes
|
## API Changes
|
||||||
|
|
||||||
@@ -24,3 +25,4 @@
|
|||||||
- Changed default value for `background` to `null` in ImageInterface::crop()
|
- Changed default value for `background` to `null` in ImageInterface::crop()
|
||||||
- Signature of ImageInterface::crop() changed `offset_x` is no `x` and `offset_y` is now `y`
|
- Signature of ImageInterface::crop() changed `offset_x` is no `x` and `offset_y` is now `y`
|
||||||
- Signature of ImageInterface::place() changed `offset_x` is no `x` and `offset_y` is now `y`
|
- Signature of ImageInterface::place() changed `offset_x` is no `x` and `offset_y` is now `y`
|
||||||
|
- EncodedImageInterface::toDataUri() now returns `DataUriInterface` instead of `string´
|
||||||
|
270
src/DataUri.php
Normal file
270
src/DataUri.php
Normal file
@@ -0,0 +1,270 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Intervention\Image;
|
||||||
|
|
||||||
|
use Intervention\Image\Exceptions\DecoderException;
|
||||||
|
use Intervention\Image\Interfaces\DataUriInterface;
|
||||||
|
use Stringable;
|
||||||
|
|
||||||
|
class DataUri implements DataUriInterface, Stringable
|
||||||
|
{
|
||||||
|
protected const PATTERN = "/^data:(?P<mediaType>\w+\/[-+.\w]+)?" .
|
||||||
|
"(?P<parameters>(;[-\w]+=[-\w]+)*)(?P<base64>;base64)?,(?P<data>.*)/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Media type of data uri output
|
||||||
|
*/
|
||||||
|
protected ?string $mediaType = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters of data uri output
|
||||||
|
*
|
||||||
|
* @var array<string, string>
|
||||||
|
*/
|
||||||
|
protected array $parameters = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create new data uri instanceof
|
||||||
|
*
|
||||||
|
* @param array<string, string> $parameters
|
||||||
|
*/
|
||||||
|
public function __construct(
|
||||||
|
protected string $data = '',
|
||||||
|
null|string|MediaType $mediaType = null,
|
||||||
|
array $parameters = [],
|
||||||
|
protected bool $isBase64Encoded = false
|
||||||
|
) {
|
||||||
|
$this->setMediaType($mediaType);
|
||||||
|
$this->setParameters($parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::readFromString()
|
||||||
|
*
|
||||||
|
* @throws DecoderException
|
||||||
|
*/
|
||||||
|
public static function readFromString(string $dataUriScheme): self
|
||||||
|
{
|
||||||
|
$result = preg_match(self::PATTERN, $dataUriScheme, $matches);
|
||||||
|
|
||||||
|
if ($result === false) {
|
||||||
|
throw new DecoderException('Unable to decode data uri scheme from string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $matches['data'] ?? '';
|
||||||
|
$isBase64Encoded = array_key_exists('base64', $matches) && $matches['base64'] !== '';
|
||||||
|
|
||||||
|
$datauri = new self(
|
||||||
|
data: $isBase64Encoded ? base64_decode($data) : rawurldecode($data),
|
||||||
|
mediaType: $matches['mediaType'] ?? '',
|
||||||
|
isBase64Encoded: $isBase64Encoded,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (array_key_exists('parameters', $matches) && $matches['parameters'] !== '') {
|
||||||
|
$parameters = explode(';', $matches['parameters']);
|
||||||
|
$parameters = array_filter($parameters, fn(string $value): bool => $value !== '');
|
||||||
|
$parameters = array_map(fn(string $value): array => explode('=', $value), $parameters);
|
||||||
|
foreach ($parameters as $parameter) {
|
||||||
|
$datauri->setParameter(...$parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $datauri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::createBase64Encoded()
|
||||||
|
*/
|
||||||
|
public static function createBase64Encoded(
|
||||||
|
string $data,
|
||||||
|
null|string|MediaType $mediaType = null,
|
||||||
|
array $parameters = [],
|
||||||
|
): self {
|
||||||
|
return new self(
|
||||||
|
data: base64_encode($data),
|
||||||
|
mediaType: $mediaType,
|
||||||
|
parameters: $parameters,
|
||||||
|
isBase64Encoded: true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::data()
|
||||||
|
*/
|
||||||
|
public function data(): string
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::setData()
|
||||||
|
*/
|
||||||
|
public function setData(string $data): self
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::mediaType()
|
||||||
|
*/
|
||||||
|
public function mediaType(): ?string
|
||||||
|
{
|
||||||
|
return $this->mediaType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::setMediaType()
|
||||||
|
*/
|
||||||
|
public function setMediaType(null|string|MediaType $mediaType): self
|
||||||
|
{
|
||||||
|
$this->mediaType = $mediaType instanceof MediaType ? $mediaType->value : $mediaType;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::parameters()
|
||||||
|
*/
|
||||||
|
public function parameters(): array
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::setParameters()
|
||||||
|
*/
|
||||||
|
public function setParameters(array $parameters): self
|
||||||
|
{
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::appendParameters()
|
||||||
|
*/
|
||||||
|
public function appendParameters(array $parameters): self
|
||||||
|
{
|
||||||
|
foreach ($parameters as $key => $value) {
|
||||||
|
$this->setParameter((string) $key, (string) $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::parameter()
|
||||||
|
*/
|
||||||
|
public function parameter(string $key): ?string
|
||||||
|
{
|
||||||
|
return $this->parameters[$key] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::setParameter()
|
||||||
|
*/
|
||||||
|
public function setParameter(string $key, string $value): self
|
||||||
|
{
|
||||||
|
$this->parameters[$key] = $value;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::charset()
|
||||||
|
*/
|
||||||
|
public function charset(): ?string
|
||||||
|
{
|
||||||
|
return $this->parameter('charset');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::setCharset()
|
||||||
|
*/
|
||||||
|
public function setCharset(string $charset): self
|
||||||
|
{
|
||||||
|
$this->setParameter('charset', $charset);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare data for output
|
||||||
|
*/
|
||||||
|
private function encodedData(): string
|
||||||
|
{
|
||||||
|
return $this->isBase64Encoded ? $this->data : rawurlencode($this->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare all set parameters for output
|
||||||
|
*/
|
||||||
|
private function encodedParameters(): string
|
||||||
|
{
|
||||||
|
if (count($this->parameters) === 0 && $this->isBase64Encoded === false) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$parameters = array_map(function (mixed $key, mixed $value) {
|
||||||
|
return $key . '=' . $value;
|
||||||
|
}, array_keys($this->parameters), $this->parameters);
|
||||||
|
|
||||||
|
$parameterString = count($parameters) ? ';' . implode(';', $parameters) : '';
|
||||||
|
|
||||||
|
if ($this->isBase64Encoded) {
|
||||||
|
$parameterString .= ';base64';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $parameterString;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see DataUriInterface::toString()
|
||||||
|
*/
|
||||||
|
public function toString(): string
|
||||||
|
{
|
||||||
|
return 'data:' . $this->mediaType() . $this->encodedParameters() . ',' . $this->encodedData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*
|
||||||
|
* @see Stringable::__toString()
|
||||||
|
*/
|
||||||
|
public function __toString(): string
|
||||||
|
{
|
||||||
|
return $this->toString();
|
||||||
|
}
|
||||||
|
}
|
@@ -86,62 +86,6 @@ abstract class AbstractDecoder implements DecoderInterface
|
|||||||
return $decoded;
|
return $decoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse data uri
|
|
||||||
*/
|
|
||||||
protected function parseDataUri(mixed $input): object
|
|
||||||
{
|
|
||||||
$pattern = "/^data:(?P<mediatype>\w+\/[-+.\w]+)?" .
|
|
||||||
"(?P<parameters>(;[-\w]+=[-\w]+)*)(?P<base64>;base64)?,(?P<data>.*)/";
|
|
||||||
|
|
||||||
$result = preg_match($pattern, (string) $input, $matches);
|
|
||||||
|
|
||||||
return new class ($matches, $result)
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param array<mixed> $matches
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct(private array $matches, private int|false $result)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isValid(): bool
|
|
||||||
{
|
|
||||||
return (bool) $this->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function mediaType(): ?string
|
|
||||||
{
|
|
||||||
if (isset($this->matches['mediatype']) && !empty($this->matches['mediatype'])) {
|
|
||||||
return $this->matches['mediatype'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function hasMediaType(): bool
|
|
||||||
{
|
|
||||||
return !empty($this->mediaType());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isBase64Encoded(): bool
|
|
||||||
{
|
|
||||||
return isset($this->matches['base64']) && $this->matches['base64'] === ';base64';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function data(): ?string
|
|
||||||
{
|
|
||||||
if (isset($this->matches['data']) && !empty($this->matches['data'])) {
|
|
||||||
return $this->matches['data'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse and return a given file path or throw detailed exception if the path is invalid
|
* Parse and return a given file path or throw detailed exception if the path is invalid
|
||||||
*
|
*
|
||||||
|
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Intervention\Image\Drivers\Gd\Decoders;
|
namespace Intervention\Image\Drivers\Gd\Decoders;
|
||||||
|
|
||||||
|
use Intervention\Image\DataUri;
|
||||||
use Intervention\Image\Exceptions\DecoderException;
|
use Intervention\Image\Exceptions\DecoderException;
|
||||||
use Intervention\Image\Interfaces\ColorInterface;
|
use Intervention\Image\Interfaces\ColorInterface;
|
||||||
use Intervention\Image\Interfaces\DecoderInterface;
|
use Intervention\Image\Interfaces\DecoderInterface;
|
||||||
@@ -22,16 +23,6 @@ class DataUriImageDecoder extends BinaryImageDecoder implements DecoderInterface
|
|||||||
throw new DecoderException('Data Uri must be of type string.');
|
throw new DecoderException('Data Uri must be of type string.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$uri = $this->parseDataUri($input);
|
return parent::decode(DataUri::readFromString($input)->data());
|
||||||
|
|
||||||
if (!$uri->isValid()) {
|
|
||||||
throw new DecoderException('Input is no valid Data Uri Scheme.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uri->isBase64Encoded()) {
|
|
||||||
return parent::decode(base64_decode($uri->data()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::decode(urldecode($uri->data()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
namespace Intervention\Image\Drivers\Imagick\Decoders;
|
||||||
|
|
||||||
|
use Intervention\Image\DataUri;
|
||||||
use Intervention\Image\Exceptions\DecoderException;
|
use Intervention\Image\Exceptions\DecoderException;
|
||||||
use Intervention\Image\Interfaces\ColorInterface;
|
use Intervention\Image\Interfaces\ColorInterface;
|
||||||
use Intervention\Image\Interfaces\ImageInterface;
|
use Intervention\Image\Interfaces\ImageInterface;
|
||||||
@@ -21,16 +22,6 @@ class DataUriImageDecoder extends BinaryImageDecoder
|
|||||||
throw new DecoderException('Data Uri must be of type string.');
|
throw new DecoderException('Data Uri must be of type string.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$uri = $this->parseDataUri($input);
|
return parent::decode(DataUri::readFromString($input)->data());
|
||||||
|
|
||||||
if (!$uri->isValid()) {
|
|
||||||
throw new DecoderException('Input is no valid Data Uri Scheme.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($uri->isBase64Encoded()) {
|
|
||||||
return parent::decode(base64_decode($uri->data()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::decode(urldecode($uri->data()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Intervention\Image;
|
namespace Intervention\Image;
|
||||||
|
|
||||||
|
use Intervention\Image\Interfaces\DataUriInterface;
|
||||||
use Intervention\Image\Interfaces\EncodedImageInterface;
|
use Intervention\Image\Interfaces\EncodedImageInterface;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@@ -46,9 +47,12 @@ class EncodedImage extends File implements EncodedImageInterface
|
|||||||
*
|
*
|
||||||
* @see EncodedImageInterface::toDataUri()
|
* @see EncodedImageInterface::toDataUri()
|
||||||
*/
|
*/
|
||||||
public function toDataUri(): string
|
public function toDataUri(): DataUriInterface
|
||||||
{
|
{
|
||||||
return sprintf('data:%s;base64,%s', $this->mediaType(), base64_encode((string) $this));
|
return DataUri::createBase64Encoded(
|
||||||
|
data: (string) $this,
|
||||||
|
mediaType: $this->mediaType(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
92
src/Interfaces/DataUriInterface.php
Normal file
92
src/Interfaces/DataUriInterface.php
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Intervention\Image\Interfaces;
|
||||||
|
|
||||||
|
use Intervention\Image\MediaType;
|
||||||
|
|
||||||
|
interface DataUriInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Create new object from given data uri scheme string
|
||||||
|
*/
|
||||||
|
public static function readFromString(string $dataUriScheme): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create base 64 encoded data uri object from given unencoded data
|
||||||
|
*
|
||||||
|
* @param array<string, string> $parameters
|
||||||
|
*/
|
||||||
|
public static function createBase64Encoded(
|
||||||
|
string $data,
|
||||||
|
null|string|MediaType $mediaType = null,
|
||||||
|
array $parameters = [],
|
||||||
|
): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return current data uri data
|
||||||
|
*/
|
||||||
|
public function data(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set data of current data uri scheme
|
||||||
|
*/
|
||||||
|
public function setData(string $data): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get media type of current data uri output
|
||||||
|
*/
|
||||||
|
public function mediaType(): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set media type of current data uri output
|
||||||
|
*/
|
||||||
|
public function setMediaType(null|string|MediaType $mediaType): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all parameters of current data uri output
|
||||||
|
*
|
||||||
|
* @return array<string, string>
|
||||||
|
*/
|
||||||
|
public function parameters(): array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set (overwrite) all parameters of current data uri output
|
||||||
|
*
|
||||||
|
* @param array<string, string> $parameters
|
||||||
|
*/
|
||||||
|
public function setParameters(array $parameters): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append given parameters to current data uri output
|
||||||
|
*
|
||||||
|
* @param array<string, string> $parameters
|
||||||
|
*/
|
||||||
|
public function appendParameters(array $parameters): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of given parameter, return null if parameter is not set
|
||||||
|
*/
|
||||||
|
public function parameter(string $key): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set (overwrite) parameter of given key to given value
|
||||||
|
*/
|
||||||
|
public function setParameter(string $key, string $value): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get charset of current data uri scheme, null if no charset is defined
|
||||||
|
*/
|
||||||
|
public function charset(): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define charset of current data uri scheme
|
||||||
|
*/
|
||||||
|
public function setCharset(string $charset): self;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform current data uri scheme to string
|
||||||
|
*/
|
||||||
|
public function toString(): string;
|
||||||
|
}
|
@@ -19,5 +19,5 @@ interface EncodedImageInterface extends FileInterface
|
|||||||
/**
|
/**
|
||||||
* Transform encoded image data into an data uri string
|
* Transform encoded image data into an data uri string
|
||||||
*/
|
*/
|
||||||
public function toDataUri(): string;
|
public function toDataUri(): DataUriInterface;
|
||||||
}
|
}
|
||||||
|
103
tests/Providers/DataUriDataProvider.php
Normal file
103
tests/Providers/DataUriDataProvider.php
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Intervention\Image\Tests\Providers;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
|
||||||
|
class DataUriDataProvider
|
||||||
|
{
|
||||||
|
public static function validDataUris(): Generator
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
'data:,', // input
|
||||||
|
'', // data
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:,foo',
|
||||||
|
'foo',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:;base64,Zm9v',
|
||||||
|
'foo',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:,foo%20bar',
|
||||||
|
'foo bar',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH' .
|
||||||
|
'ElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==',
|
||||||
|
base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAH' .
|
||||||
|
'ElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=='),
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/vnd-example+xyz;foo=bar;base64,R0lGODdh',
|
||||||
|
'GIF87a',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/vnd-example+xyz;foo=bar;bar-baz=false;base64,R0lGODdh',
|
||||||
|
'GIF87a',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/plain;charset=UTF-8;page=21,the%20data:1234,5678',
|
||||||
|
'the data:1234,5678',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/plain;charset=US-ASCII,foobar',
|
||||||
|
'foobar',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/plain,foobar',
|
||||||
|
'foobar',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:,VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy=',
|
||||||
|
'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy=',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:,Hello%2C%20World%21',
|
||||||
|
'Hello, World!',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==',
|
||||||
|
'Hello, World!',
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text/html,<script>alert(\'hi\');</script>',
|
||||||
|
'<script>alert(\'hi\');</script>',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function invalidDataUris(): Generator
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
'foo'
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'bar'
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:'
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:;base64,foo'
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:foo/plain,foobar'
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:;base64,VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy='
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:image/jpeg;base64,VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy='
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZy4='
|
||||||
|
];
|
||||||
|
yield [
|
||||||
|
'data:text;base64,SGVsbG8sIFdvcmxkIQ=='
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
135
tests/Unit/DataUriTest.php
Normal file
135
tests/Unit/DataUriTest.php
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Intervention\Image\Tests\Unit;
|
||||||
|
|
||||||
|
use Generator;
|
||||||
|
use Intervention\Image\DataUri;
|
||||||
|
use Intervention\Image\MediaType;
|
||||||
|
use Intervention\Image\Tests\BaseTestCase;
|
||||||
|
use Intervention\Image\Tests\Providers\DataUriDataProvider;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProvider;
|
||||||
|
use PHPUnit\Framework\Attributes\DataProviderExternal;
|
||||||
|
|
||||||
|
class DataUriTest extends BaseTestCase
|
||||||
|
{
|
||||||
|
public function testSetGetData(): void
|
||||||
|
{
|
||||||
|
$datauri = new DataUri(data: 'test');
|
||||||
|
$this->assertEquals('test', $datauri->data());
|
||||||
|
$datauri->setData('foo');
|
||||||
|
$this->assertEquals('foo', $datauri->data());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[DataProvider('getSetMediaTypeDataProvider')]
|
||||||
|
public function testGetSetMediaType(mixed $inputMediaType, ?string $resultMediaType): void
|
||||||
|
{
|
||||||
|
$datauri = new DataUri(mediaType: $inputMediaType);
|
||||||
|
$this->assertEquals($resultMediaType, $datauri->mediaType());
|
||||||
|
$datauri->setMediaType(null);
|
||||||
|
$this->assertNull($datauri->mediaType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getSetMediaTypeDataProvider(): Generator
|
||||||
|
{
|
||||||
|
yield [null, null];
|
||||||
|
yield ['', null];
|
||||||
|
yield ['image/jpeg', 'image/jpeg'];
|
||||||
|
yield ['image/gif', 'image/gif'];
|
||||||
|
yield [MediaType::IMAGE_AVIF, 'image/avif'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSetGetParameters(): void
|
||||||
|
{
|
||||||
|
$datauri = new DataUri();
|
||||||
|
$this->assertEquals([], $datauri->parameters());
|
||||||
|
$datauri->setParameters(['foo' => 'bar']);
|
||||||
|
$this->assertEquals(['foo' => 'bar'], $datauri->parameters());
|
||||||
|
$datauri->setParameters(['bar' => 'baz', 'test' => 123]);
|
||||||
|
$this->assertEquals(['bar' => 'baz', 'test' => '123'], $datauri->parameters());
|
||||||
|
$datauri->setParameter('test', '456');
|
||||||
|
$this->assertEquals(['bar' => 'baz', 'test' => '456'], $datauri->parameters());
|
||||||
|
$datauri->appendParameters(['bar' => 'foobar', 'append' => 'ok']);
|
||||||
|
$this->assertEquals(['bar' => 'foobar', 'test' => '456', 'append' => 'ok'], $datauri->parameters());
|
||||||
|
$this->assertEquals('foobar', $datauri->parameter('bar'));
|
||||||
|
$this->assertEquals('456', $datauri->parameter('test'));
|
||||||
|
$this->assertEquals('ok', $datauri->parameter('append'));
|
||||||
|
$this->assertEquals(null, $datauri->parameter('none'));
|
||||||
|
$datauri->setCharset('utf-8');
|
||||||
|
$this->assertEquals('utf-8', $datauri->charset());
|
||||||
|
$this->assertEquals([
|
||||||
|
'bar' => 'foobar',
|
||||||
|
'test' => '456',
|
||||||
|
'append' => 'ok',
|
||||||
|
'charset' => 'utf-8',
|
||||||
|
], $datauri->parameters());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array<string, string> $parameters
|
||||||
|
*/
|
||||||
|
#[DataProvider('toStringDataProvider')]
|
||||||
|
public function testToString(
|
||||||
|
string $data,
|
||||||
|
null|string|MediaType $mediaType,
|
||||||
|
array $parameters,
|
||||||
|
bool $isBase64Encoded,
|
||||||
|
string $result,
|
||||||
|
): void {
|
||||||
|
$datauri = new DataUri($data, $mediaType, $parameters, $isBase64Encoded);
|
||||||
|
$this->assertEquals($result, $datauri->toString());
|
||||||
|
$this->assertEquals($result, (string) $datauri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function toStringDataProvider(): Generator
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
'',
|
||||||
|
null,
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
'data:,'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'foo',
|
||||||
|
null,
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
'data:,foo'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'foo',
|
||||||
|
'text/plain',
|
||||||
|
[],
|
||||||
|
false,
|
||||||
|
'data:text/plain,foo'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'foo',
|
||||||
|
'text/plain',
|
||||||
|
['charset' => 'utf-8'],
|
||||||
|
false,
|
||||||
|
'data:text/plain;charset=utf-8,foo'
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'foo',
|
||||||
|
'text/plain',
|
||||||
|
['charset' => 'utf-8'],
|
||||||
|
true,
|
||||||
|
'data:text/plain;charset=utf-8;base64,foo'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[DataProviderExternal(DataUriDataProvider::class, 'validDataUris')]
|
||||||
|
public function testCreateFromString(string $dataUriScheme, string $resultData): void
|
||||||
|
{
|
||||||
|
$datauri = DataUri::readFromString($dataUriScheme);
|
||||||
|
$this->assertInstanceOf(DataUri::class, $datauri);
|
||||||
|
$this->assertEquals($resultData, $datauri->data());
|
||||||
|
}
|
||||||
|
}
|
@@ -47,49 +47,6 @@ final class AbstractDecoderTest extends BaseTestCase
|
|||||||
$this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));
|
$this->assertEquals('Oliver Vogel', $result->get('IFD0.Artist'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testParseDataUri(): void
|
|
||||||
{
|
|
||||||
$decoder = new class () extends AbstractDecoder
|
|
||||||
{
|
|
||||||
public function parse(mixed $input): object
|
|
||||||
{
|
|
||||||
return parent::parseDataUri($input);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function decode(mixed $input): ImageInterface|ColorInterface
|
|
||||||
{
|
|
||||||
throw new Exception('');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$result = $decoder->parse(
|
|
||||||
'data:image/gif;foo=bar;base64,R0lGODdhAwADAKIAAAQyrKTy/ByS7AQytLT2/AAAAAAAAAAAACwAAAAAAwADAAADBhgU0gMgAQA7'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->assertTrue($result->isValid());
|
|
||||||
$this->assertEquals('image/gif', $result->mediaType());
|
|
||||||
$this->assertTrue($result->hasMediaType());
|
|
||||||
$this->assertTrue($result->isBase64Encoded());
|
|
||||||
$this->assertEquals(
|
|
||||||
'R0lGODdhAwADAKIAAAQyrKTy/ByS7AQytLT2/AAAAAAAAAAAACwAAAAAAwADAAADBhgU0gMgAQA7',
|
|
||||||
$result->data()
|
|
||||||
);
|
|
||||||
|
|
||||||
$result = $decoder->parse('data:text/plain;charset=utf-8,test');
|
|
||||||
$this->assertTrue($result->isValid());
|
|
||||||
$this->assertEquals('text/plain', $result->mediaType());
|
|
||||||
$this->assertTrue($result->hasMediaType());
|
|
||||||
$this->assertFalse($result->isBase64Encoded());
|
|
||||||
$this->assertEquals('test', $result->data());
|
|
||||||
|
|
||||||
$result = $decoder->parse('data:;charset=utf-8,');
|
|
||||||
$this->assertTrue($result->isValid());
|
|
||||||
$this->assertNull($result->mediaType());
|
|
||||||
$this->assertFalse($result->hasMediaType());
|
|
||||||
$this->assertFalse($result->isBase64Encoded());
|
|
||||||
$this->assertNull($result->data());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testIsValidBase64(): void
|
public function testIsValidBase64(): void
|
||||||
{
|
{
|
||||||
$decoder = new class () extends AbstractDecoder
|
$decoder = new class () extends AbstractDecoder
|
||||||
|
Reference in New Issue
Block a user