banner
10 months ago
bodies
10 months ago
check
10 months ago
cli
10 months ago
cron
10 months ago
dashboard
10 months ago
database
10 months ago
external
10 months ago
extracter
10 months ago
htaccess
10 months ago
notices
10 months ago
progress
10 months ago
scanner
10 months ago
staging
10 months ago
traits
10 months ago
uploader
10 months ago
vendor
10 months ago
zipper
10 months ago
.htaccess
10 months ago
activation.php
10 months ago
ajax.php
10 months ago
ajax_offline.php
10 months ago
analyst.php
10 months ago
backup-process.php
10 months ago
class-backup-method-mananger.php
10 months ago
cli-handler.php
10 months ago
compatibility.php
10 months ago
config.php
10 months ago
constants.php
10 months ago
file-explorer.php
10 months ago
initializer.php
10 months ago
logger.php
10 months ago
offline.php
10 months ago
file-explorer.php
192 lines
| 1 | <?php |
| 2 | |
| 3 | |
| 4 | namespace BMI\Plugin; |
| 5 | |
| 6 | |
| 7 | |
| 8 | if (!defined('ABSPATH')) exit; |
| 9 | |
| 10 | use BMI\Plugin\Backup_Migration_Plugin as BMP; |
| 11 | use BMI\Plugin\BMI_Logger as Logger; |
| 12 | |
| 13 | |
| 14 | /** |
| 15 | * File_Queue is an interface that define the methods that should be implemented by the file container |
| 16 | */ |
| 17 | interface File_Queue{ |
| 18 | |
| 19 | /** |
| 20 | * Insert the file in the container |
| 21 | * @param string $path |
| 22 | * @return void |
| 23 | */ |
| 24 | public function insert_file($path); |
| 25 | |
| 26 | /** |
| 27 | * Get the largest n files and directories |
| 28 | * @param int $n |
| 29 | * @return array of largest n files and directories [['path', 'type', 'size'], ...] |
| 30 | */ |
| 31 | public function getLargest($n); // Get the largest n files and directories |
| 32 | } |
| 33 | |
| 34 | |
| 35 | /** |
| 36 | * BMI_File_Queue is a priority queue that store the files and directories and sort them based on the size |
| 37 | */ |
| 38 | class BMI_File_Queue extends \SplPriorityQueue implements File_Queue{ |
| 39 | |
| 40 | const DIR_TYPE = 0; |
| 41 | const FILE_TYPE = 1; |
| 42 | |
| 43 | const PATH_INDEX = 0; |
| 44 | const TYPE_INDEX = 1; |
| 45 | const SIZE_INDEX = 2; |
| 46 | |
| 47 | |
| 48 | const UNABLE_TO_READ = -1; |
| 49 | |
| 50 | public function __construct(){ |
| 51 | $this->setExtractFlags(\SplPriorityQueue::EXTR_DATA); |
| 52 | } |
| 53 | |
| 54 | |
| 55 | /** |
| 56 | * Insert the file in the container determine the type of the file and size and insert it in array ['path', 'type', 'size'] |
| 57 | * @param string $path |
| 58 | * @return void |
| 59 | */ |
| 60 | public function insert_file($path){ |
| 61 | if (strpos($path, '..') !== false || strpos($path, '/.') !== false){ |
| 62 | return; |
| 63 | } |
| 64 | $path = BMP::fixSlashes($path); |
| 65 | if (is_dir($path)){ |
| 66 | $size = $this->getDirSize($path); |
| 67 | if ($size == self::UNABLE_TO_READ){ |
| 68 | Logger::debug('Unable to read the directory: ' . $path); |
| 69 | return; |
| 70 | } |
| 71 | $this->insert([$path, self::DIR_TYPE, $size], $size); |
| 72 | }else{ |
| 73 | $this->insert([$path, self::FILE_TYPE, filesize($path)], filesize($path)); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | /** |
| 78 | * Get the largest n files and directories |
| 79 | * @param int $n |
| 80 | * @return array of largest n files and directories [['path', 'type', 'size'], ...] |
| 81 | */ |
| 82 | public function getLargest($n){ |
| 83 | $largest = []; |
| 84 | for ($i = 0; $i < $n; $i++){ |
| 85 | if ($this->isEmpty()){ |
| 86 | break; |
| 87 | } |
| 88 | $largest[] = $this->extract(); |
| 89 | } |
| 90 | return $largest; |
| 91 | } |
| 92 | |
| 93 | |
| 94 | |
| 95 | /** |
| 96 | * Get the size of the directory recursively using DirectoryIterator |
| 97 | * @param string $path |
| 98 | * @return int size of the directory |
| 99 | */ |
| 100 | function getDirSize($path){ |
| 101 | $bytestotal = 0; |
| 102 | $path = realpath($path); |
| 103 | if($path!==false && $path!='' && file_exists($path)){ |
| 104 | try{ |
| 105 | new \DirectoryIterator($path); |
| 106 | }catch(\Exception $e){ |
| 107 | return self::UNABLE_TO_READ; |
| 108 | } |
| 109 | foreach(new \DirectoryIterator($path) as $file){ |
| 110 | if($file->isFile()){ |
| 111 | $bytestotal += $file->getSize(); |
| 112 | } |
| 113 | else if(!$file->isDot() && $file->isDir()){ |
| 114 | $bytestotal += $this->getDirSize($file->getPathname()); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | return $bytestotal; |
| 119 | } |
| 120 | |
| 121 | } |
| 122 | |
| 123 | |
| 124 | /** |
| 125 | * BMI_File_Explorer is a class that provide the methods to scan the directory and get the list of largest files and directories |
| 126 | * |
| 127 | * @package BMI\Plugin |
| 128 | * @since 1.4.5 |
| 129 | * @version 1.0 |
| 130 | * @category Class |
| 131 | * @see BMI_File_Queue |
| 132 | * @method BMI_File_Queue scanDir($path) Get the list of largest 100 files and directories in the path |
| 133 | * @method int isSub($dir, $path) Recursivly get if the directory is sub directory of given path or not and return the depth of the sub directory return -1 if not sub directory |
| 134 | * |
| 135 | */ |
| 136 | class BMI_File_Explorer { |
| 137 | |
| 138 | /** |
| 139 | * Get the list of largest 100 files and directories in the path |
| 140 | * don't include the ignored files and directories |
| 141 | * @param string $path |
| 142 | * @param array $ignored |
| 143 | * @param File_Queue $queue |
| 144 | * @return BMI_File_Queue of directories and files each element is an path and type and size [['html/wp-content/plugins', 'dir', 658745], ['html/wp-content/index.php', 'file', 0]], ...] |
| 145 | * |
| 146 | */ |
| 147 | public static function scanDir($path, $ignored = [], $queue = null) { |
| 148 | if ($queue == null){ |
| 149 | $queue = new BMI_File_Queue(); |
| 150 | } |
| 151 | $handle = opendir($path); |
| 152 | while (false !== ($entry = readdir($handle))) { |
| 153 | |
| 154 | $full_path = BMP::fixSlashes($path . '\\' . $entry); |
| 155 | if (in_array($entry, $ignored) || in_array($full_path, $ignored) || $entry == '.' || $entry == '..') { |
| 156 | continue; |
| 157 | } |
| 158 | $queue->insert_file($full_path); |
| 159 | |
| 160 | } |
| 161 | return $queue; |
| 162 | } |
| 163 | |
| 164 | /** |
| 165 | * Recursivly get if the directory is sub directory of given path or not and return true or false |
| 166 | * @param string $dir directory path |
| 167 | * @param string $path path to check if the directory is sub directory of this path |
| 168 | * @return int -1 if not sub directory, 0 is the same directory, depth of the sub directory |
| 169 | */ |
| 170 | public static function isSub($dir, $path , $depth = 0){ |
| 171 | $path = str_replace('***ABSPATH***', ABSPATH, $path); |
| 172 | $dir = str_replace('***ABSPATH***', ABSPATH, $dir); |
| 173 | if (strpos($dir, $path) === false || strpos($dir, '..') !== false) { |
| 174 | return -1; |
| 175 | } |
| 176 | |
| 177 | if ($dir == $path) { |
| 178 | return $depth; |
| 179 | } |
| 180 | |
| 181 | return self::isSub(dirname($dir), $path, $depth + 1); |
| 182 | } |
| 183 | |
| 184 | /** |
| 185 | * Get the size of the directory recursively using DirectoryIterator |
| 186 | * @param string $path |
| 187 | * @return int size of the directory |
| 188 | */ |
| 189 | public static function getDirSize($path){ |
| 190 | return (new BMI_File_Queue())->getDirSize($path); |
| 191 | } |
| 192 | } |