123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- <?php
- namespace PhpZip\Util;
- use PhpZip\Util\Iterator\IgnoreFilesFilterIterator;
- use PhpZip\Util\Iterator\IgnoreFilesRecursiveFilterIterator;
- /**
- * Files util.
- *
- * @author Ne-Lexa alexey@nelexa.ru
- * @license MIT
- *
- * @internal
- */
- final class FilesUtil
- {
- /**
- * Is empty directory.
- *
- * @param string $dir Directory
- *
- * @return bool
- */
- public static function isEmptyDir($dir)
- {
- if (!is_readable($dir)) {
- return false;
- }
- return \count(scandir($dir)) === 2;
- }
- /**
- * Remove recursive directory.
- *
- * @param string $dir directory path
- */
- public static function removeDir($dir)
- {
- $files = new \RecursiveIteratorIterator(
- new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS),
- \RecursiveIteratorIterator::CHILD_FIRST
- );
- /** @var \SplFileInfo $fileInfo */
- foreach ($files as $fileInfo) {
- $function = ($fileInfo->isDir() ? 'rmdir' : 'unlink');
- $function($fileInfo->getPathname());
- }
- @rmdir($dir);
- }
- /**
- * Convert glob pattern to regex pattern.
- *
- * @param string $globPattern
- *
- * @return string
- */
- public static function convertGlobToRegEx($globPattern)
- {
- // Remove beginning and ending * globs because they're useless
- $globPattern = trim($globPattern, '*');
- $escaping = false;
- $inCurrent = 0;
- $chars = str_split($globPattern);
- $regexPattern = '';
- foreach ($chars as $currentChar) {
- switch ($currentChar) {
- case '*':
- $regexPattern .= ($escaping ? '\\*' : '.*');
- $escaping = false;
- break;
- case '?':
- $regexPattern .= ($escaping ? '\\?' : '.');
- $escaping = false;
- break;
- case '.':
- case '(':
- case ')':
- case '+':
- case '|':
- case '^':
- case '$':
- case '@':
- case '%':
- $regexPattern .= '\\' . $currentChar;
- $escaping = false;
- break;
- case '\\':
- if ($escaping) {
- $regexPattern .= '\\\\';
- $escaping = false;
- } else {
- $escaping = true;
- }
- break;
- case '{':
- if ($escaping) {
- $regexPattern .= '\\{';
- } else {
- $regexPattern = '(';
- $inCurrent++;
- }
- $escaping = false;
- break;
- case '}':
- if ($inCurrent > 0 && !$escaping) {
- $regexPattern .= ')';
- $inCurrent--;
- } elseif ($escaping) {
- $regexPattern = '\\}';
- } else {
- $regexPattern = '}';
- }
- $escaping = false;
- break;
- case ',':
- if ($inCurrent > 0 && !$escaping) {
- $regexPattern .= '|';
- } elseif ($escaping) {
- $regexPattern .= '\\,';
- } else {
- $regexPattern = ',';
- }
- break;
- default:
- $escaping = false;
- $regexPattern .= $currentChar;
- }
- }
- return $regexPattern;
- }
- /**
- * Search files.
- *
- * @param string $inputDir
- * @param bool $recursive
- * @param array $ignoreFiles
- *
- * @return array Searched file list
- */
- public static function fileSearchWithIgnore($inputDir, $recursive = true, array $ignoreFiles = [])
- {
- if ($recursive) {
- $directoryIterator = new \RecursiveDirectoryIterator($inputDir);
- if (!empty($ignoreFiles)) {
- $directoryIterator = new IgnoreFilesRecursiveFilterIterator($directoryIterator, $ignoreFiles);
- }
- $iterator = new \RecursiveIteratorIterator($directoryIterator);
- } else {
- $directoryIterator = new \DirectoryIterator($inputDir);
- if (!empty($ignoreFiles)) {
- $directoryIterator = new IgnoreFilesFilterIterator($directoryIterator, $ignoreFiles);
- }
- $iterator = new \IteratorIterator($directoryIterator);
- }
- $fileList = [];
- foreach ($iterator as $file) {
- if ($file instanceof \SplFileInfo) {
- $fileList[] = $file->getPathname();
- }
- }
- return $fileList;
- }
- /**
- * Search files from glob pattern.
- *
- * @param string $globPattern
- * @param int $flags
- * @param bool $recursive
- *
- * @return array Searched file list
- */
- public static function globFileSearch($globPattern, $flags = 0, $recursive = true)
- {
- $flags = (int) $flags;
- $recursive = (bool) $recursive;
- $files = glob($globPattern, $flags);
- if (!$recursive) {
- return $files;
- }
- foreach (glob(\dirname($globPattern) . \DIRECTORY_SEPARATOR . '*', \GLOB_ONLYDIR | \GLOB_NOSORT) as $dir) {
- // Unpacking the argument via ... is supported starting from php 5.6 only
- /** @noinspection SlowArrayOperationsInLoopInspection */
- $files = array_merge($files, self::globFileSearch($dir . \DIRECTORY_SEPARATOR . basename($globPattern), $flags, $recursive));
- }
- return $files;
- }
- /**
- * Search files from regex pattern.
- *
- * @param string $folder
- * @param string $pattern
- * @param bool $recursive
- *
- * @return array Searched file list
- */
- public static function regexFileSearch($folder, $pattern, $recursive = true)
- {
- if ($recursive) {
- $directoryIterator = new \RecursiveDirectoryIterator($folder);
- $iterator = new \RecursiveIteratorIterator($directoryIterator);
- } else {
- $directoryIterator = new \DirectoryIterator($folder);
- $iterator = new \IteratorIterator($directoryIterator);
- }
- $regexIterator = new \RegexIterator($iterator, $pattern, \RegexIterator::MATCH);
- $fileList = [];
- foreach ($regexIterator as $file) {
- if ($file instanceof \SplFileInfo) {
- $fileList[] = $file->getPathname();
- }
- }
- return $fileList;
- }
- /**
- * Convert bytes to human size.
- *
- * @param int $size Size bytes
- * @param string|null $unit Unit support 'GB', 'MB', 'KB'
- *
- * @return string
- */
- public static function humanSize($size, $unit = null)
- {
- if (($unit === null && $size >= 1 << 30) || $unit === 'GB') {
- return number_format($size / (1 << 30), 2) . 'GB';
- }
- if (($unit === null && $size >= 1 << 20) || $unit === 'MB') {
- return number_format($size / (1 << 20), 2) . 'MB';
- }
- if (($unit === null && $size >= 1 << 10) || $unit === 'KB') {
- return number_format($size / (1 << 10), 2) . 'KB';
- }
- return number_format($size) . ' bytes';
- }
- /**
- * Normalizes zip path.
- *
- * @param string $path Zip path
- *
- * @return string
- */
- public static function normalizeZipPath($path)
- {
- return implode(
- \DIRECTORY_SEPARATOR,
- array_filter(
- explode('/', (string) $path),
- static function ($part) {
- return $part !== '.' && $part !== '..';
- }
- )
- );
- }
- /**
- * Returns whether the file path is an absolute path.
- *
- * @param string $file A file path
- *
- * @return bool
- *
- * @see source symfony filesystem component
- */
- public static function isAbsolutePath($file)
- {
- return strspn($file, '/\\', 0, 1)
- || (
- \strlen($file) > 3 && ctype_alpha($file[0])
- && $file[1] === ':'
- && strspn($file, '/\\', 2, 1)
- )
- || parse_url($file, \PHP_URL_SCHEME) !== null;
- }
- /**
- * @param string $target
- * @param string $path
- * @param bool $allowSymlink
- *
- * @return bool
- */
- public static function symlink($target, $path, $allowSymlink)
- {
- if (\DIRECTORY_SEPARATOR === '\\' || !$allowSymlink) {
- return file_put_contents($path, $target) !== false;
- }
- return symlink($target, $path);
- }
- /**
- * @param string $file
- *
- * @return bool
- */
- public static function isBadCompressionFile($file)
- {
- $badCompressFileExt = [
- 'dic',
- 'dng',
- 'f4v',
- 'flipchart',
- 'h264',
- 'lrf',
- 'mobi',
- 'mts',
- 'nef',
- 'pspimage',
- ];
- $ext = strtolower(pathinfo($file, \PATHINFO_EXTENSION));
- if (\in_array($ext, $badCompressFileExt, true)) {
- return true;
- }
- $mimeType = self::getMimeTypeFromFile($file);
- return self::isBadCompressionMimeType($mimeType);
- }
- /**
- * @param string $mimeType
- *
- * @return bool
- */
- public static function isBadCompressionMimeType($mimeType)
- {
- static $badDeflateCompMimeTypes = [
- 'application/epub+zip',
- 'application/gzip',
- 'application/vnd.debian.binary-package',
- 'application/vnd.oasis.opendocument.graphics',
- 'application/vnd.oasis.opendocument.presentation',
- 'application/vnd.oasis.opendocument.text',
- 'application/vnd.oasis.opendocument.text-master',
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
- 'application/vnd.rn-realmedia',
- 'application/x-7z-compressed',
- 'application/x-arj',
- 'application/x-bzip2',
- 'application/x-hwp',
- 'application/x-lzip',
- 'application/x-lzma',
- 'application/x-ms-reader',
- 'application/x-rar',
- 'application/x-rpm',
- 'application/x-stuffit',
- 'application/x-tar',
- 'application/x-xz',
- 'application/zip',
- 'application/zlib',
- 'audio/flac',
- 'audio/mpeg',
- 'audio/ogg',
- 'audio/vnd.dolby.dd-raw',
- 'audio/webm',
- 'audio/x-ape',
- 'audio/x-hx-aac-adts',
- 'audio/x-m4a',
- 'audio/x-m4a',
- 'audio/x-wav',
- 'image/gif',
- 'image/heic',
- 'image/jp2',
- 'image/jpeg',
- 'image/png',
- 'image/vnd.djvu',
- 'image/webp',
- 'image/x-canon-cr2',
- 'video/ogg',
- 'video/webm',
- 'video/x-matroska',
- 'video/x-ms-asf',
- 'x-epoc/x-sisx-app',
- ];
- if (\in_array($mimeType, $badDeflateCompMimeTypes, true)) {
- return true;
- }
- return false;
- }
- /**
- * @param string $file
- *
- * @return string
- *
- * @noinspection PhpComposerExtensionStubsInspection
- */
- public static function getMimeTypeFromFile($file)
- {
- if (\function_exists('mime_content_type')) {
- return mime_content_type($file);
- }
- return 'application/octet-stream';
- }
- /**
- * @param string $contents
- *
- * @return string
- * @noinspection PhpComposerExtensionStubsInspection
- */
- public static function getMimeTypeFromString($contents)
- {
- $contents = (string) $contents;
- $finfo = new \finfo(\FILEINFO_MIME);
- $mimeType = $finfo->buffer($contents);
- if ($mimeType === false) {
- $mimeType = 'application/octet-stream';
- }
- return explode(';', $mimeType)[0];
- }
- }
|