This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | // don't call the file directly |
||
3 | defined( 'ABSPATH' ) or die(); |
||
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(); |
||
0 ignored issues
–
show
|
|||
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 ); |
||
0 ignored issues
–
show
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||
71 | die(); |
||
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 | if ( 'sha1' == $method ) |
||
81 | $method_bin = 'sha1sum'; |
||
82 | $checksum = ''; |
||
83 | exec( sprintf( '%s %s', escapeshellcmd( $method_bin ), escapeshellarg( $file ) ), $out ); |
||
0 ignored issues
–
show
The variable
$method_bin does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
![]() |
|||
84 | if ( !empty( $out ) ) |
||
85 | $checksum = trim( array_shift( explode( ' ', array_pop( $out ) ) ) ); |
||
0 ignored issues
–
show
|
|||
86 | if ( !empty( $checksum ) ) |
||
87 | return $checksum; |
||
88 | return false; |
||
89 | } |
||
90 | |||
91 | function checksum_file( $file, $method ) { |
||
92 | $use_exec = false; |
||
93 | if ( filesize( $file ) >= 104857600 ) |
||
94 | $use_exec = true; |
||
95 | switch( $method ) { |
||
96 | View Code Duplication | case 'md5': |
|
97 | if ( $use_exec ) { |
||
98 | $checksum = $this->exec_checksum( $file, $method ); |
||
99 | if ( !empty( $checksum ) ) |
||
100 | return $checksum; |
||
101 | } |
||
102 | return md5_file( $file ); |
||
103 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
104 | View Code Duplication | case 'sha1': |
|
105 | if ( $use_exec ) { |
||
106 | $checksum = $this->exec_checksum( $file, $method ); |
||
107 | if ( !empty( $checksum ) ) |
||
108 | return $checksum; |
||
109 | } |
||
110 | return sha1_file( $file ); |
||
111 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
112 | default: |
||
113 | return false; |
||
114 | break; |
||
0 ignored issues
–
show
break is not strictly necessary here and could be removed.
The break statement is not necessary if it is preceded for example by a return statement: switch ($x) {
case 1:
return 'foo';
break; // This break is not necessary and can be left off.
}
If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive. ![]() |
|||
115 | } |
||
116 | } |
||
117 | |||
118 | function stat( $file, $md5=true, $sha1=true ) { |
||
119 | if ( ! file_exists( $file ) ) |
||
120 | return false; |
||
121 | |||
122 | $rval = array(); |
||
123 | foreach ( stat( $file ) as $i => $v ) { |
||
124 | if ( is_numeric( $i ) ) |
||
125 | continue; |
||
126 | $rval[$i] = $v; |
||
127 | } |
||
128 | $rval['type'] = filetype( $file ); |
||
129 | if ( $rval['type'] == 'file' ) { |
||
130 | if ( $md5 ) |
||
131 | $rval['md5'] = $this->checksum_file( $file, 'md5' ); |
||
132 | if ( $sha1 ) |
||
133 | $rval['sha1'] = $this->checksum_file( $file, 'sha1' ); |
||
134 | } |
||
135 | $dir = $this->dir; |
||
136 | if ( 0 !== strpos( $file, $dir ) && 'wp-config.php' == basename( $file ) ) { |
||
137 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
||
138 | array_pop( $dir ); |
||
139 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
||
140 | } |
||
141 | $rval['full_path'] = realpath( $file ); |
||
142 | |||
143 | // Avoid rebuilding path tidy-up regex when fetching multiple entries |
||
144 | static $last_dir = null; |
||
145 | static $dir_regex = null; |
||
146 | if ( $last_dir !== $dir ) { |
||
147 | $dir_regex = '#' . preg_quote( $dir ) . '#'; |
||
148 | $last_dir = $dir; |
||
149 | } |
||
150 | |||
151 | $rval['path'] = preg_replace( $dir_regex, '', $file, 1 ); |
||
152 | return $rval; |
||
153 | } |
||
154 | |||
155 | function ls( $what, $md5=false, $sha1=false, $limit=null, $offset=null, $full_list=false ) { |
||
156 | clearstatcache(); |
||
157 | $path = realpath($this->dir . $what); |
||
158 | $dir = $this->dir; |
||
159 | View Code Duplication | if ( !$path && '/wp-config.php' == $what ) { |
|
160 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
||
161 | array_pop( $dir ); |
||
162 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
||
163 | $path = realpath( $dir . $what ); |
||
164 | } |
||
165 | if ( is_file($path) ) |
||
166 | return $this->stat( $path, $md5, $sha1 ); |
||
167 | if ( is_dir($path) ) { |
||
168 | $entries = array(); |
||
169 | $current = 0; |
||
170 | $offset = (int)$offset; |
||
171 | $orig_limit = (int)$limit; |
||
172 | $limit = $offset + (int)$limit; |
||
173 | foreach ( (array)$this->scan_dir( $path ) as $i ) { |
||
174 | if ( !$full_list && !$this->should_backup_file( $i ) ) |
||
175 | continue; |
||
176 | $current++; |
||
177 | if ( $offset >= $current ) |
||
178 | continue; |
||
179 | if ( $limit && $limit < $current ) |
||
180 | break; |
||
181 | |||
182 | // don't sha1 files over 100MB if we are batching due to memory consumption |
||
183 | if ( $sha1 && $orig_limit > 1 && is_file( $i ) && (int)@filesize( $i ) > 104857600 ) |
||
184 | $sha1 = false; |
||
185 | |||
186 | $entries[] = $this->stat( $i, $md5, $sha1 ); |
||
187 | } |
||
188 | return $entries; |
||
189 | } |
||
190 | } |
||
191 | |||
192 | function should_backup_file( $filepath ) { |
||
193 | $vp = VaultPress::init(); |
||
194 | if ( is_dir( $filepath ) ) |
||
195 | $filepath = trailingslashit( $filepath ); |
||
196 | $regex_patterns = $vp->get_should_ignore_files(); |
||
197 | foreach ( $regex_patterns as $pattern ) { |
||
198 | $matches = array(); |
||
199 | if ( preg_match( $pattern, $filepath, $matches ) ) { |
||
200 | return false; |
||
201 | } |
||
202 | } |
||
203 | return true; |
||
204 | } |
||
205 | |||
206 | function validate( $file ) { |
||
207 | $rpath = realpath( $this->dir.$file ); |
||
208 | $dir = $this->dir; |
||
209 | View Code Duplication | if ( !$rpath && '/wp-config.php' == $file ) { |
|
210 | $dir = explode( DIRECTORY_SEPARATOR, $dir ); |
||
211 | array_pop( $dir ); |
||
212 | $dir = implode( DIRECTORY_SEPARATOR, $dir ); |
||
213 | $rpath = realpath( $dir . $file ); |
||
214 | } |
||
215 | if ( !$rpath ) |
||
216 | die( serialize( array( 'type' => 'null', 'path' => $file ) ) ); |
||
217 | if ( is_dir( $rpath ) ) |
||
218 | $rpath = "$rpath/"; |
||
219 | if ( strpos( $rpath, $dir ) !== 0 ) |
||
220 | return false; |
||
221 | return true; |
||
222 | } |
||
223 | |||
224 | function dir_examine( $subdir='', $recursive=true, $origin=false ) { |
||
225 | $res = array(); |
||
226 | if ( !$subdir ) |
||
227 | $subdir='/'; |
||
228 | $dir = $this->dir . $subdir; |
||
229 | if ( $origin === false ) |
||
230 | $origin = $this->dir . $subdir; |
||
231 | if ( is_file($dir) ) { |
||
232 | if ( $origin == $dir ) |
||
233 | $name = str_replace( $this->dir, '/', $subdir ); |
||
234 | else |
||
235 | $name = str_replace( $origin, '/', $dir ); |
||
236 | $res[$name] = $this->stat( $dir.$entry ); |
||
0 ignored issues
–
show
The variable
$entry seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case, ![]() |
|||
237 | return $res; |
||
238 | } |
||
239 | $d = dir( $dir ); |
||
240 | if ( !$d ) |
||
241 | return $res; |
||
242 | while ( false !== ( $entry = $d->read() ) ) { |
||
243 | $rpath = realpath( $dir.$entry ); |
||
244 | $bname = basename( $rpath ); |
||
0 ignored issues
–
show
$bname is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
245 | if ( is_link( $dir.$entry ) ) |
||
246 | continue; |
||
247 | if ( $entry == '.' || $entry == '..' || $entry == '...' ) |
||
248 | continue; |
||
249 | if ( !$this->validate( $subdir.$entry ) ) |
||
0 ignored issues
–
show
The expression
$this->validate($subdir . $entry) of type null|boolean is loosely compared to false ; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.
If an expression can have both $a = canBeFalseAndNull();
// Instead of
if ( ! $a) { }
// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
![]() |
|||
250 | continue; |
||
251 | $name = str_replace( $origin, '/', $dir.$entry ); |
||
252 | $res[$name] = $this->stat( $dir.$entry ); |
||
253 | if ( $recursive && is_dir( $this->dir.$subdir.'/'.$entry ) ) { |
||
254 | $res = array_merge( $res, $this->dir_examine( $subdir.$entry.'/', $recursive, $origin ) ); |
||
0 ignored issues
–
show
It seems like
$origin defined by $this->dir . $subdir on line 230 can also be of type string ; however, VaultPress_Filesystem::dir_examine() does only seem to accept boolean , maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. ![]() |
|||
255 | } |
||
256 | } |
||
257 | return $res; |
||
258 | } |
||
259 | |||
260 | function dir_checksum( $base, &$list, $recursive=true ) { |
||
261 | if ( $list == null ) |
||
262 | $list = array(); |
||
263 | |||
264 | if ( 0 !== strpos( $base, $this->dir ) ) |
||
265 | $base = $this->dir . rtrim( $base, '/' ); |
||
266 | |||
267 | $shortbase = substr( $base, strlen( $this->dir ) ); |
||
268 | if ( !$shortbase ) |
||
269 | $shortbase = '/'; |
||
270 | $stat = stat( $base ); |
||
0 ignored issues
–
show
$stat is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
271 | $directories = array(); |
||
272 | $files = (array)$this->scan_dir( $base ); |
||
273 | array_push( $files, $base ); |
||
274 | foreach ( $files as $file ) { |
||
275 | if ( $file !== $base && @is_dir( $file ) ) { |
||
276 | $directories[] = $file; |
||
277 | continue; |
||
278 | } |
||
279 | $stat = @stat( $file ); |
||
280 | if ( !$stat ) |
||
281 | continue; |
||
282 | $shortstat = array(); |
||
283 | foreach( $this->keys as $key ) { |
||
284 | if ( isset( $stat[$key] ) ) |
||
285 | $shortstat[$key] = $stat[$key]; |
||
286 | } |
||
287 | $list[$shortbase][basename( $file )] = $shortstat; |
||
288 | } |
||
289 | $list[$shortbase] = md5( serialize( $list[$shortbase] ) ); |
||
290 | if ( !$recursive ) |
||
291 | return $list; |
||
292 | foreach ( $directories as $dir ) { |
||
293 | $this->dir_checksum( $dir, $list, $recursive ); |
||
294 | } |
||
295 | return $list; |
||
296 | } |
||
297 | |||
298 | function scan_dir( $path ) { |
||
299 | $files = array(); |
||
300 | |||
301 | if ( false === is_readable( $path ) ) { |
||
302 | return array(); |
||
303 | } |
||
304 | |||
305 | $dh = opendir( $path ); |
||
306 | |||
307 | if ( false === $dh ) { |
||
308 | return array(); |
||
309 | } |
||
310 | |||
311 | while ( false !== ( $file = readdir( $dh ) ) ) { |
||
312 | if ( $file == '.' || $file == '..' ) continue; |
||
313 | $files[] = "$path/$file"; |
||
314 | } |
||
315 | |||
316 | closedir( $dh ); |
||
317 | sort( $files ); |
||
318 | return $files; |
||
319 | } |
||
320 | } |
||
321 |
If you suppress an error, we recommend checking for the error condition explicitly: