From ab5c205d9d9a5b0babaa953aa648bda2fdd4dd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Andr=C3=A1s=20Horv=C3=A1th?= Date: Wed, 23 Jan 2019 11:14:46 +0100 Subject: [PATCH 1/6] PSR-7 file validation implemented --- src/File/Crc32.php | 28 ++--- src/File/ExcludeExtension.php | 27 ++--- src/File/ExcludeMimeType.php | 33 ++---- src/File/Exists.php | 29 ++---- src/File/Extension.php | 27 ++--- src/File/FileInformationTrait.php | 166 ++++++++++++++++++++++++++++++ src/File/Hash.php | 29 ++---- src/File/ImageSize.php | 27 ++--- src/File/Md5.php | 28 ++--- src/File/MimeType.php | 32 ++---- src/File/NotExists.php | 29 ++---- src/File/Sha1.php | 28 ++--- src/File/Size.php | 27 ++--- src/File/WordCount.php | 27 ++--- 14 files changed, 274 insertions(+), 263 deletions(-) create mode 100644 src/File/FileInformationTrait.php diff --git a/src/File/Crc32.php b/src/File/Crc32.php index 126d63d56..9c225a1f4 100644 --- a/src/File/Crc32.php +++ b/src/File/Crc32.php @@ -9,13 +9,15 @@ namespace Zend\Validator\File; -use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the crc32 hash of given files */ class Crc32 extends Hash { + use FileInformationTrait; + /** * @const string Error constants */ @@ -85,32 +87,18 @@ public function addCrc32($options) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } $hashes = array_unique(array_keys($this->getHash())); - $filehash = hash_file('crc32', $file); + $filehash = hash_file('crc32', $fileInfo['file']); if ($filehash === false) { $this->error(self::NOT_DETECTED); return false; diff --git a/src/File/ExcludeExtension.php b/src/File/ExcludeExtension.php index 1d1cb4218..9f8d3e034 100644 --- a/src/File/ExcludeExtension.php +++ b/src/File/ExcludeExtension.php @@ -9,6 +9,7 @@ namespace Zend\Validator\File; +use Zend\Validator\File\FileInformationTrait; use Zend\Validator\Exception; /** @@ -16,6 +17,8 @@ */ class ExcludeExtension extends Extension { + use FileInformationTrait; + /** * @const string Error constants */ @@ -40,31 +43,17 @@ class ExcludeExtension extends Extension */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } - $extension = substr($filename, strrpos($filename, '.') + 1); + $extension = substr($fileInfo['filename'], strrpos($fileInfo['filename'], '.') + 1); $extensions = $this->getExtension(); if ($this->getCase() && (! in_array($extension, $extensions))) { diff --git a/src/File/ExcludeMimeType.php b/src/File/ExcludeMimeType.php index 66c8eadb6..b217c9219 100644 --- a/src/File/ExcludeMimeType.php +++ b/src/File/ExcludeMimeType.php @@ -10,13 +10,15 @@ namespace Zend\Validator\File; use finfo; -use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the mime type of a file */ class ExcludeMimeType extends MimeType { + use FileInformationTrait; + const FALSE_TYPE = 'fileExcludeMimeTypeFalse'; const NOT_DETECTED = 'fileExcludeMimeTypeNotDetected'; const NOT_READABLE = 'fileExcludeMimeTypeNotReadable'; @@ -41,29 +43,12 @@ class ExcludeMimeType extends MimeType */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $filetype = $file['type']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name']) || ! isset($value['type'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - $filetype = $value['type']; - } else { - $file = $value; - $filename = basename($file); - $filetype = null; - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file, true); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_READABLE); return false; } @@ -80,12 +65,12 @@ public function isValid($value, $file = null) $this->type = null; if (! empty($this->finfo)) { - $this->type = finfo_file($this->finfo, $file); + $this->type = finfo_file($this->finfo, $fileInfo['file']); } } if (empty($this->type) && $this->getHeaderCheck()) { - $this->type = $filetype; + $this->type = $fileInfo['filetype']; } if (empty($this->type)) { diff --git a/src/File/Exists.php b/src/File/Exists.php index 817be1658..9968cc6cb 100644 --- a/src/File/Exists.php +++ b/src/File/Exists.php @@ -11,12 +11,15 @@ use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator which checks if the file already exists in the directory */ class Exists extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -144,31 +147,15 @@ public function addDirectory($directory) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - $this->setValue($filename); - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = basename($file); - $this->setValue($value['name']); - } else { - $file = $value; - $filename = basename($file); - $this->setValue($filename); - } + $fileInfo = $this->getFileInfo($value, $file, false, true); + + $this->setValue($fileInfo['filename']); $check = false; $directories = $this->getDirectory(true); if (! isset($directories)) { $check = true; - if (! file_exists($file)) { + if (! file_exists($fileInfo['file'])) { $this->error(self::DOES_NOT_EXIST); return false; } @@ -179,7 +166,7 @@ public function isValid($value, $file = null) } $check = true; - if (! file_exists($directory . DIRECTORY_SEPARATOR . $filename)) { + if (! file_exists($directory . DIRECTORY_SEPARATOR . $fileInfo['basename'])) { $this->error(self::DOES_NOT_EXIST); return false; } diff --git a/src/File/Extension.php b/src/File/Extension.php index e502dc993..0e1cd9ed0 100644 --- a/src/File/Extension.php +++ b/src/File/Extension.php @@ -12,6 +12,7 @@ use Traversable; use Zend\Stdlib\ArrayUtils; use Zend\Validator\AbstractValidator; +use Zend\Validator\File\FileInformationTrait; use Zend\Validator\Exception; /** @@ -19,6 +20,8 @@ */ class Extension extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -177,31 +180,17 @@ public function addExtension($extension) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } - $extension = substr($filename, strrpos($filename, '.') + 1); + $extension = substr($fileInfo['filename'], strrpos($fileInfo['filename'], '.') + 1); $extensions = $this->getExtension(); if ($this->getCase() && (in_array($extension, $extensions))) { diff --git a/src/File/FileInformationTrait.php b/src/File/FileInformationTrait.php new file mode 100644 index 000000000..a7454e611 --- /dev/null +++ b/src/File/FileInformationTrait.php @@ -0,0 +1,166 @@ +getLegacyFileInfo($file, $hasType, $hasBasename); + } + + if (is_array($value)) { + return $this->getSapiFileInfo($value, $hasType, $hasBasename); + } + + if ($value instanceof UploadedFileInterface) { + return $this->getPsr7FileInfo($value, $hasType, $hasBasename); + } + + return $this->getFileBasedFileInfo($value, $hasType, $hasBasename); + } + + /** + * Generate file information array with Legacy Zend\Transfer API + * + * @param object $file File data from \Zend\File\Transfer\Transfer + * @param bool $hasType Return with filetype + * @param bool $hasBasename Basename is calculated from location path + * @return array + */ + private function getLegacyFileInfo( + $file, + bool $hasType = false, + bool $hasBasename = false + ) { + $fileInfo = []; + + $fileInfo['filename'] = $file['name']; + $fileInfo['file'] = $file['tmp_name']; + + if ($hasBasename) { + $fileInfo['basename'] = basename($fileInfo['file']); + } + + if (! $hasType) { + $fileInfo['filetype'] = $file['type']; + } + + return $fileInfo; + } + + /** + * Generate file information array with Sapi + * + * @param array $file File data from Sapi + * @param bool $hasType Return with filetype + * @param bool $hasBasename Filename is calculated from location path + * @return array + */ + private function getSapiFileInfo( + array $file, + bool $hasType = false, + bool $hasBasename = false + ) { + if (! isset($file['tmp_name']) || ! isset($file['name'])) { + throw new Exception\InvalidArgumentException( + 'Value array must be in $_FILES format' + ); + } + + $fileInfo = []; + + $fileInfo['file'] = $file['tmp_name']; + $fileInfo['filename'] = $file['name']; + + if ($hasBasename) { + $fileInfo['basename'] = basename($fileInfo['file']); + } + + if (! $hasType) { + $fileInfo['filetype'] = $file['type']; + } + + return $fileInfo; + } + + /** + * Generate file information array with PSR-7 UploadedFileInterface + * + * @param object $file File data from Psr\Http\Message\UploadedFileInterface + * @param bool $hasType Return with filetype + * @param bool $hasBasename Filename is calculated from location path + * @return array + */ + private function getPsr7FileInfo( + UploadedFileInterface $file, + bool $hasType = false, + bool $hasBasename = false + ) { + $fileInfo = []; + + $fileInfo['file'] = $file->getStream()->getMetadata('uri'); + $fileInfo['filename'] = $file->getClientFilename(); + + if ($hasBasename) { + $fileInfo['basename'] = basename($fileInfo['file']); + } + + if (! $hasType) { + $fileInfo['filetype'] = $file->getClientMediaType(); + } + + return $fileInfo; + } + + /** + * Generate file information array with base method + * + * @param string $file File path + * @param bool $hasType Return with filetype + * @param bool $hasBasename Filename is calculated from location path + * @return array + */ + private function getFileBasedFileInfo( + string $file, + bool $hasType = false, + bool $hasBasename = false + ) { + $fileInfo = []; + + $fileInfo['file'] = $file; + $fileInfo['filename'] = basename($fileInfo['file']); + + if ($hasBasename) { + $fileInfo['basename'] = basename($fileInfo['file']); + } + + if (! $hasType) { + $fileInfo['filetype'] = null; + } + + return $fileInfo; + } +} diff --git a/src/File/Hash.php b/src/File/Hash.php index f48c2c921..54a47c284 100644 --- a/src/File/Hash.php +++ b/src/File/Hash.php @@ -11,12 +11,15 @@ use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the hash of given files */ class Hash extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -129,34 +132,22 @@ public function addHash($options) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } $algos = array_unique(array_values($this->getHash())); $hashes = array_unique(array_keys($this->getHash())); + foreach ($algos as $algorithm) { - $filehash = hash_file($algorithm, $file); + $filehash = hash_file($algorithm, $fileInfo['file']); + if ($filehash === false) { $this->error(self::NOT_DETECTED); return false; diff --git a/src/File/ImageSize.php b/src/File/ImageSize.php index 47fe12914..8ea1dad3e 100644 --- a/src/File/ImageSize.php +++ b/src/File/ImageSize.php @@ -12,12 +12,15 @@ use Zend\Stdlib\ErrorHandler; use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the image size of an image file */ class ImageSize extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -332,32 +335,18 @@ public function setImageHeight($options) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_READABLE); return false; } ErrorHandler::start(); - $size = getimagesize($file); + $size = getimagesize($fileInfo['file']); ErrorHandler::stop(); if (empty($size) || ($size[0] === 0) || ($size[1] === 0)) { diff --git a/src/File/Md5.php b/src/File/Md5.php index c36b8a457..aa60ff3cd 100644 --- a/src/File/Md5.php +++ b/src/File/Md5.php @@ -9,13 +9,15 @@ namespace Zend\Validator\File; -use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the md5 hash of given files */ class Md5 extends Hash { + use FileInformationTrait; + /** * @const string Error constants */ @@ -85,32 +87,18 @@ public function addMd5($options) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } $hashes = array_unique(array_keys($this->getHash())); - $filehash = hash_file('md5', $file); + $filehash = hash_file('md5', $fileInfo['file']); if ($filehash === false) { $this->error(self::NOT_DETECTED); return false; diff --git a/src/File/MimeType.php b/src/File/MimeType.php index 3a9d42e6f..7ef3d6ede 100644 --- a/src/File/MimeType.php +++ b/src/File/MimeType.php @@ -14,12 +14,15 @@ use Zend\Stdlib\ErrorHandler; use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the mime type of a file */ class MimeType extends AbstractValidator { + use FileInformationTrait; + /**#@+ * @const Error type constants */ @@ -341,29 +344,12 @@ public function addMimeType($mimetype) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $filetype = $file['type']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name']) || ! isset($value['type'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - $filetype = $value['type']; - } else { - $file = $value; - $filename = basename($file); - $filetype = null; - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file, true); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(static::NOT_READABLE); return false; } @@ -384,13 +370,13 @@ public function isValid($value, $file = null) $this->type = null; if (! empty($this->finfo)) { - $this->type = finfo_file($this->finfo, $file); + $this->type = finfo_file($this->finfo, $fileInfo['file']); unset($this->finfo); } } if (empty($this->type) && $this->getHeaderCheck()) { - $this->type = $filetype; + $this->type = $fileInfo['filetype']; } if (empty($this->type)) { diff --git a/src/File/NotExists.php b/src/File/NotExists.php index 1128e6c6f..324400fb6 100644 --- a/src/File/NotExists.php +++ b/src/File/NotExists.php @@ -10,12 +10,15 @@ namespace Zend\Validator\File; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator which checks if the destination file does not exist */ class NotExists extends Exists { + use FileInformationTrait; + /** * @const string Error constants */ @@ -37,31 +40,15 @@ class NotExists extends Exists */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - $this->setValue($filename); - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = basename($file); - $this->setValue($value['name']); - } else { - $file = $value; - $filename = basename($file); - $this->setValue($filename); - } + $fileInfo = $this->getFileInfo($value, $file, false, true); + + $this->setValue($fileInfo['filename']); $check = false; $directories = $this->getDirectory(true); if (! isset($directories)) { $check = true; - if (file_exists($file)) { + if (file_exists($fileInfo['file'])) { $this->error(self::DOES_EXIST); return false; } @@ -72,7 +59,7 @@ public function isValid($value, $file = null) } $check = true; - if (file_exists($directory . DIRECTORY_SEPARATOR . $filename)) { + if (file_exists($directory . DIRECTORY_SEPARATOR . $fileInfo['basename'])) { $this->error(self::DOES_EXIST); return false; } diff --git a/src/File/Sha1.php b/src/File/Sha1.php index bc3929d1f..03eebc74f 100644 --- a/src/File/Sha1.php +++ b/src/File/Sha1.php @@ -9,13 +9,15 @@ namespace Zend\Validator\File; -use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the sha1 hash of given files */ class Sha1 extends Hash { + use FileInformationTrait; + /** * @const string Error constants */ @@ -85,32 +87,18 @@ public function addSha1($options) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } $hashes = array_unique(array_keys($this->getHash())); - $filehash = hash_file('sha1', $file); + $filehash = hash_file('sha1', $fileInfo['file']); if ($filehash === false) { $this->error(self::NOT_DETECTED); return false; diff --git a/src/File/Size.php b/src/File/Size.php index 45b90c01e..b45b13255 100644 --- a/src/File/Size.php +++ b/src/File/Size.php @@ -12,12 +12,15 @@ use Zend\Stdlib\ErrorHandler; use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for the maximum size of a file up to a max of 2GB */ class Size extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -234,33 +237,19 @@ protected function setSize($size) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } // limited to 4GB files ErrorHandler::start(); - $size = sprintf("%u", filesize($file)); + $size = sprintf("%u", filesize($fileInfo['file'])); ErrorHandler::stop(); $this->size = $size; diff --git a/src/File/WordCount.php b/src/File/WordCount.php index cbe9ce451..049e331a5 100644 --- a/src/File/WordCount.php +++ b/src/File/WordCount.php @@ -11,12 +11,15 @@ use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; +use Zend\Validator\File\FileInformationTrait; /** * Validator for counting all words in a file */ class WordCount extends AbstractValidator { + use FileInformationTrait; + /** * @const string Error constants */ @@ -175,31 +178,17 @@ public function setMax($max) */ public function isValid($value, $file = null) { - if (is_string($value) && is_array($file)) { - // Legacy Zend\Transfer API support - $filename = $file['name']; - $file = $file['tmp_name']; - } elseif (is_array($value)) { - if (! isset($value['tmp_name']) || ! isset($value['name'])) { - throw new Exception\InvalidArgumentException( - 'Value array must be in $_FILES format' - ); - } - $file = $value['tmp_name']; - $filename = $value['name']; - } else { - $file = $value; - $filename = basename($file); - } - $this->setValue($filename); + $fileInfo = $this->getFileInfo($value, $file); + + $this->setValue($fileInfo['filename']); // Is file readable ? - if (empty($file) || false === is_readable($file)) { + if (empty($fileInfo['file']) || false === is_readable($fileInfo['file'])) { $this->error(self::NOT_FOUND); return false; } - $content = file_get_contents($file); + $content = file_get_contents($fileInfo['file']); $this->count = str_word_count($content); if (($this->getMax() !== null) && ($this->count > $this->getMax())) { $this->error(self::TOO_MUCH); From 8e0ff20a9143cfece32e4586d5bf7e0da30d4650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Andr=C3=A1s=20Horv=C3=A1th?= Date: Wed, 23 Jan 2019 11:38:10 +0100 Subject: [PATCH 2/6] Remove typehints for PHP 5.6 Fatal error: Default value for parameters with a class type hint can only be NULL --- src/File/FileInformationTrait.php | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/File/FileInformationTrait.php b/src/File/FileInformationTrait.php index a7454e611..8ec1b39ce 100644 --- a/src/File/FileInformationTrait.php +++ b/src/File/FileInformationTrait.php @@ -24,8 +24,8 @@ trait FileInformationTrait protected function getFileInfo( $value, $file = null, - bool $hasType = false, - bool $hasBasename = false + $hasType = false, + $hasBasename = false ) { if (is_string($value) && is_array($file)) { return $this->getLegacyFileInfo($file, $hasType, $hasBasename); @@ -52,8 +52,8 @@ protected function getFileInfo( */ private function getLegacyFileInfo( $file, - bool $hasType = false, - bool $hasBasename = false + $hasType = false, + $hasBasename = false ) { $fileInfo = []; @@ -80,9 +80,9 @@ private function getLegacyFileInfo( * @return array */ private function getSapiFileInfo( - array $file, - bool $hasType = false, - bool $hasBasename = false + $file, + $hasType = false, + $hasBasename = false ) { if (! isset($file['tmp_name']) || ! isset($file['name'])) { throw new Exception\InvalidArgumentException( @@ -115,9 +115,9 @@ private function getSapiFileInfo( * @return array */ private function getPsr7FileInfo( - UploadedFileInterface $file, - bool $hasType = false, - bool $hasBasename = false + $file, + $hasType = false, + $hasBasename = false ) { $fileInfo = []; @@ -144,9 +144,9 @@ private function getPsr7FileInfo( * @return array */ private function getFileBasedFileInfo( - string $file, - bool $hasType = false, - bool $hasBasename = false + $file, + $hasType = false, + $hasBasename = false ) { $fileInfo = []; From e6e9d08bd801daa7f3a547c41410279328f0ff6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20Andr=C3=A1s=20Horv=C3=A1th?= Date: Fri, 25 Jan 2019 00:37:43 +0100 Subject: [PATCH 3/6] Add tests for FileInformationTrait --- src/File/FileInformationTrait.php | 8 +- test/File/FileInformationTraitTest.php | 286 ++++++++++++++++++++++++ test/File/TestAsset/FileInformation.php | 36 +++ 3 files changed, 326 insertions(+), 4 deletions(-) create mode 100644 test/File/FileInformationTraitTest.php create mode 100644 test/File/TestAsset/FileInformation.php diff --git a/src/File/FileInformationTrait.php b/src/File/FileInformationTrait.php index 8ec1b39ce..bba8cbc45 100644 --- a/src/File/FileInformationTrait.php +++ b/src/File/FileInformationTrait.php @@ -64,7 +64,7 @@ private function getLegacyFileInfo( $fileInfo['basename'] = basename($fileInfo['file']); } - if (! $hasType) { + if ($hasType) { $fileInfo['filetype'] = $file['type']; } @@ -99,7 +99,7 @@ private function getSapiFileInfo( $fileInfo['basename'] = basename($fileInfo['file']); } - if (! $hasType) { + if ($hasType) { $fileInfo['filetype'] = $file['type']; } @@ -128,7 +128,7 @@ private function getPsr7FileInfo( $fileInfo['basename'] = basename($fileInfo['file']); } - if (! $hasType) { + if ($hasType) { $fileInfo['filetype'] = $file->getClientMediaType(); } @@ -157,7 +157,7 @@ private function getFileBasedFileInfo( $fileInfo['basename'] = basename($fileInfo['file']); } - if (! $hasType) { + if ($hasType) { $fileInfo['filetype'] = null; } diff --git a/test/File/FileInformationTraitTest.php b/test/File/FileInformationTraitTest.php new file mode 100644 index 000000000..4b060d0d3 --- /dev/null +++ b/test/File/FileInformationTraitTest.php @@ -0,0 +1,286 @@ +stream = $this->prophesize(StreamInterface::class); + $this->upload = $this->prophesize(UploadedFileInterface::class); + } + + public function testLegacyFileInfoBasic() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $basename = basename($testFile); + $file = [ + 'name' => $basename, + 'tmp_name' => $testFile + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $basename, + $file + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + ]); + } + + public function testLegacyFileInfoWithFiletype() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $basename = basename($testFile); + $file = [ + 'name' => $basename, + 'tmp_name' => $testFile, + 'type' => 'mo', + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $basename, + $file, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + 'filetype' => $file['type'], + ]); + } + + public function testLegacyFileInfoWithBasename() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $basename = basename($testFile); + $file = [ + 'name' => $basename, + 'tmp_name' => $testFile, + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $basename, + $file, + false, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + 'basename' => basename($file['tmp_name']), + ]); + } + + public function testSapiFileInfoBasic() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $file = [ + 'name' => basename($testFile), + 'tmp_name' => $testFile + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $file + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + ]); + } + + public function testSapiFileInfoWithFiletype() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $file = [ + 'name' => basename($testFile), + 'tmp_name' => $testFile, + 'type' => 'mo', + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $file, + null, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + 'filetype' => $file['type'], + ]); + } + + public function testSapiFileInfoWithBasename() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + $file = [ + 'name' => basename($testFile), + 'tmp_name' => $testFile, + ]; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $file, + null, + false, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => $file['name'], + 'file' => $file['tmp_name'], + 'basename' => basename($file['tmp_name']), + ]); + } + + public function testPsr7FileInfoBasic() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $this->stream->getMetadata('uri')->willReturn($testFile); + $this->upload->getClientFilename()->willReturn(basename($testFile)); + $this->upload->getClientMediaType()->willReturn(mime_content_type($testFile)); + $this->upload->getStream()->willReturn($this->stream->reveal()); + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $this->upload->reveal() + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + ]); + } + + public function testPsr7FileInfoBasicWithFiletype() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $this->stream->getMetadata('uri')->willReturn($testFile); + $this->upload->getClientFilename()->willReturn(basename($testFile)); + $this->upload->getClientMediaType()->willReturn(mime_content_type($testFile)); + $this->upload->getStream()->willReturn($this->stream->reveal()); + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $this->upload->reveal(), + null, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + 'filetype' => mime_content_type($testFile), + ]); + } + + public function testPsr7FileInfoBasicWithBasename() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $this->stream->getMetadata('uri')->willReturn($testFile); + $this->upload->getClientFilename()->willReturn(basename($testFile)); + $this->upload->getClientMediaType()->willReturn(mime_content_type($testFile)); + $this->upload->getStream()->willReturn($this->stream->reveal()); + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $this->upload->reveal(), + null, + false, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + 'basename' => basename($testFile), + ]); + } + + public function testFileBasedFileInfoBasic() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $testFile + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + ]); + } + + public function testFileBasedFileInfoBasicWithFiletype() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $testFile, + null, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + 'filetype' => null + ]); + } + + public function testFileBasedFileInfoBasicWithBasename() + { + $testFile = __DIR__ . '/_files/testsize.mo'; + + $fileInformation = new FileInformation(); + $fileInfo = $fileInformation->checkFileInformation( + $testFile, + null, + false, + true + ); + + $this->assertEquals($fileInfo, [ + 'filename' => basename($testFile), + 'file' => $testFile, + 'basename' => basename($testFile) + ]); + } +} diff --git a/test/File/TestAsset/FileInformation.php b/test/File/TestAsset/FileInformation.php new file mode 100644 index 000000000..24bcb5230 --- /dev/null +++ b/test/File/TestAsset/FileInformation.php @@ -0,0 +1,36 @@ +getFileInfo($value, $file, $hasType, $hasBasename); + } +} From b7113443cad7618915ce15e01589e5e88fef7b09 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 29 Jan 2019 16:38:57 -0600 Subject: [PATCH 4/6] Adds CHANGELOG entry for #251 --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2561e13eb..cb2cdb882 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,9 @@ All notable changes to this project will be documented in this file, in reverse ### Changed -- Nothing. +- [#251](https://github.com/zendframework/zend-validator/pull/251) updates the logic of each of the various `Zend\Validator\File` validators + to allow validating against PSR-7 `UploadedFileInterface` instances, expanding + the support originally provided in version 2.11.0. ### Deprecated @@ -20,7 +22,6 @@ All notable changes to this project will be documented in this file, in reverse - [#250](https://github.com/zendframework/zend-validator/pull/250) removes support for zend-stdlib v2 releases. - ### Fixed - Nothing. From 8108e63696ea28765e62fb0ebb747a337f20e5ba Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 29 Jan 2019 16:48:01 -0600 Subject: [PATCH 5/6] qa: use better typehints in FileInformationTrait Per comments from @webimpress --- src/File/FileInformationTrait.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/File/FileInformationTrait.php b/src/File/FileInformationTrait.php index bba8cbc45..7985f0eab 100644 --- a/src/File/FileInformationTrait.php +++ b/src/File/FileInformationTrait.php @@ -16,14 +16,14 @@ trait FileInformationTrait * Returns array if the procedure is identified * * @param string|array|object $value Filename to check - * @param array $file File data from \Zend\File\Transfer\Transfer (optional) + * @param null|array $file File data (when using legacy Zend_File_Transfer API) * @param bool $hasType Return with filetype (optional) * @param bool $basename Return with basename - is calculated from location path (optional) * @return array */ protected function getFileInfo( $value, - $file = null, + array $file = null, $hasType = false, $hasBasename = false ) { @@ -43,15 +43,15 @@ protected function getFileInfo( } /** - * Generate file information array with Legacy Zend\Transfer API + * Generate file information array with legacy Zend_File_Transfer API * - * @param object $file File data from \Zend\File\Transfer\Transfer + * @param array $file File data * @param bool $hasType Return with filetype * @param bool $hasBasename Basename is calculated from location path * @return array */ private function getLegacyFileInfo( - $file, + array $file, $hasType = false, $hasBasename = false ) { @@ -72,15 +72,15 @@ private function getLegacyFileInfo( } /** - * Generate file information array with Sapi + * Generate file information array with SAPI * - * @param array $file File data from Sapi + * @param array $file File data from SAPI * @param bool $hasType Return with filetype * @param bool $hasBasename Filename is calculated from location path * @return array */ private function getSapiFileInfo( - $file, + array $file, $hasType = false, $hasBasename = false ) { @@ -109,13 +109,13 @@ private function getSapiFileInfo( /** * Generate file information array with PSR-7 UploadedFileInterface * - * @param object $file File data from Psr\Http\Message\UploadedFileInterface - * @param bool $hasType Return with filetype - * @param bool $hasBasename Filename is calculated from location path + * @param UploadedFileInterface $file + * @param bool $hasType Return with filetype + * @param bool $hasBasename Filename is calculated from location path * @return array */ private function getPsr7FileInfo( - $file, + UploadedFileInterface $file, $hasType = false, $hasBasename = false ) { From 8d9eb432cdb3a257ec527229323c39693749b659 Mon Sep 17 00:00:00 2001 From: Matthew Weier O'Phinney Date: Tue, 29 Jan 2019 16:50:15 -0600 Subject: [PATCH 6/6] qa: incorporate review feedback for FileInformationTraitTest Incorporates all feedback from @webimpress --- test/File/FileInformationTraitTest.php | 5 +---- test/File/TestAsset/FileInformation.php | 4 ++-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/File/FileInformationTraitTest.php b/test/File/FileInformationTraitTest.php index 4b060d0d3..9c63dd5bd 100644 --- a/test/File/FileInformationTraitTest.php +++ b/test/File/FileInformationTraitTest.php @@ -14,12 +14,9 @@ use ZendTest\Validator\File\TestAsset\FileInformation; use Zend\Validator\Exception\InvalidArgumentException; -/** - * @group Zend_Validator - */ class FileInformationTraitTest extends TestCase { - /** @var ObjectProphecy */ + /** @var ObjectProphecy|StreamInterface */ public $stream; /** @var ObjectProphecy */ diff --git a/test/File/TestAsset/FileInformation.php b/test/File/TestAsset/FileInformation.php index 24bcb5230..0a3e6fdb2 100644 --- a/test/File/TestAsset/FileInformation.php +++ b/test/File/TestAsset/FileInformation.php @@ -20,14 +20,14 @@ class FileInformation * Returns array if the procedure is identified * * @param string|array|object $value Filename to check - * @param array $file File data from \Zend\File\Transfer\Transfer (optional) + * @param null|array $file File data (when using legacy Zend_File_Transfer API) * @param bool $hasType Return with filetype (optional) * @param bool $basename Return with basename - is calculated from location path (optional) * @return array */ public function checkFileInformation( $value, - $file = null, + array $file = null, $hasType = false, $hasBasename = false ) {