Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 228
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
VaultPress_Filesystem
0.00% covered (danger)
0.00%
0 / 227
0.00% covered (danger)
0.00%
0 / 12
9900
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 want
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
42
 fdump
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
110
 exec_checksum
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
42
 checksum_file
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
90
 stat
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 1
110
 ls
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
240
 should_backup_file
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
20
 validate
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
42
 dir_examine
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
210
 dir_checksum
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
156
 scan_dir
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2// don't call the file directly
3defined( 'ABSPATH' ) || die( 0 );
4
5class 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}