PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/traits/io.php +70 -32 5.3.1 → 6.3.0 View file →
@@ -10,8 +10,9 @@
10 10 use RecursiveIteratorIterator;
11 11 use RecursiveDirectoryIterator;
12 12 use WP_Defender\Helper\File as File_Helper;
13 13 use WP_Defender\Component\Logger\Rotation_Logger as Logger;
14 +use WP_Filesystem_Base;
14 15
15 16 trait IO {
16 17
17 18 /**
@@ -24,9 +25,9 @@
24 25 */
25 26 protected function get_tmp_path( bool $main_site_path = false ): string {
26 27 global $wp_filesystem;
27 28 // Initialize the WP filesystem, no more using 'file-put-contents' function.
28 - if ( empty( $wp_filesystem ) ) {
29 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
29 30 require_once ABSPATH . '/wp-admin/includes/file.php';
30 31 WP_Filesystem();
31 32 }
32 33 $is_switch_to_main_site = $main_site_path && is_multisite() && ! is_main_site();
@@ -64,9 +65,9 @@
64 65 *
65 66 * @return string The path to the log file.
66 67 */
67 68 public function get_log_path( $category = '' ): string {
68 - $file = empty( $category ) ? wd_internal_log() : $category;
69 + $file = '' === $category ? wd_internal_log() : $category;
69 70
70 71 $logger = new Logger();
71 72 $file_name = $logger->generate_file_name( $file );
72 73
@@ -91,9 +92,9 @@
91 92 */
92 93 public function delete_dir( $dir ): bool {
93 94 global $wp_filesystem;
94 95 // Initialize the WP filesystem, no more using 'file-put-contents' function.
95 - if ( empty( $wp_filesystem ) ) {
96 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
96 97 require_once ABSPATH . '/wp-admin/includes/file.php';
97 98 WP_Filesystem();
98 99 }
99 100 if ( ! is_dir( $dir ) ) {
@@ -149,9 +150,10 @@
149 150 *
150 151 * @return bool
151 152 */
152 153 protected function compare_hashes_on_different_os( $file_path, $file_hash ) {
153 - if ( hash_equals( md5_file( $file_path ), $file_hash ) ) {
154 + $hashed_file = md5_file( $file_path );
155 + if ( false !== $hashed_file && hash_equals( $hashed_file, $file_hash ) ) {
154 156 return true;
155 157 }
156 158 if ( hash_equals( $this->hash_file( $file_path, 'linux' ), $file_hash ) ) {
157 159 return true;
@@ -176,9 +178,9 @@
176 178 return $this->compare_hashes_on_different_os( $file_path, $file_hash );
177 179 } elseif ( is_array( $file_hash ) ) {
178 180 // Sometimes file has some hashes.
179 181 foreach ( $file_hash as $hash_value ) {
180 - if ( $this->compare_hashes_on_different_os( $file_path, $hash_value ) ) {
182 + if ( is_string( $hash_value ) && $this->compare_hashes_on_different_os( $file_path, $hash_value ) ) {
181 183 return true;
182 184 }
183 185 }
184 186
@@ -199,9 +201,9 @@
199 201 */
200 202 protected function hash_file( string $file_path, string $convert_to = '' ) {
201 203 global $wp_filesystem;
202 204 // Initialize the WP filesystem, no more using 'file-put-contents' function.
203 - if ( empty( $wp_filesystem ) ) {
205 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
204 206 require_once ABSPATH . '/wp-admin/includes/file.php';
205 207 WP_Filesystem();
206 208 }
207 209 if ( ! file_exists( $file_path ) ) {
@@ -224,58 +226,73 @@
224 226
225 227 /**
226 228 * Retrieves the lock file path used in scanning.
227 229 *
230 + * @param string $lock_filename The lock file name.
231 + *
228 232 * @return string The lock file path.
229 233 *
230 234 * @throws \RuntimeException If the lock file name is not defined.
231 235 */
232 - protected function get_lock_path(): string {
233 - if ( empty( $this->lock_filename ) ) {
236 + protected function get_lock_path( string $lock_filename ): string {
237 + if ( '' === $lock_filename ) {
234 238 throw new \RuntimeException( 'Lock file name must be defined in the class using IO trait.' );
235 239 }
236 240
237 - return $this->get_tmp_path() . DIRECTORY_SEPARATOR . $this->lock_filename;
241 + return $this->get_tmp_path() . DIRECTORY_SEPARATOR . $lock_filename;
238 242 }
239 243
240 244 /**
241 - * Create a file lock, so we can check if a process already running.
242 - */
243 - public function create_lock() {
244 - $this->remove_lock();
245 - file_put_contents( $this->get_lock_path(), time(), LOCK_EX ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
246 - }
247 -
248 - /**
249 245 * Delete file lock.
246 + *
247 + * @param string $lock_filename The lock file name.
250 248 */
251 - public function remove_lock() {
252 - if ( file_exists( $this->get_lock_path() ) ) {
253 - wp_delete_file( $this->get_lock_path() );
249 + public function remove_lock( string $lock_filename ) {
250 + $lock_path = $this->get_lock_path( $lock_filename );
251 + if ( file_exists( $lock_path ) ) {
252 + wp_delete_file( $lock_path );
254 253 }
255 254 }
256 255
257 256 /**
258 - * Check if a lock is valid.
257 + * Atomically acquire a file lock.
259 258 *
260 - * @return bool
259 + * @param string $lock_filename The lock filename.
260 + *
261 + * @return bool True when the lock is acquired.
261 262 */
262 - public function has_lock(): bool {
263 + public function try_create_lock( string $lock_filename ): bool {
263 264 global $wp_filesystem;
264 - // Initialize the WP filesystem, no more using 'file-put-contents' function.
265 - if ( empty( $wp_filesystem ) ) {
265 +
266 + if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) {
266 267 require_once ABSPATH . '/wp-admin/includes/file.php';
267 268 WP_Filesystem();
268 269 }
269 - if ( ! file_exists( $this->get_lock_path() ) ) {
270 - return false;
270 +
271 + $lock_path = $this->get_lock_path( $lock_filename );
272 +
273 + if ( is_file( $lock_path ) ) {
274 + $time = (int) $wp_filesystem->get_contents( $lock_path );
275 +
276 + // Existing lock is still valid.
277 + if ( ( $time + 90 ) >= time() ) {
278 + return false;
279 + }
280 +
281 + // Remove stale lock.
282 + wp_delete_file( $lock_path );
271 283 }
272 - $time = $wp_filesystem->get_contents( $this->get_lock_path() );
273 - if ( strtotime( '+90 seconds', $time ) < time() ) {
274 - // Usually a timeout window is 30 seconds, so we should allow lock at 1.30min for safe.
284 +
285 + $handle = @fopen( $lock_path, 'x' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen, WordPress.PHP.NoSilencedErrors.Discouraged
286 +
287 + if ( false === $handle ) {
288 + // Another process acquired the lock.
275 289 return false;
276 290 }
277 291
292 + fwrite( $handle, (string) time() ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
293 + fclose( $handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
294 +
278 295 return true;
279 296 }
280 297
281 298 /**
@@ -312,10 +329,10 @@
312 329 return false;
313 330 }
314 331
315 332 // Check if another process is running.
316 - $lock_time = get_site_option( $lock_key, 0 );
317 - if ( $lock_time && ( $now < $lock_time + $lock_duration ) ) {
333 + $lock_time = (int) get_site_option( $lock_key, 0 );
334 + if ( $lock_time > 0 && ( $now < $lock_time + $lock_duration ) ) {
318 335 return false;
319 336 }
320 337
321 338 // Acquire the lock.
@@ -334,6 +351,27 @@
334 351 $lock_key = "{$event}_lock";
335 352 $last_run_key = "{$event}_last_run";
336 353 update_site_option( $last_run_key, time() );
337 354 delete_site_option( $lock_key );
355 + }
356 +
357 + /**
358 + * Detect the line ending style used in a given text.
359 + *
360 + * @param string $text The text to analyze.
361 + *
362 + * @return string The detected line ending style: "\r\n" for Windows, "\n" for Unix, or "\r" for Classic Mac.
363 + */
364 + public function detect_line_ending( string $text ): string {
365 + $count_crlf = substr_count( $text, "\r\n" );
366 + $count_lf = substr_count( $text, "\n" ) - $count_crlf;
367 + $count_cr = substr_count( $text, "\r" ) - $count_crlf;
368 +
369 + if ( $count_crlf >= $count_lf && $count_crlf >= $count_cr ) {
370 + return "\r\n"; // Windows-style.
371 + } elseif ( $count_lf >= $count_cr ) {
372 + return "\n"; // Unix-style.
373 + } else {
374 + return "\r"; // Classic Mac (rare).
375 + }
338 376 }
339 377 }