diff --git a/src/Output/CssColorModuleValueTrait.php b/src/Output/CssColorModuleValueTrait.php new file mode 100644 index 000000000..817ed7f13 --- /dev/null +++ b/src/Output/CssColorModuleValueTrait.php @@ -0,0 +1,74 @@ + + * @copyright 2024 smiley + * @license MIT + */ + +namespace chillerlan\QRCode\Output; + +use function is_string, preg_match, strip_tags, trim; + +/** + * Module value checks for output classes that use CSS colors + */ +trait CssColorModuleValueTrait{ + + /** + * note: we're not necessarily validating the several values, just checking the general syntax + * note: css4 colors are not included + * + * @todo: XSS proof + * + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value + * @implements \chillerlan\QRCode\Output\QROutputInterface::moduleValueIsValid() + * @inheritDoc + */ + public static function moduleValueIsValid(mixed $value):bool{ + + if(!is_string($value)){ + return false; + } + + $value = trim(strip_tags($value), " '\"\r\n\t"); + + // hex notation + // #rgb(a) + // #rrggbb(aa) + if(preg_match('/^#([\da-f]{3}){1,2}$|^#([\da-f]{4}){1,2}$/i', $value)){ + return true; + } + + // css: hsla/rgba(...values) + if(preg_match('#^(hsla?|rgba?)\([\d .,%/]+\)$#i', $value)){ + return true; + } + + // predefined css color + if(preg_match('/^[a-z]+$/i', $value)){ + return true; + } + + return false; + } + + /** + * @implements \chillerlan\QRCode\Output\QROutputAbstract::prepareModuleValue() + * @inheritDoc + */ + protected function prepareModuleValue(mixed $value):string{ + return trim(strip_tags($value), " '\"\r\n\t"); + } + + /** + * @implements \chillerlan\QRCode\Output\QROutputAbstract::getDefaultModuleValue() + * @inheritDoc + */ + protected function getDefaultModuleValue(bool $isDark):string{ + return ($isDark) ? '#000' : '#fff'; + } + +} diff --git a/src/Output/QRMarkup.php b/src/Output/QRMarkup.php index 06fb53728..f7d52c1e0 100644 --- a/src/Output/QRMarkup.php +++ b/src/Output/QRMarkup.php @@ -10,63 +10,11 @@ namespace chillerlan\QRCode\Output; -use function is_string, preg_match, strip_tags, trim; - /** * Abstract for markup types: HTML, SVG, ... XML anyone? */ abstract class QRMarkup extends QROutputAbstract{ - - /** - * note: we're not necessarily validating the several values, just checking the general syntax - * note: css4 colors are not included - * - * @todo: XSS proof - * - * @see https://developer.mozilla.org/en-US/docs/Web/CSS/color_value - * @inheritDoc - */ - public static function moduleValueIsValid(mixed $value):bool{ - - if(!is_string($value)){ - return false; - } - - $value = trim(strip_tags($value), " '\"\r\n\t"); - - // hex notation - // #rgb(a) - // #rrggbb(aa) - if(preg_match('/^#([\da-f]{3}){1,2}$|^#([\da-f]{4}){1,2}$/i', $value)){ - return true; - } - - // css: hsla/rgba(...values) - if(preg_match('#^(hsla?|rgba?)\([\d .,%/]+\)$#i', $value)){ - return true; - } - - // predefined css color - if(preg_match('/^[a-z]+$/i', $value)){ - return true; - } - - return false; - } - - /** - * @inheritDoc - */ - protected function prepareModuleValue(mixed $value):string{ - return trim(strip_tags($value), " '\"\r\n\t"); - } - - /** - * @inheritDoc - */ - protected function getDefaultModuleValue(bool $isDark):string{ - return ($isDark) ? '#000' : '#fff'; - } + use CssColorModuleValueTrait; /** * @inheritDoc diff --git a/tests/Output/CssColorModuleValueProviderTrait.php b/tests/Output/CssColorModuleValueProviderTrait.php new file mode 100644 index 000000000..52ee60ad5 --- /dev/null +++ b/tests/Output/CssColorModuleValueProviderTrait.php @@ -0,0 +1,45 @@ + + * @copyright 2024 smiley + * @license MIT + */ + +namespace chillerlan\QRCodeTest\Output; + +/** + * A data provider for use in tests that include CssColorModuleValueTrait + * + * @see \chillerlan\QRCode\Output\CssColorModuleValueTrait + */ +trait CssColorModuleValueProviderTrait{ + + /** + * @implements \chillerlan\QRCodeTest\Output\QROutputTestAbstract::moduleValueProvider() + */ + public static function moduleValueProvider():array{ + return [ + 'invalid: wrong type' => [[], false], + 'valid: hex color (3)' => ['#abc', true], + 'valid: hex color (4)' => ['#abcd', true], + 'valid: hex color (6)' => ['#aabbcc', true], + 'valid: hex color (8)' => ['#aabbccdd', true], + 'invalid: hex color (non-hex)' => ['#aabbcxyz', false], + 'invalid: hex color (too short)' => ['#aa', false], + 'invalid: hex color (5)' => ['#aabbc', false], + 'invalid: hex color (7)' => ['#aabbccd', false], + 'valid: rgb(...%)' => ['rgb(100.0%, 0.0%, 0.0%)', true], + 'valid: rgba(...)' => [' rgba(255, 0, 0, 1.0) ', true], + 'valid: hsl(...)' => ['hsl(120, 60%, 50%)', true], + 'valid: hsla(...)' => ['hsla(120, 255, 191.25, 1.0)', true], + 'invalid: rgba(non-numeric)' => ['rgba(255, 0, whatever, 0, 1.0)', false], + 'invalid: rgba(extra-char)' => ['rgba(255, 0, 0, 1.0);', false], + 'valid: csscolor' => ['purple', true], + 'invalid: c5sc0lor' => ['c5sc0lor', false], + ]; + } + +} diff --git a/tests/Output/QRMarkupTestAbstract.php b/tests/Output/QRMarkupTestAbstract.php index e724332f1..1dc23abe2 100644 --- a/tests/Output/QRMarkupTestAbstract.php +++ b/tests/Output/QRMarkupTestAbstract.php @@ -16,28 +16,7 @@ use chillerlan\QRCode\Data\QRMatrix; * Tests the QRMarkup output module */ abstract class QRMarkupTestAbstract extends QROutputTestAbstract{ - - public static function moduleValueProvider():array{ - return [ - 'invalid: wrong type' => [[], false], - 'valid: hex color (3)' => ['#abc', true], - 'valid: hex color (4)' => ['#abcd', true], - 'valid: hex color (6)' => ['#aabbcc', true], - 'valid: hex color (8)' => ['#aabbccdd', true], - 'invalid: hex color (non-hex)' => ['#aabbcxyz', false], - 'invalid: hex color (too short)' => ['#aa', false], - 'invalid: hex color (5)' => ['#aabbc', false], - 'invalid: hex color (7)' => ['#aabbccd', false], - 'valid: rgb(...%)' => ['rgb(100.0%, 0.0%, 0.0%)', true], - 'valid: rgba(...)' => [' rgba(255, 0, 0, 1.0) ', true], - 'valid: hsl(...)' => ['hsl(120, 60%, 50%)', true], - 'valid: hsla(...)' => ['hsla(120, 255, 191.25, 1.0)', true], - 'invalid: rgba(non-numeric)' => ['rgba(255, 0, whatever, 0, 1.0)', false], - 'invalid: rgba(extra-char)' => ['rgba(255, 0, 0, 1.0);', false], - 'valid: csscolor' => ['purple', true], - 'invalid: c5sc0lor' => ['c5sc0lor', false], - ]; - } + use CssColorModuleValueProviderTrait; /** * @inheritDoc