File: /var/www/html/wpwatermates_err/wp-content/plugins/defender-security/framework/base/file.php
<?php
/**
* Author: Hoang Ngo
*/
namespace Calotes\Base;
class File {
const ENGINE_SPL = 'spl', ENGINE_SCANDIR = 'scan_dir', ENGINE_OPENDIR = 'open_dir';
/**
* Engine use to create a dir tree
*
* @var string
*/
public $engine = '';
/**
* Absolute path to a folder need to create a dir tre
*
* @var string
*/
public $path = '';
/**
* Is the result including file?
*
* @var bool
*/
public $include_file = true;
/**
* Is the result include dir
*
* @var bool
*/
public $include_dir = true;
/**
* @var bool
*/
public $include_hidden = false;
/**
* This is where to define the rules for exclude files out of the result
*
* 'ext'=>array('jpg','gif') file extension you don't want appear in the result
* 'path'=>array('/tmp/file1.txt','/tmp/file2') absolute path to files
* 'dir'=>array('/tmp/','/dir/') absolute path to the directory you dont want to include files
* 'filename'=>array('abc*') file name you don't want to include, can be regex,
*
* @var array
*/
public $exclude = [];
/**
* This is where to define the rules for include files, please note that if $include is provided, the $exclude
* will get ignored
*
* 'ext'=>array('jpg','gif') file extension you don't want appear in the result
* 'path'=>array('/tmp/file1.txt','/tmp/file2') absolute path to files
* 'dir'=>array('/tmp/','/dir/') absolute path to the directory you dont want to include files
* 'filename'=>array('abc*') file name you don't want to include, can be regex.
*
* @var array
*/
public $include = [];
/**
* Does this search recursive
*
* @var bool
*/
public $is_recursive = true;
/**
* if provided, only search file smaller than this
*
* @var bool
*/
public $max_filesize = false;
/**
* @param $path
* @param bool|true $include_file
* @param bool|false $include_dir
* @param array $include
* @param array $exclude
* @param bool|true $is_recursive
* @param bool|int $max_filesize
*/
public function __construct( $path, $include_file = true, $include_dir = false, $include_rules = [], $exclude = [], $is_recursive = true, $include_hidden = false, $max_filesize = false ) {
$this->path = $path;
$this->include_file = $include_file;
$this->include_dir = $include_dir;
$this->include = $include_rules;
$this->exclude = $exclude;
$this->is_recursive = $is_recursive;
$this->engine = self::ENGINE_SCANDIR;
$this->include_hidden = $include_hidden;
$this->max_filesize = $max_filesize;
}
/**
* @return array
*/
public function get_dir_tree() {
$result = [];
if ( ! is_dir( $this->path ) ) {
return $result;
}
if ( self::ENGINE_SPL === $this->engine ) {
$result = $this->_get_dir_tree_by_spl();
} elseif ( self::ENGINE_SCANDIR === $this->engine ) {
$result = $this->_get_dir_tree_by_scandir();
} elseif ( self::ENGINE_OPENDIR === $this->engine ) {
$result = $this->_get_dir_tree_by_open_dir();
}
return $result;
}
/**
* Create a dir tree by SPL library
*
* @return array
*/
private function _get_dir_tree_by_spl() {
$path = $this->path;
$data = [];
if ( $this->is_recursive ) {
$directory_flag = \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO
| \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::SKIP_DOTS;
$directory = new \RecursiveDirectoryIterator( $path, $directory_flag );
if ( ! empty( $this->include ) || ! empty( $this->exclude ) ) {
$directory = new \RecursiveCallbackFilterIterator(
$directory,
[
&$this,
'filter_directory',
]
);
}
$tree = new \RecursiveIteratorIterator( $directory, \RecursiveIteratorIterator::SELF_FIRST );
if ( true !== $this->is_recursive ) {
$tree->setMaxDepth( $this->is_recursive );
}
} else {
$tree = new \FilesystemIterator( $path );
}
foreach ( $tree as $file ) {
$real_path = $file->getRealPath();
$is_hidden = explode( DIRECTORY_SEPARATOR . '.', $real_path );
if ( count( $is_hidden ) > 1 && false === $this->include_hidden ) {
continue;
}
if ( false === $this->is_recursive ) {
// Have to filter this, for un recursive.
if ( ! empty( $this->include ) || ! empty( $this->exclude ) ) {
if ( false === $this->filter_directory( $real_path ) ) {
continue;
}
}
}
if ( false === $this->include_file && $file->isFile() ) {
continue;
}
if ( false === $this->include_dir && $file->isDir() ) {
continue;
}
if ( $file->isFile() && is_numeric( $this->max_filesize ) ) {
// Convert max to bytes.
$max_size = $this->max_filesize * ( pow( 1024, 2 ) );
if ( $file->getSize() > $max_size ) {
continue;
}
}
$data[] = $real_path;
}
return $data;
}
/**
* @param $path
*
* @return array
*/
private function _get_dir_tree_by_scandir( $path = null ) {
if ( is_null( $path ) ) {
$path = $this->path;
}
$path = rtrim( $path, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
$rfiles = scandir( $path );
$data = [];
foreach ( $rfiles as $rfile ) {
if ( '.' === $rfile || '..' === $rfile ) {
continue;
}
if ( '.' === substr( pathinfo( $rfile, PATHINFO_BASENAME ), 0, 1 )
&& false === $this->include_hidden ) {
// Hidden files, move on.
continue;
}
$real_path = $path . $rfile;
$type = filetype( $real_path );
if ( ( ! empty( $this->include ) || ! empty( $this->exclude ) ) && ( false === $this->filter_directory( $real_path, $type ) ) ) {
continue;
}
if ( 'file' === $type && true === $this->include_file ) {
if ( is_numeric( $this->max_filesize ) ) {
$max_size = $this->max_filesize * ( pow( 1024, 2 ) );
if ( filesize( $real_path ) > $max_size ) {
continue;
} else {
$data[] = $real_path;
}
} else {
$data[] = $real_path;
}
}
if ( 'dir' === $type ) {
if ( $this->include_dir ) {
$data[] = $real_path;
}
if ( $this->is_recursive ) {
$tdata = $this->_get_dir_tree_by_scandir( $real_path );
$data = array_merge( $data, $tdata );
}
}
}
return $data;
}
/**
* Query files on path using opendir&readir
*
* @param $path
*
* @return array
* @since 1.0.5
*/
private function _get_dir_tree_by_open_dir( $path = null ) {
if ( is_null( $path ) ) {
$path = $this->path;
}
$path = rtrim( $path, DIRECTORY_SEPARATOR ) . DIRECTORY_SEPARATOR;
$data = [];
if ( $dh = opendir( $path ) ) {// phpcs:ignore
while ( ( $file = readdir( $dh ) ) !== false ) {// phpcs:ignore
if ( '.' === $file || '..' === $file ) {
continue;
}
$real_path = $path . $file;
if ( '.' === substr( pathinfo( $real_path, PATHINFO_BASENAME ), 0, 1 ) ) {
// Hidden files, move on.
continue;
}
if ( ( ! empty( $this->include ) || ! empty( $this->exclude ) ) && ( false === $this->filter_directory( $real_path ) ) ) {
continue;
}
$type = filetype( $real_path );
if ( 'file' === $type && true === $this->include_file ) {
if ( is_numeric( $this->max_filesize ) ) {
$max_size = $this->max_filesize * ( pow( 1024, 2 ) );
if ( filesize( $real_path ) > $max_size ) {
continue;
} else {
$data[] = $real_path;
}
} else {
$data[] = $real_path;
}
}
if ( 'dir' === $type ) {
if ( $this->include_dir ) {
$data[] = $real_path;
}
if ( $this->is_recursive ) {
$tdata = $this->_get_dir_tree_by_open_dir( $real_path );
$data = array_merge( $data, $tdata );
}
}
}
closedir( $dh );
}
return $data;
}
/**
* Filter for recursive directory tree
*
* @param $current
* @param $filetype
*
* @return bool|void
*/
public function filter_directory( $current, $filetype = null ) {
if ( ! empty( $this->include ) ) {
return $this->_filter_include( $current, $filetype );
} elseif ( ! empty( $this->exclude ) ) {
return $this->_filter_exclude( $current, $filetype );
}
}
/**
* @param $path
* @param $filetype
*
* @return bool
*/
private function _filter_include( $path, $filetype = null ) {
$include = $this->include;
$exclude = $this->exclude;
$applied = 0;
$dir_include = isset( $include['dir'] ) ? $include['dir'] : [];
$dir_exclude = isset( $exclude['dir'] ) ? $exclude['dir'] : [];
if ( ! is_null( $filetype ) ) {
$type = $filetype;
} else {
$type = filetype( $path );
}
if ( is_array( $dir_include ) && count( $dir_include ) ) {
if ( is_array( $dir_exclude ) ) {
foreach ( $dir_exclude as $dir ) {
if ( 0 === strpos( $path, $dir ) ) {
// This mean, exlucde matched, we won't list this. Move to next loop.
continue;
}
}
}
foreach ( $dir_include as $dir ) {
if ( 0 === strpos( $path, $dir ) ) {
return true;
}
}
$applied++;// phpcs:ignore
}
// Next extension.
$ext_include = isset( $include['ext'] ) ? $include['ext'] : [];
if ( is_array( $ext_include ) && count( $ext_include ) && 'file' === $type ) {
// We will uses foreach and strcasecmp instead of regex cause it faster.
foreach ( $ext_include as $ext ) {
if ( strcasecmp( pathinfo( $path, PATHINFO_EXTENSION ), $ext ) === 0 ) {
// Match.
return true;
}
}
$applied++;// phpcs:ignore
}
// Now filename.
$filename_include = isset( $include['filename'] ) ? $include['filename'] : [];
if ( is_array( $filename_include ) && count( $filename_include ) && 'file' === $type ) {
foreach ( $filename_include as $filename ) {
if ( preg_match( '/' . $filename . '/', pathinfo( $path, PATHINFO_BASENAME ) ) ) {
return true;
}
}
$applied++;// phpcs:ignore
}
// Now abs path.
$path_include = isset( $include['path'] ) ? $include['path'] : [];
if ( is_array( $path_include ) && count( $path_include ) && 'file' === $type ) {
foreach ( $path_include as $p ) {
if ( strcmp( $p, $path ) === 0 ) {
return true;
}
}
$applied++;// phpcs:ignore
}
if ( 0 === $applied ) {
return true;
}
return false;
}
/**
* Run the filter for a file/dir.
*
* @param $path
* @param $filetype
*
* @return bool
*/
private function _filter_exclude( $path, $filetype = null ) {
$exclude = $this->exclude;
// First filer dir, or file inside dir.
if ( ! is_null( $filetype ) ) {
$type = $filetype;
} else {
$type = filetype( $path );
}
$dir_exclude = isset( $exclude['dir'] ) ? $exclude['dir'] : [];
if ( is_array( $dir_exclude ) && count( $dir_exclude ) ) {
foreach ( $dir_exclude as $dir ) {
if ( strpos( $path, $dir ) === 0 ) {
return false;
}
}
}
// Next extension.
$ext_exclude = isset( $exclude['ext'] ) ? $exclude['ext'] : [];
if ( is_array( $ext_exclude ) && count( $ext_exclude ) && 'file' === $type ) {
// We will uses foreach and strcasecmp instead of regex cause it faster.
foreach ( $ext_exclude as $ext ) {
if ( strcasecmp( pathinfo( $path, PATHINFO_EXTENSION ), $ext ) === 0 ) {
// Match.
return false;
}
}
}
// Now filename.
$filename_exclude = isset( $exclude['filename'] ) ? $exclude['filename'] : [];
if ( is_array( $filename_exclude ) && count( $filename_exclude ) && 'file' === $type ) {
foreach ( $filename_exclude as $filename ) {
if ( preg_match( '/' . $filename . '/', pathinfo( $path, PATHINFO_BASENAME ) ) ) {
return false;
}
}
}
// Now abs path.
$path_exclude = isset( $exclude['path'] ) ? $exclude['path'] : [];
if ( is_array( $path_exclude ) && count( $path_exclude ) && 'file' === $type ) {
foreach ( $path_exclude as $p ) {
if ( strcmp( $p, $path ) === 0 ) {
return false;
}
}
}
return true;
}
}