classes/yf_dir.class.php
<?php
/**
* Filesystem utils.
*
* Benchmark results of the methods, from SLOW to FASTEST:
* 1) _class("dir")->scan() | time: 0.46 | mem: 175824 | peakmem: 4467496 | found: 8
* 2) _class("dir")->riterate() | time: 0.306 | mem: 2288 | peakmem: 4489568 | found: 8
* 3) _class("dir")->scan_fast() | time: 0.176 | mem: 2352 | peakmem: 4489568 | found: 8
* 4) _class("dir")->rglob() | time: 0.066 | mem: 2256 | peakmem: 4489568 | found: 8
* 5) _class("dir")->find() | time: 0.058 | mem: 2232 | peakmem: 4489568 | found: 8 = fastest so far
*
* @author YFix Team <yfix.dev@gmail.com>
* @version 1.0
*/
class yf_dir
{
/** @var bool */
public $CHECK_IF_READABLE = true;
/** @var bool */
public $CHECK_IF_WRITABLE = true;
/**
* Catch missing method call.
* @param mixed $name
* @param mixed $args
*/
public function __call($name, $args)
{
return main()->extend_call($this, $name, $args);
}
/**
* Scan dir using shell find = so far, fastest method.
* @param mixed $folder
* @param mixed $pattern
*/
public function find($folder, $pattern = '*')
{
return explode("\n", trim(shell_exec('find -L ' . escapeshellarg($folder) . ' -iname ' . escapeshellarg($pattern))));
}
/**
* Compatible function, supporting PHP7+, because:
* http://php.net/sql_regcase !Warning! This function has been DEPRECATED as of PHP 5.3.0. Relying on this feature is highly discouraged.
* @param mixed $str
*/
public function _sql_regcase($str)
{
if (function_exists('sql_regcase')) {
return sql_regcase($str);
}
$res = '';
$chars = str_split($str);
foreach ($chars as $char) {
if (preg_match('/[A-Za-z]/', $char)) {
$res .= '[' . mb_strtoupper($char, 'UTF-8') . mb_strtolower($char, 'UTF-8') . ']';
} else {
$res .= $char;
}
}
return $res;
}
/**
* Recursive glob(). Note that glob and rglob does not search hidden files (starting from dot on linux/unix).
* @param mixed $folder
* @param mixed $pattern
*/
public function rglob($folder, $pattern = '*')
{
$folder = rtrim($folder, '/');
if (false === strpos($pattern, '[')) {
$pattern = $this->_sql_regcase($pattern);
}
$files = (array) glob($folder . '/' . $pattern, GLOB_BRACE | GLOB_NOSORT);
$dirs = (array) glob($folder . '/*', GLOB_BRACE | GLOB_ONLYDIR | GLOB_NOSORT);
// Dotted dirs
foreach (glob($folder . '/.**', GLOB_BRACE | GLOB_ONLYDIR | GLOB_NOSORT) as $path) {
$d = basename($path);
if ($d === '.' || $d === '..' || $d === '.git' || $d === '.svn') {
continue;
}
$dirs[] = $path;
}
$func = __FUNCTION__;
foreach ((array) $dirs as $dir) {
$files = array_merge($files, $this->$func($dir, $pattern));
}
return $files;
}
/**
* Fast implementation with old functions opendir/readdir.
* @param mixed $start_dir
* @param mixed $pattern
*/
public function scan_fast($start_dir, $pattern = '~.+~')
{
$files = [];
$dh = @opendir($start_dir);
if ( ! $dh) {
return $files;
}
$func = __FUNCTION__;
while (false !== ($f = readdir($dh))) {
if ($f === '.' || $f === '..') {
continue;
}
$item = $start_dir . '/' . $f;
if (is_dir($item)) {
$files = array_merge($files, $this->$func($item, $pattern));
} elseif (is_file($item) && ( ! $pattern || preg_match($pattern, $item))) {
$files[] = $item;
}
}
closedir($dh);
return $files;
}
/**
* Recursive folder search, based on RecursiveDirectoryIterator.
* @param mixed $folder
* @param mixed $pattern
*/
public function riterate($folder, $pattern = '~.+~')
{
$out = [];
$flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::FOLLOW_SYMLINKS;
foreach (new RegexIterator(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder, $flags)), $pattern, RegexIterator::GET_MATCH) as $path => $f) {
$out[] = $path;
}
return $out;
}
/**
* Alias.
* @param mixed $start_dir
* @param mixed $_tmp
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function scan($start_dir, $_tmp = true, $pattern_include = '', $pattern_exclude = '')
{
return $this->scan_dir($start_dir, $_tmp, $pattern_include, $pattern_exclude);
}
/**
* Recursively scanning directory structure (including subdirectories) //.
* @param mixed $start_dir
* @param mixed $_tmp
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function scan_dir($start_dir, $_tmp = 1, $pattern_include = '', $pattern_exclude = '')
{
$func = __FUNCTION__;
// Here we accept several start folders, result will be merged
if (is_array($start_dir)) {
foreach ((array) $start_dir as $_dir_name) {
foreach ((array) $this->$func($_dir_name, 1, $pattern_include, $pattern_exclude) as $_file_path) {
$_files[] = $_file_path;
}
}
return $_files;
}
if ( ! $start_dir || ! file_exists($start_dir)) {
return false;
}
$start_dir = rtrim($start_dir, '/');
$files = [];
$dh = opendir($start_dir);
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..') {
continue;
}
$item = $start_dir . '/' . $f;
$_is_dir = is_dir($item);
if ($this->_skip_by_pattern($item, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
if ($_is_dir) {
$files = array_merge($files, $this->$func($item, 1, $pattern_include, $pattern_exclude));
} elseif (is_file($item)) {
$files[] = $item;
}
}
closedir($dh);
return $files;
}
/**
* Alias.
* @param mixed $start_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function size($start_dir, $pattern_include = '', $pattern_exclude = '')
{
return $this->dirsize($start_dir, $pattern_include, $pattern_exclude);
}
/**
* This function calculate directory size.
* @param mixed $start_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function dirsize($start_dir, $pattern_include = '', $pattern_exclude = '')
{
if ( ! $start_dir || ! file_exists($start_dir)) {
return false;
}
$start_dir = rtrim($start_dir, '/');
$dh = opendir($start_dir);
$size = 0;
while (($f = readdir($dh)) !== false) {
if ($f == '.' || $f == '..') {
continue;
}
$path = $start_dir . '/' . $f;
$_is_dir = is_dir($path);
// Check patterns
if ($this->_skip_by_pattern($path, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
if ($_is_dir) {
$size += $this->dirsize($path . '/', $pattern_include, $pattern_exclude);
} elseif (is_file($path)) {
$size += filesize($path);
}
}
closedir($dh);
return $size;
}
/**
* This function calculate number of files by mask inside given directory.
* @param mixed $start_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function count_files($start_dir, $pattern_include = '', $pattern_exclude = '')
{
if ( ! $start_dir || ! file_exists($start_dir)) {
return false;
}
$start_dir = rtrim($start_dir, '/');
$dh = opendir($start_dir);
$num_files = 0;
while (($f = readdir($dh)) !== false) {
if ($f == '.' || $f == '..') {
continue;
}
$path = $start_dir . '/' . $f;
$_is_dir = is_dir($path);
// Check patterns
if ($this->_skip_by_pattern($path, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
if ($_is_dir) {
$num_files += $this->count_files($path . '/', $pattern_include, $pattern_exclude);
} elseif (is_file($path)) {
$num_files++;
}
}
closedir($dh);
return $num_files;
}
/**
* Alias.
* @param mixed $path1
* @param mixed $path2
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param null|mixed $level
*/
public function copy($path1, $path2, $pattern_include = '', $pattern_exclude = '', $level = null)
{
return $this->copy_dir($path1, $path2, $pattern_include, $pattern_exclude, $level);
}
/**
* This function recursively copies contents of source directory to destination.
* @param mixed $path1
* @param mixed $path2
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param null|mixed $level
*/
public function copy_dir($path1, $path2, $pattern_include = '', $pattern_exclude = '', $level = null)
{
if ( ! $path1 || ! file_exists($path1)) {
return false;
}
$func = __FUNCTION__;
$path1 = rtrim(str_replace('\\', '/', realpath($path1)), '/');
$path2 = rtrim(str_replace('\\', '/', realpath($path2)), '/');
$dh = opendir($path1);
$old_mask = umask(0);
if ( ! file_exists($path2)) {
$this->mkdir_m($path2);
}
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..') {
continue;
}
$item_1 = $path1 . '/' . $f;
$item_2 = $path2 . '/' . $f;
$_is_dir = is_dir($item_1);
// Check patterns
if ($this->_skip_by_pattern($item_1, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
if ($_is_dir) {
if ( ! file_exists($item_2)) {
$this->mkdir_m($item_2);
}
if ($level === null || $level > 0) {
$this->$func($item_1, $item_2, $pattern_include, $pattern_exclude, $level === null ? $level : $level - 1);
}
} else {
$this->_copy_file($item_1, $item_2);
}
}
umask($old_mask);
}
/**
* Alias.
* @param mixed $path1
* @param mixed $path2
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function move($path1, $path2, $pattern_include = '', $pattern_exclude = '')
{
return $this->move_dir($path1, $path2, $pattern_include, $pattern_exclude);
}
/**
* This function recursively move contents of source directory to destination.
* @param mixed $path1
* @param mixed $path2
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function move_dir($path1, $path2, $pattern_include = '', $pattern_exclude = '')
{
if ( ! $path1 || ! file_exists($path1)) {
return false;
}
$func = __FUNCTION__;
$path1 = rtrim($path1, '/');
$path2 = rtrim($path2, '/');
$dh = opendir($path1);
if ( ! file_exists($path2)) {
mkdir($path2, 0777);
}
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..') {
continue;
}
$item_1 = $path1 . '/' . $f;
$item_2 = $path2 . '/' . $f;
$_is_dir = is_dir($item_1);
// Check patterns
if ($this->_skip_by_pattern($item_1, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
if ($_is_dir) {
if ( ! file_exists($item_2)) {
mkdir($item_2, 0777);
}
$this->$func($item_1, $item_2, $pattern_include, $pattern_exclude);
} else {
$this->_copy_file($item_1, $item_2);
unlink($item_1);
}
}
rmdir($path1);
}
/**
* Try to copy file.
* @param mixed $path_from
* @param mixed $path_to
*/
public function _copy_file($path_from = '', $path_to = '')
{
if ( ! $path_from || ! $path_to) {
return false;
}
$result = false;
if ( ! file_exists($path_from)) {
return false;
}
// Quick way
$result = copy($path_from, $path_to);
if ( ! $result) {
$result = (bool) file_put_contents($path_to, file_get_contents($path_from));
}
return $result;
}
/**
* Alias.
* @param mixed $start_dir
* @param mixed $delete_start_dir
*/
public function delete($start_dir, $delete_start_dir = false)
{
return $this->delete_dir($start_dir, $delete_start_dir);
}
/**
* Recursively delete directory structure (including subdirectories).
* @param mixed $start_dir
* @param mixed $delete_start_dir
*/
public function delete_dir($start_dir, $delete_start_dir = false)
{
if ( ! $start_dir || ! file_exists($start_dir)) {
return false;
}
$func = __FUNCTION__;
$start_dir = rtrim($start_dir, '/');
// Process folder contents
$dh = opendir($start_dir);
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..') {
continue;
}
$item = str_replace('//', '/', $start_dir . '/' . $f);
chmod($item, 0777);
// Delete files immediatelly
if (is_file($item)) {
unlink($item);
// Store folders to delete in stack and try to delete sub items
} elseif (is_dir($item)) {
$this->$func($item);
$sub_dirs_list[] = $item;
}
}
closedir($dh);
// Now try to delete sub folders
foreach ((array) $sub_dirs_list as $dir_name) {
rmdir($dir_name);
}
// Do delete start dir if needed
if ($delete_start_dir) {
rmdir($start_dir);
}
}
/**
* Delete files in specified dir recursively using patterns.
* @param mixed $start_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function delete_files($start_dir, $pattern_include = '', $pattern_exclude = '')
{
foreach ((array) $this->scan_dir($start_dir, 1, $pattern_include, $pattern_exclude) as $file_path) {
unlink($file_path);
}
}
/**
* Alias.
* @param mixed $start_dir
* @param mixed $new_mode
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function chmod($start_dir, $new_mode = 0755, $pattern_include = '', $pattern_exclude = '')
{
return $this->chmod_dir($start_dir, $new_mode, $pattern_include, $pattern_exclude);
}
/**
* Recursively chmod directory structure (including subdirectories).
* @param mixed $start_dir
* @param mixed $new_mode
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function chmod_dir($start_dir, $new_mode = 0755, $pattern_include = '', $pattern_exclude = '')
{
if ( ! $start_dir || ! file_exists($start_dir) || empty($new_mode)) {
return false;
}
$func = __FUNCTION__;
$start_dir = rtrim($start_dir, '/');
$dh = opendir($start_dir);
while (false !== ($f = readdir($dh))) {
if ($f == '.' || $f == '..') {
continue;
}
$item = $start_dir . '/' . $f;
$_is_dir = is_dir($item);
// Check patterns
if ($this->_skip_by_pattern($item, $_is_dir, $pattern_include, $pattern_exclude)) {
continue;
}
chmod($item, $new_mode);
if ($_is_dir) {
$this->$func($item, $new_mode);
}
}
}
/**
* Alias.
* @param mixed $dir_name
* @param mixed $dir_mode
* @param mixed $create_index_htmls
* @param mixed $start_folder
*/
public function mkdir($dir_name, $dir_mode = 0755, $create_index_htmls = 0, $start_folder = '')
{
return $this->mkdir_m($dir_name, $dir_mode, $create_index_htmls, $start_folder);
}
/**
* Create multiple dirs at one time (eg. mkdir_m('some_dir1/some_dir2/some_dir3')).
*
* @param $dir_name string
* @param $dir_mode octal
* @param $create_index_htmls bool
* @param $start_folder string
* @return int Status code
*/
public function mkdir_m($dir_name, $dir_mode = 0755, $create_index_htmls = 0, $start_folder = '')
{
if ( ! $dir_name || ! strlen($dir_name)) {
return 0;
}
$dir_name = rtrim(str_replace(['\\', '//'], '/', $dir_name), '/');
// Default dir mode
if (empty($dir_mode)) {
$dir_mode = 0777;
}
// Use native recursive function if applicable
if ( ! $create_index_htmls) {
if (file_exists($dir_name)) {
return true;
}
return mkdir($dir_name, $dir_mode, true);
}
$old_mask = umask(0);
// Default start folder to look at
if ( ! strlen($start_folder)) {
$start_folder = INCLUDE_PATH;
}
$start_folder = str_replace(['\\', '//'], '/', realpath($start_folder) . '/');
// Process given file name
if ( ! file_exists($dir_name)) {
$base_path = OS_WINDOWS ? '' : '/';
preg_match_all('/([^\/]+)\/?/i', $dir_name, $atmp);
foreach ((array) $atmp[0] as $val) {
$base_path = $base_path . $val;
// Skip paths while we are out of base_folder
if ( ! empty($start_folder) && false === strpos($base_path, $start_folder)) {
continue;
}
// Skip if already exists
if (file_exists($base_path)) {
continue;
} elseif ($this->CHECK_IF_WRITABLE && ! is_writable(dirname($base_path))) {
trigger_error('DIR: directory: ' . dirname($base_path) . ' is not writable', E_USER_WARNING);
}
// Try to create sub dir
if ( ! mkdir($base_path, $dir_mode)) {
trigger_error('DIR: Cannot create: ' . $base_path, E_USER_WARNING);
return -1;
}
chmod($base_path, $dir_mode);
}
} elseif ( ! is_dir($dir_name)) {
trigger_error('DIR: ' . $dir_name . ' exists and is not a directory', E_USER_WARNING);
return -2;
}
// Create empty index.html in new folder if needed
if ($create_index_htmls) {
$index_file_path = $dir_name . '/index.html';
if ( ! file_exists($index_file_path)) {
file_put_contents($index_file_path, '');
}
}
umask($old_mask);
return 0;
}
/**
* generate user upload path and if need make generated dirs.
*
* @code
* $user_id = 123456789;
*
* // generate only path
* $dir = _class('dir')->_gen_dir_path($user_id);
* // $dir == '123/456/789/';
*
* // generate only full path
* $dir = _class('dir')->_gen_dir_path($user_id,INCLUDE_PATH);
* // $dir == INCLUDE_PATH.'123/456/789/';
*
* // generate full path and make dirs '123/456/789/'
* $dir = _class('dir')->_gen_dir_path($user_id,INCLUDE_PATH,true);
* // $dir == INCLUDE_PATH.'123/456/789/';
*
* // generate full path and make dirs '123/456/789/' with permissions 0644
* $dir = _class('dir')->_gen_dir_path($user_id,INCLUDE_PATH,true,0644);
* // $dir == INCLUDE_PATH.'123/456/789/';
* @endcode
* @param $id user id
* @param $path path to main dir
* @param $make bool if create directories need
* @param $dir_mode mode of the new dirs (octal)
* @param $create_index_htmls bool Create index.html's in every new folder or not
* @return user uploads path
* @private
*/
public function _gen_dir_path($id, $path = '', $make = false, $dir_mode = 0755, $create_index_htmls = 1)
{
// Make 3-level dir path
$dirs = sprintf('%09s', $id);
$dir3 = substr($dirs, -3, 3);
$dir2 = substr($dirs, -6, 3);
$dir1 = substr($dirs, 0, -6);
// 3-level path
$mpath = $dir1 . '/' . $dir2 . '/' . $dir3 . '/';
// Add path prefix to string
if (strlen($path) > 0) {
// if last char in $path not '\' or '/' add '/'
if ((substr($path, -1, 1) !== '/') && (substr($path, -1, 1) !== '\\')) {
$path .= '/';
}
$mpath = $path . $mpath;
}
// Do create subdirs (if needed)
if ($make) {
$this->mkdir_m($mpath, $dir_mode, $create_index_htmls);
}
return $mpath;
}
/**
* Cross-OS make symlink method.
* @param mixed $target
* @param mixed $link
*/
public function mklink($target, $link)
{
// Required fixes for trailink slash
$target = rtrim(str_replace('\\', '/', $target), '/');
$link = rtrim(str_replace('\\', '/', $link), '/');
// Check required stuff
if ( ! strlen($target) || ! strlen($link) || ! file_exists($target)) {
return false;
}
if (function_exists('symlink')) {
return symlink($target, $link);
}
return false;
}
/**
* This function searches given folder(folders) for provided text using paths include/exclude patterns.
*
* @return array of found files
* @param mixed $start_dirs
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param mixed $pattern_find
*/
public function search($start_dirs, $pattern_include = '', $pattern_exclude = '', $pattern_find)
{
if ( ! is_array($start_dirs)) {
$start_dirs = [$start_dirs];
}
if ( ! $pattern_find) {
return false;
}
if ( ! is_array($pattern_find)) {
$pattern_find = [$pattern_find];
}
$files = [];
foreach ((array) $start_dirs as $_dir_name) {
foreach ((array) $this->scan_dir($_dir_name, 1, $pattern_include, $pattern_exclude) as $_file_path) {
$files[] = $_file_path;
}
}
$files_matched = [];
foreach ((array) $files as $_id => $_file_path) {
$contents = file_get_contents($_file_path);
foreach ((array) $pattern_find as $p_find) {
if (preg_match($p_find, $contents)) {
$files_matched[$_id] = $files[$_id];
continue;
}
}
}
return $files_matched;
}
/**
* This function searches given folder(folders) for provided text using paths include/exclude patterns
* and replaces by pattern.
*
* WARNING! Be careful here, it really overwrites files matches $pattern_replace (if not null)
* test first with $this-search() method
*
* @return array of processed files
* @param mixed $start_dirs
* @param mixed $pattern_include
* @param mixed $pattern_exclude
* @param mixed $pattern_find
* @param mixed $pattern_replace
*/
public function replace($start_dirs, $pattern_include = '', $pattern_exclude = '', $pattern_find, $pattern_replace)
{
$files = [];
if ( ! is_array($start_dirs)) {
$start_dirs = [$start_dirs];
}
if ( ! $pattern_find || ! isset($pattern_replace)) {
return false;
}
if ( ! is_array($pattern_find)) {
$pattern_find = [$pattern_find => $pattern_replace];
}
foreach ((array) $start_dirs as $_dir_name) {
foreach ((array) $this->scan_dir($_dir_name, 1, $pattern_include, $pattern_exclude) as $_file_path) {
$files[] = $_file_path;
}
}
foreach ((array) $files as $_id => $_file_path) {
$contents = file_get_contents($_file_path);
$what = [];
foreach ((array) $pattern_find as $p_find => $p_replace) {
if (preg_match($p_find, $contents)) {
$what[$p_find] = $p_replace;
}
}
// This needed to not log/touch/override files that have no matches
if ( ! $what) {
unset($files[$_id]);
continue;
}
$contents_new = preg_replace(array_keys($what), array_values($what), $contents);
if ($contents_new !== $contents) {
file_put_contents($_file_path, $contents_new);
}
}
return $files;
}
/**
* @param mixed $pattern_find
* @param mixed $start_dirs
* @param mixed $pattern_path
* @param mixed $extra
*/
public function grep($pattern_find, $start_dirs, $pattern_path = '*', $extra = [])
{
if ( ! $pattern_find) {
return false;
}
if ( ! $start_dirs) {
$start_dirs = APP_PATH;
}
if ( ! is_array($start_dirs)) {
$start_dirs = [$start_dirs];
}
if ( ! is_array($pattern_find)) {
$pattern_find = [$pattern_find];
}
$files = [];
foreach ((array) $start_dirs as $start_dir) {
$start_dir = rtrim($start_dir, '/');
foreach ((array) $this->rglob($start_dir, $pattern_path) as $path) {
$files[] = $path;
}
}
$matched = [];
foreach ((array) $files as $_id => $path) {
if (isset($extra['exclude_paths']) && wildcard_compare($extra['exclude_paths'], $path)) {
continue;
}
$contents = file_get_contents($path);
foreach ((array) $pattern_find as $p_find) {
if (preg_match_all($p_find, $contents, $m)) {
$matched[$files[$_id]] = $extra['return_match'] && isset($m[$extra['return_match']]) ? $m[$extra['return_match']] : $m[0];
continue;
}
}
}
return $matched;
}
/**
* Implementation of the UNIX 'tail' command on pure PHP, memory safe on huge files.
* @param mixed $file
* @param mixed $lines
*/
public function tail($file, $lines = 10)
{
if ( ! $file || ! file_exists($file)) {
return false;
}
$handle = fopen($file, 'r');
$linecounter = $lines;
$pos = -2;
$beginning = false;
$text = [];
while ($linecounter > 0) {
$t = ' ';
while ($t != "\n") {
if (fseek($handle, $pos, SEEK_END) == -1) {
$beginning = true;
break;
}
$t = fgetc($handle);
$pos--;
}
$linecounter--;
if ($beginning) {
rewind($handle);
}
$text[$lines - $linecounter - 1] = fgets($handle);
if ($beginning) {
break;
}
}
fclose($handle);
return array_reverse($text);
}
/**
* Check if we need to skip current path according to given patterns (unified method for whole dir module).
* @param mixed $path
* @param mixed $_is_dir
* @param mixed $pattern_include
* @param mixed $pattern_exclude
*/
public function _skip_by_pattern($path = '', $_is_dir = false, $pattern_include = '', $pattern_exclude = '')
{
if ( ! $path) {
return false;
}
if ( ! $pattern_include && ! $pattern_exclude) {
return false;
}
$_path_clean = trim(str_replace('//', '/', str_replace('\\', '/', $path)));
// Include files only if they match the mask
$_index = $_is_dir ? 0 : 1;
if ($_is_dir) {
$_path_clean = rtrim($_path_clean, '/');
}
if (is_array($pattern_include)) {
$pattern_include = $pattern_include[$_index];
}
if (is_array($pattern_exclude)) {
$pattern_exclude = $pattern_exclude[$_index];
}
$MATCHED = false;
if ( ! empty($pattern_include) && is_string($pattern_include)) {
// Examples: "-f /\.(jpg|png)$/", -d /some_dir/
$try_modifier = substr($pattern_include, 0, 3);
if (in_array($try_modifier, ['-f ', '-d '])) {
$pattern_include = substr($pattern_include, 3);
$modifier = $try_modifier;
}
if (strlen($pattern_include) == 2 && $pattern_include[0] == '-') {
if ($pattern_include == '-d' && ! $_is_dir) {
$MATCHED = true;
} elseif ($pattern_include == '-f' && $_is_dir) {
$MATCHED = true;
}
} else {
$need_match = true;
if ($modifier == '-f ' && $_is_dir) {
$need_match = false;
} elseif ($modifier == '-d ' && ! $_is_dir) {
$need_match = false;
}
if ($need_match && ! preg_match($pattern_include . 'ims', $_path_clean)) {
$MATCHED = true;
}
}
}
// Exclude files from list by mask
if ( ! empty($pattern_exclude) && is_string($pattern_exclude)) {
// Examples: "-f /\.(jpg|png)$/", -d /some_dir/
$try_modifier = substr($pattern_include, 0, 3);
if (in_array($try_modifier, ['-f ', '-d '])) {
$pattern_include = substr($pattern_include, 3);
$modifier = $try_modifier;
}
if (strlen($pattern_exclude) == 2 && $pattern_exclude[0] == '-') {
if ($pattern_exclude == '-d' && $_is_dir) {
$MATCHED = true;
} elseif ($pattern_exclude == '-f' && ! $_is_dir) {
$MATCHED = true;
}
} else {
$need_match = true;
if ($modifier == '-f ' && $_is_dir) {
$need_match = false;
} elseif ($modifier == '-d ' && ! $_is_dir) {
$need_match = false;
}
if ($need_match && preg_match($pattern_exclude . 'ims', $_path_clean)) {
$MATCHED = true;
}
}
}
return $MATCHED;
}
}