diff --git a/src/Knp/Snappy/AbstractGenerator.php b/src/Knp/Snappy/AbstractGenerator.php index c2aad853..2a93529b 100644 --- a/src/Knp/Snappy/AbstractGenerator.php +++ b/src/Knp/Snappy/AbstractGenerator.php @@ -21,6 +21,10 @@ abstract class AbstractGenerator implements GeneratorInterface, LoggerAwareInter { use LoggerAwareTrait; + protected const ALLOWED_PROTOCOLS = ['file']; + + protected const WINDOWS_LOCAL_FILENAME_REGEX = '/^[a-z]:(?:[\\\\\/]?(?:[\w\s!#()-]+|[\.]{1,2})+)*[\\\\\/]?/i'; + /** * @var array */ @@ -625,21 +629,8 @@ protected function executeCommand($command) */ protected function prepareOutput($filename, $overwrite) { - if (false === $parsedFilename = \parse_url($filename)) { - throw new InvalidArgumentException('The output filename is invalid.'); - } - - $scheme = isset($parsedFilename['scheme']) ? \mb_strtolower($parsedFilename['scheme']) : ''; - if (!( - $scheme === '' || - $scheme === 'file' || - ( - // Check if it's a Windows path - \strlen($scheme) === 1 && - \preg_match('/^[a-z]:(?:[\\\\\/]?(?:[\w\s!#()-]+|[\.]{1,2})+)*[\\\\\/]?/i', $filename) === 1 - ) - )) { - throw new InvalidArgumentException(\sprintf('The output file scheme is not supported. Expected \'file\' but got \'%s\'.', $scheme)); + if (!$this->isProtocolAllowed($filename)) { + throw new InvalidArgumentException(\sprintf('The output file scheme is not supported. Expected one of [\'%s\'].', \implode('\', \'', self::ALLOWED_PROTOCOLS))); } $directory = \dirname($filename); @@ -659,6 +650,34 @@ protected function prepareOutput($filename, $overwrite) } } + /** + * Verifies if the given filename has a supported protocol. + * + * @param string $filename + * + * @throws InvalidArgumentException + * + * @return bool + */ + protected function isProtocolAllowed($filename) + { + if (false === $parsedFilename = \parse_url($filename)) { + throw new InvalidArgumentException('The filename is not valid.'); + } + + $protocol = isset($parsedFilename['scheme']) ? \mb_strtolower($parsedFilename['scheme']) : 'file'; + + if ( + \PHP_OS_FAMILY === 'Windows' + && \strlen($protocol) === 1 + && \preg_match(self::WINDOWS_LOCAL_FILENAME_REGEX, $filename) + ) { + $protocol = 'file'; + } + + return \in_array($protocol, self::ALLOWED_PROTOCOLS, true); + } + /** * Wrapper for the "file_get_contents" function. *