Skip to content

Commit 60a19b3

Browse files
committed
:octocat: QROutputInterface::moduleValueIsValid() improved checks & tests
1 parent b18647a commit 60a19b3

15 files changed

+259
-30
lines changed

src/Output/QREps.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public static function moduleValueIsValid($value):bool{
3232
}
3333

3434
// check the first values of the array
35-
foreach($value as $i => $val){
35+
foreach(array_values($value) as $i => $val){
3636

3737
if($i > 3){
3838
break;
@@ -61,8 +61,8 @@ protected function getModuleValue($value):array{
6161
break;
6262
}
6363

64-
// clamp value and convert from 0-255 to 0-1 RGB/CMYK range
65-
$values[] = round((max(0, min(255, $val)) / 255), 6);
64+
// clamp value and convert from int 0-255 to float 0-1 RGB/CMYK range
65+
$values[] = round((max(0, min(255, intval($val))) / 255), 6);
6666
}
6767

6868
return $values;

src/Output/QRFpdf.php

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use chillerlan\Settings\SettingsContainerInterface;
1616
use FPDF;
1717

18-
use function class_exists, count, is_array, is_numeric, max, min;
18+
use function array_values, class_exists, count, intval, is_array, is_numeric, max, min;
1919

2020
/**
2121
* QRFpdf output module (requires fpdf)
@@ -54,27 +54,39 @@ public static function moduleValueIsValid($value):bool{
5454
}
5555

5656
// check the first 3 values of the array
57-
for($i = 0; $i < 3; $i++){
58-
if(!is_numeric($value[$i])){
57+
foreach(array_values($value) as $i => $val){
58+
59+
if($i > 2){
60+
break;
61+
}
62+
63+
if(!is_numeric($val)){
5964
return false;
6065
}
66+
6167
}
6268

6369
return true;
6470
}
6571

6672
/**
73+
* @param array $value
74+
*
6775
* @inheritDoc
6876
*/
6977
protected function getModuleValue($value):array{
70-
$v = [];
78+
$values = [];
79+
80+
foreach(array_values($value) as $i => $val){
81+
82+
if($i > 2){
83+
break;
84+
}
7185

72-
for($i = 0; $i < 3; $i++){
73-
// clamp value
74-
$v[] = (int)max(0, min(255, $value[$i]));
86+
$values[] = max(0, min(255, intval($val)));
7587
}
7688

77-
return $v;
89+
return $values;
7890
}
7991

8092
/**

src/Output/QRGdImage.php

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
use chillerlan\QRCode\Data\QRMatrix;
1616
use chillerlan\Settings\SettingsContainerInterface;
1717
use ErrorException, Throwable;
18-
use function count, extension_loaded, imagecolorallocate, imagecolortransparent, imagecreatetruecolor,
19-
imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, is_array, is_numeric,
20-
max, min, ob_end_clean, ob_get_contents, ob_start, restore_error_handler, set_error_handler;
18+
use function array_values, count, extension_loaded, imagecolorallocate, imagecolortransparent, imagecreatetruecolor,
19+
imagedestroy, imagefilledellipse, imagefilledrectangle, imagegif, imagejpeg, imagepng, imagescale, intval,
20+
is_array, is_numeric, max, min, ob_end_clean, ob_get_contents, ob_start, restore_error_handler, set_error_handler;
2121

2222
/**
2323
* Converts the matrix into GD images, raw or base64 output (requires ext-gd)
@@ -89,29 +89,41 @@ public static function moduleValueIsValid($value):bool{
8989
}
9090

9191
// check the first 3 values of the array
92-
for($i = 0; $i < 3; $i++){
93-
if(!is_numeric($value[$i])){
92+
foreach(array_values($value) as $i => $val){
93+
94+
if($i > 2){
95+
break;
96+
}
97+
98+
if(!is_numeric($val)){
9499
return false;
95100
}
101+
96102
}
97103

98104
return true;
99105
}
100106

101107
/**
108+
* @param array $value
109+
*
102110
* @inheritDoc
103111
* @throws \chillerlan\QRCode\Output\QRCodeOutputException
104112
*/
105113
protected function getModuleValue($value):int{
106-
$v = [];
114+
$values = [];
115+
116+
foreach(array_values($value) as $i => $val){
117+
118+
if($i > 2){
119+
break;
120+
}
107121

108-
for($i = 0; $i < 3; $i++){
109-
// clamp value
110-
$v[] = (int)max(0, min(255, $value[$i]));
122+
$values[] = max(0, min(255, intval($val)));
111123
}
112124

113125
/** @phan-suppress-next-line PhanParamTooFewInternalUnpack */
114-
$color = imagecolorallocate($this->image, ...$v);
126+
$color = imagecolorallocate($this->image, ...$values);
115127

116128
if($color === false){
117129
throw new QRCodeOutputException('could not set color: imagecolorallocate() error');

src/Output/QRImagick.php

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use chillerlan\QRCode\Data\QRMatrix;
1616
use chillerlan\Settings\SettingsContainerInterface;
1717
use finfo, Imagick, ImagickDraw, ImagickPixel;
18-
use function extension_loaded, is_string;
18+
use function extension_loaded, in_array, is_string, preg_match, strlen;
1919
use const FILEINFO_MIME_TYPE;
2020

2121
/**
@@ -60,16 +60,44 @@ public function __construct(SettingsContainerInterface $options, QRMatrix $matri
6060
}
6161

6262
/**
63-
* @todo: check/validate possible values
63+
* note: we're not necessarily validating the several values, just checking the general syntax
64+
*
6465
* @see https://www.php.net/manual/imagickpixel.construct.php
6566
* @inheritDoc
6667
*/
6768
public static function moduleValueIsValid($value):bool{
68-
return is_string($value);
69+
70+
if(!is_string($value)){
71+
return false;
72+
}
73+
74+
$value = trim($value);
75+
76+
// hex notation
77+
// #rgb(a)
78+
// #rrggbb(aa)
79+
// #rrrrggggbbbb(aaaa)
80+
// ...
81+
if(preg_match('/^#[a-f]+$/i', $value) && in_array((strlen($value) - 1), [3, 4, 6, 8, 9, 12, 16, 24, 32], true)){
82+
return true;
83+
}
84+
85+
// css (-like) func(...values)
86+
if(preg_match('#^(graya?|hs(b|la?)|rgba?)\([\d .,%]+\)$#i', $value)){
87+
return true;
88+
}
89+
90+
// predefined css color
91+
if(preg_match('/^[a-z]+$/i', $value)){
92+
return true;
93+
}
94+
95+
return false;
6996
}
7097

7198
/**
7299
* @inheritDoc
100+
* @throws \ImagickPixelException
73101
*/
74102
protected function getModuleValue($value):ImagickPixel{
75103
return new ImagickPixel($value);

src/Output/QRMarkup.php

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,46 @@
1010

1111
namespace chillerlan\QRCode\Output;
1212

13-
use function is_string, strip_tags, trim;
13+
use function is_string, preg_match, strip_tags, trim;
1414

1515
/**
1616
* Abstract for markup types: HTML, SVG, ... XML anyone?
1717
*/
1818
abstract class QRMarkup extends QROutputAbstract{
1919

2020
/**
21+
* note: we're not necessarily validating the several values, just checking the general syntax
22+
* note: css4 colors are not included
23+
*
24+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
2125
* @inheritDoc
2226
*/
2327
public static function moduleValueIsValid($value):bool{
24-
return is_string($value);
28+
29+
if(!is_string($value)){
30+
return false;
31+
}
32+
33+
$value = trim(strip_tags($value), " '\"\r\n\t");
34+
35+
// hex notation
36+
// #rgb(a)
37+
// #rrggbb(aa)
38+
if(preg_match('/^#([\da-f]{3}){1,2}$|^#([\da-f]{4}){1,2}$/i', $value)){
39+
return true;
40+
}
41+
42+
// css: hsla/rgba(...values)
43+
if(preg_match('#^(hsla?|rgba?)\([\d .,%/]+\)$#i', $value)){
44+
return true;
45+
}
46+
47+
// predefined css color
48+
if(preg_match('/^[a-z]+$/i', $value)){
49+
return true;
50+
}
51+
52+
return false;
2553
}
2654

2755
/**

src/Output/QRMarkupSVG.php

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace chillerlan\QRCode\Output;
1212

1313
use chillerlan\QRCode\Data\QRMatrix;
14-
use function array_chunk, implode, sprintf;
14+
use function array_chunk, implode, is_string, preg_match, sprintf, trim;
1515

1616
/**
1717
* SVG output
@@ -23,6 +23,27 @@
2323
*/
2424
class QRMarkupSVG extends QRMarkup{
2525

26+
/**
27+
* @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/fill
28+
* @inheritDoc
29+
*/
30+
public static function moduleValueIsValid($value):bool{
31+
32+
if(!is_string($value)){
33+
return false;
34+
}
35+
36+
$value = trim($value);
37+
38+
// url(...)
39+
if(preg_match('~^url\([-/#a-z\d]+\)$~i', $value)){
40+
return true;
41+
}
42+
43+
// otherwise check for standard css notation
44+
return parent::moduleValueIsValid($value);
45+
}
46+
2647
/**
2748
* @inheritDoc
2849
*/

src/Output/QROutputInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ interface QROutputInterface{
8989
/**
9090
* Determines whether the given value is valid
9191
*
92-
* @param mixed|null $value
92+
* @param mixed $value
9393
*/
9494
public static function moduleValueIsValid($value):bool;
9595

tests/Output/QREpsTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ class QREpsTest extends QROutputTestAbstract{
1919
protected string $FQN = QREps::class;
2020
protected string $type = QROutputInterface::EPS;
2121

22+
public static function moduleValueProvider():array{
23+
return [
24+
'valid: 3 int' => [[123, 123, 123], true],
25+
'valid: 4 int' => [[123, 123, 123, 123], true],
26+
'valid: w/invalid extra element' => [[123, 123, 123, 123, 'abc'], true],
27+
'valid: numeric string' => [['123', '123', '123'], true],
28+
'invalid: wrong type' => ['foo', false],
29+
'invalid: array too short' => [[1, 2], false],
30+
'invalid: contains non-number' => [[1, 'b', 3], false],
31+
];
32+
}
33+
2234
/**
2335
* @inheritDoc
2436
*/

tests/Output/QRFpdfTest.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,17 @@ protected function setUp():void{
3636
parent::setUp();
3737
}
3838

39+
public static function moduleValueProvider():array{
40+
return [
41+
'valid: int' => [[123, 123, 123], true],
42+
'valid: w/invalid extra element' => [[123, 123, 123, 'abc'], true],
43+
'valid: numeric string' => [['123', '123', '123'], true],
44+
'invalid: wrong type' => ['foo', false],
45+
'invalid: array too short' => [[1, 2], false],
46+
'invalid: contains non-number' => [[1, 'b', 3], false],
47+
];
48+
}
49+
3950
/**
4051
* @inheritDoc
4152
*/

tests/Output/QRGdImageTestAbstract.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ protected function setUp():void{
3333
parent::setUp();
3434
}
3535

36+
public static function moduleValueProvider():array{
37+
return [
38+
'valid: int' => [[123, 123, 123], true],
39+
'valid: w/invalid extra element' => [[123, 123, 123, 'abc'], true],
40+
'valid: numeric string' => [['123', '123', '123'], true],
41+
'invalid: wrong type' => ['foo', false],
42+
'invalid: array too short' => [[1, 2], false],
43+
'invalid: contains non-number' => [[1, 'b', 3], false],
44+
];
45+
}
46+
3647
/**
3748
* @inheritDoc
3849
*/

0 commit comments

Comments
 (0)