Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
0.00% |
0 / 228 |
|
0.00% |
0 / 12 |
CRAP | |
0.00% |
0 / 1 |
| VaultPress_Filesystem | |
0.00% |
0 / 227 |
|
0.00% |
0 / 12 |
9900 | |
0.00% |
0 / 1 |
| __construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| want | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
42 | |||
| fdump | |
0.00% |
0 / 23 |
|
0.00% |
0 / 1 |
110 | |||
| exec_checksum | |
0.00% |
0 / 15 |
|
0.00% |
0 / 1 |
42 | |||
| checksum_file | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
90 | |||
| stat | |
0.00% |
0 / 26 |
|
0.00% |
0 / 1 |
110 | |||
| ls | |
0.00% |
0 / 28 |
|
0.00% |
0 / 1 |
240 | |||
| should_backup_file | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
20 | |||
| validate | |
0.00% |
0 / 14 |
|
0.00% |
0 / 1 |
42 | |||
| dir_examine | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
210 | |||
| dir_checksum | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
156 | |||
| scan_dir | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
| 1 | <?php |
| 2 | // don't call the file directly |
| 3 | defined( 'ABSPATH' ) || die( 0 ); |
| 4 | |
| 5 | class VaultPress_Filesystem { |
| 6 | |
| 7 | var $type = null; |
| 8 | var $dir = null; |
| 9 | var $keys = array( 'ino', 'uid', 'gid', 'size', 'mtime', 'blksize', 'blocks' ); |
| 10 | |
| 11 | function __construct() { |
| 12 | } |
| 13 | |
| 14 | function want( $type ) { |
| 15 | $vp = VaultPress::init(); |
| 16 | |
| 17 | if ( $type == 'plugins' ) { |
| 18 | $this->dir = realpath( $vp->resolve_content_dir() . 'plugins' ); |
| 19 | $this->type = 'p'; |
| 20 | return true; |
| 21 | } |
| 22 | if ( $type == 'themes' ) { |
| 23 | $this->dir = realpath( $vp->resolve_content_dir() . 'themes' ); |
| 24 | $this->type = 't'; |
| 25 | return true; |
| 26 | } |
| 27 | if ( $type == 'uploads' ) { |
| 28 | $this->dir = realpath( $vp->resolve_upload_path() ); |
| 29 | $this->type = 'u'; |
| 30 | return true; |
| 31 | } |
| 32 | if ( $type == 'content' ) { |
| 33 | $this->dir = realpath( $vp->resolve_content_dir() ); |
| 34 | $this->type = 'c'; |
| 35 | return true; |
| 36 | } |
| 37 | if ( $type == 'root' ) { |
| 38 | $this->dir = realpath( ABSPATH ); |
| 39 | $this->type = 'r'; |
| 40 | return true; |
| 41 | } |
| 42 | die( 'naughty naughty' ); |
| 43 | } |
| 44 | |
| 45 | function fdump( $file ) { |
| 46 | header("Content-Type: application/octet-stream;"); |
| 47 | header("Content-Transfer-Encoding: binary"); |
| 48 | @ob_end_clean(); |
| 49 | if ( !file_exists( $file ) || !is_readable( $file ) ) { |
| 50 | $file_name = basename( $file ); |
| 51 | if ( 'wp-config.php' == $file_name ) { |
| 52 | $dir = dirname( $file ); |
| 53 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
| 54 | array_pop( $dir ); |
| 55 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
| 56 | $file = trailingslashit( $dir ) . $file_name; |
| 57 | if ( !file_exists( $file ) || !is_readable( $file ) ) |
| 58 | die( "no such file" ); |
| 59 | } else { |
| 60 | die( "no such file" ); |
| 61 | } |
| 62 | } |
| 63 | if ( !is_file( $file ) && !is_link( $file ) ) |
| 64 | die( "can only dump files" ); |
| 65 | $fp = @fopen( $file, 'rb' ); |
| 66 | if ( !$fp ) |
| 67 | die( "could not open file" ); |
| 68 | while ( !feof( $fp ) ) |
| 69 | echo @fread( $fp, 8192 ); |
| 70 | @fclose( $fp ); |
| 71 | die( 0 ); |
| 72 | } |
| 73 | |
| 74 | function exec_checksum( $file, $method ) { |
| 75 | if ( !function_exists( 'exec' ) ) |
| 76 | return false; |
| 77 | $out = array(); |
| 78 | if ( 'md5' === $method ) { |
| 79 | $method_bin = 'md5sum'; |
| 80 | } elseif ( 'sha1' === $method ) { |
| 81 | $method_bin = 'sha1sum'; |
| 82 | } else { |
| 83 | return false; |
| 84 | } |
| 85 | $checksum = ''; |
| 86 | exec( sprintf( '%s %s', escapeshellcmd( $method_bin ), escapeshellarg( $file ) ), $out ); |
| 87 | if ( !empty( $out ) ) |
| 88 | $checksum = trim( array_shift( explode( ' ', array_pop( $out ) ) ) ); |
| 89 | if ( !empty( $checksum ) ) |
| 90 | return $checksum; |
| 91 | return false; |
| 92 | } |
| 93 | |
| 94 | function checksum_file( $file, $method ) { |
| 95 | $use_exec = false; |
| 96 | if ( filesize( $file ) >= 104857600 ) |
| 97 | $use_exec = true; |
| 98 | switch( $method ) { |
| 99 | case 'md5': |
| 100 | if ( $use_exec ) { |
| 101 | $checksum = $this->exec_checksum( $file, $method ); |
| 102 | if ( !empty( $checksum ) ) |
| 103 | return $checksum; |
| 104 | } |
| 105 | return md5_file( $file ); |
| 106 | break; |
| 107 | case 'sha1': |
| 108 | if ( $use_exec ) { |
| 109 | $checksum = $this->exec_checksum( $file, $method ); |
| 110 | if ( !empty( $checksum ) ) |
| 111 | return $checksum; |
| 112 | } |
| 113 | return sha1_file( $file ); |
| 114 | break; |
| 115 | default: |
| 116 | return false; |
| 117 | break; |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | function stat( $file, $md5=true, $sha1=true ) { |
| 122 | if ( ! file_exists( $file ) ) |
| 123 | return false; |
| 124 | |
| 125 | $rval = array(); |
| 126 | foreach ( stat( $file ) as $i => $v ) { |
| 127 | if ( is_numeric( $i ) ) |
| 128 | continue; |
| 129 | $rval[$i] = $v; |
| 130 | } |
| 131 | $rval['type'] = filetype( $file ); |
| 132 | if ( $rval['type'] == 'file' ) { |
| 133 | if ( $md5 ) |
| 134 | $rval['md5'] = $this->checksum_file( $file, 'md5' ); |
| 135 | if ( $sha1 ) |
| 136 | $rval['sha1'] = $this->checksum_file( $file, 'sha1' ); |
| 137 | } |
| 138 | $dir = $this->dir; |
| 139 | if ( 0 !== strpos( $file, $dir ) && 'wp-config.php' == basename( $file ) ) { |
| 140 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
| 141 | array_pop( $dir ); |
| 142 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
| 143 | } |
| 144 | $rval['full_path'] = realpath( $file ); |
| 145 | |
| 146 | // Avoid rebuilding path tidy-up regex when fetching multiple entries |
| 147 | static $last_dir = null; |
| 148 | static $dir_regex = null; |
| 149 | if ( $last_dir !== $dir ) { |
| 150 | $dir_regex = '#' . preg_quote( $dir ) . '#'; |
| 151 | $last_dir = $dir; |
| 152 | } |
| 153 | |
| 154 | $rval['path'] = preg_replace( $dir_regex, '', $file, 1 ); |
| 155 | return $rval; |
| 156 | } |
| 157 | |
| 158 | function ls( $what, $md5=false, $sha1=false, $limit=null, $offset=null, $full_list=false ) { |
| 159 | clearstatcache(); |
| 160 | $path = realpath($this->dir . $what); |
| 161 | $dir = $this->dir; |
| 162 | if ( !$path && '/wp-config.php' == $what ) { |
| 163 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
| 164 | array_pop( $dir ); |
| 165 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
| 166 | $path = realpath( $dir . $what ); |
| 167 | } |
| 168 | if ( is_file($path) ) |
| 169 | return $this->stat( $path, $md5, $sha1 ); |
| 170 | if ( is_dir($path) ) { |
| 171 | $entries = array(); |
| 172 | $current = 0; |
| 173 | $offset = (int)$offset; |
| 174 | $orig_limit = (int)$limit; |
| 175 | $limit = $offset + (int)$limit; |
| 176 | foreach ( (array)$this->scan_dir( $path ) as $i ) { |
| 177 | if ( !$full_list && !$this->should_backup_file( $i ) ) |
| 178 | continue; |
| 179 | ++$current; |
| 180 | if ( $offset >= $current ) |
| 181 | continue; |
| 182 | if ( $limit && $limit < $current ) |
| 183 | break; |
| 184 | |
| 185 | // don't sha1 files over 100MB if we are batching due to memory consumption |
| 186 | if ( $sha1 && $orig_limit > 1 && is_file( $i ) && (int)@filesize( $i ) > 104857600 ) |
| 187 | $sha1 = false; |
| 188 | |
| 189 | $entries[] = $this->stat( $i, $md5, $sha1 ); |
| 190 | } |
| 191 | return $entries; |
| 192 | } |
| 193 | } |
| 194 | |
| 195 | function should_backup_file( $filepath ) { |
| 196 | $vp = VaultPress::init(); |
| 197 | if ( is_dir( $filepath ) ) |
| 198 | $filepath = trailingslashit( $filepath ); |
| 199 | $regex_patterns = $vp->get_should_ignore_files(); |
| 200 | foreach ( $regex_patterns as $pattern ) { |
| 201 | $matches = array(); |
| 202 | if ( preg_match( $pattern, $filepath, $matches ) ) { |
| 203 | return false; |
| 204 | } |
| 205 | } |
| 206 | return true; |
| 207 | } |
| 208 | |
| 209 | function validate( $file ) { |
| 210 | $rpath = realpath( $this->dir.$file ); |
| 211 | $dir = $this->dir; |
| 212 | if ( !$rpath && '/wp-config.php' == $file ) { |
| 213 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
| 214 | array_pop( $dir ); |
| 215 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
| 216 | $rpath = realpath( $dir . $file ); |
| 217 | } |
| 218 | if ( !$rpath ) |
| 219 | die( serialize( array( 'type' => 'null', 'path' => $file ) ) ); |
| 220 | if ( is_dir( $rpath ) ) |
| 221 | $rpath = "$rpath/"; |
| 222 | if ( strpos( $rpath, $dir ) !== 0 ) |
| 223 | return false; |
| 224 | return true; |
| 225 | } |
| 226 | |
| 227 | function dir_examine( $subdir='', $recursive=true, $origin=false ) { |
| 228 | $res = array(); |
| 229 | if ( !$subdir ) |
| 230 | $subdir='/'; |
| 231 | $dir = $this->dir . $subdir; |
| 232 | if ( $origin === false ) |
| 233 | $origin = $this->dir . $subdir; |
| 234 | if ( is_file($dir) ) { |
| 235 | if ( $origin == $dir ) |
| 236 | $name = str_replace( $this->dir, '/', $subdir ); |
| 237 | else |
| 238 | $name = str_replace( $origin, '/', $dir ); |
| 239 | $res[$name] = $this->stat( $dir.$entry ); |
| 240 | return $res; |
| 241 | } |
| 242 | $d = dir( $dir ); |
| 243 | if ( !$d ) |
| 244 | return $res; |
| 245 | while ( false !== ( $entry = $d->read() ) ) { |
| 246 | $rpath = realpath( $dir.$entry ); |
| 247 | $bname = basename( $rpath ); |
| 248 | if ( is_link( $dir.$entry ) ) |
| 249 | continue; |
| 250 | if ( $entry == '.' || $entry == '..' || $entry == '...' ) |
| 251 | continue; |
| 252 | if ( !$this->validate( $subdir.$entry ) ) |
| 253 | continue; |
| 254 | $name = str_replace( $origin, '/', $dir.$entry ); |
| 255 | $res[$name] = $this->stat( $dir.$entry ); |
| 256 | if ( $recursive && is_dir( $this->dir.$subdir.'/'.$entry ) ) { |
| 257 | $res = array_merge( $res, $this->dir_examine( $subdir.$entry.'/', $recursive, $origin ) ); |
| 258 | } |
| 259 | } |
| 260 | return $res; |
| 261 | } |
| 262 | |
| 263 | function dir_checksum( $base, &$list, $recursive=true ) { |
| 264 | if ( $list == null ) |
| 265 | $list = array(); |
| 266 | |
| 267 | if ( 0 !== strpos( $base, $this->dir ) ) |
| 268 | $base = $this->dir . rtrim( $base, '/' ); |
| 269 | |
| 270 | $shortbase = substr( $base, strlen( $this->dir ) ); |
| 271 | if ( !$shortbase ) |
| 272 | $shortbase = '/'; |
| 273 | $stat = stat( $base ); |
| 274 | $directories = array(); |
| 275 | $files = (array)$this->scan_dir( $base ); |
| 276 | array_push( $files, $base ); |
| 277 | foreach ( $files as $file ) { |
| 278 | if ( $file !== $base && @is_dir( $file ) ) { |
| 279 | $directories[] = $file; |
| 280 | continue; |
| 281 | } |
| 282 | $stat = @stat( $file ); |
| 283 | if ( !$stat ) |
| 284 | continue; |
| 285 | $shortstat = array(); |
| 286 | foreach( $this->keys as $key ) { |
| 287 | if ( isset( $stat[$key] ) ) |
| 288 | $shortstat[$key] = $stat[$key]; |
| 289 | } |
| 290 | $list[$shortbase][basename( $file )] = $shortstat; |
| 291 | } |
| 292 | $list[$shortbase] = md5( serialize( $list[$shortbase] ) ); |
| 293 | if ( !$recursive ) |
| 294 | return $list; |
| 295 | foreach ( $directories as $dir ) { |
| 296 | $this->dir_checksum( $dir, $list, $recursive ); |
| 297 | } |
| 298 | return $list; |
| 299 | } |
| 300 | |
| 301 | function scan_dir( $path ) { |
| 302 | $files = array(); |
| 303 | |
| 304 | if ( ! is_readable( $path ) ) { |
| 305 | return array(); |
| 306 | } |
| 307 | |
| 308 | $dh = opendir( $path ); |
| 309 | |
| 310 | if ( false === $dh ) { |
| 311 | return array(); |
| 312 | } |
| 313 | |
| 314 | while ( false !== ( $file = readdir( $dh ) ) ) { |
| 315 | if ( $file == '.' || $file == '..' ) continue; |
| 316 | $files[] = "$path/$file"; |
| 317 | } |
| 318 | |
| 319 | closedir( $dh ); |
| 320 | sort( $files ); |
| 321 | return $files; |
| 322 | } |
| 323 | } |