| @@ -241,18 +241,8 @@ | ||
| 241 | 241 | return $this->get_tmp_path() . DIRECTORY_SEPARATOR . $lock_filename; |
| 242 | 242 | } |
| 243 | 243 | |
| 244 | 244 | /** |
| 245 | - * Create a file lock, so we can check if a process already running. | |
| 246 | - * | |
| 247 | - * @param string $lock_filename The lock file name. | |
| 248 | - */ | |
| 249 | - public function create_lock( string $lock_filename ) { | |
| 250 | - $this->remove_lock( $lock_filename ); | |
| 251 | - file_put_contents( $this->get_lock_path( $lock_filename ), time(), LOCK_EX ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents | |
| 252 | - } | |
| 253 | - | |
| 254 | - /** | |
| 255 | 245 | * Delete file lock. |
| 256 | 246 | * |
| 257 | 247 | * @param string $lock_filename The lock file name. |
| 258 | 248 | */ |
| @@ -263,17 +253,17 @@ | ||
| 263 | 253 | } |
| 264 | 254 | } |
| 265 | 255 | |
| 266 | 256 | /** |
| 267 | - * Check if a lock is valid. | |
| 257 | + * Atomically acquire a file lock. | |
| 268 | 258 | * |
| 269 | - * @param string $lock_filename The lock file name. | |
| 259 | + * @param string $lock_filename The lock filename. | |
| 270 | 260 | * |
| 271 | - * @return bool | |
| 261 | + * @return bool True when the lock is acquired. | |
| 272 | 262 | */ |
| 273 | - public function has_lock( string $lock_filename ): bool { | |
| 263 | + public function try_create_lock( string $lock_filename ): bool { | |
| 274 | 264 | global $wp_filesystem; |
| 275 | - // Initialize the WP filesystem, no more using 'file-put-contents' function. | |
| 265 | + | |
| 276 | 266 | if ( ! $wp_filesystem instanceof WP_Filesystem_Base ) { |
| 277 | 267 | require_once ABSPATH . '/wp-admin/includes/file.php'; |
| 278 | 268 | WP_Filesystem(); |
| 279 | 269 | } |
| @@ -278,16 +268,30 @@ | ||
| 278 | 268 | WP_Filesystem(); |
| 279 | 269 | } |
| 280 | 270 | |
| 281 | 271 | $lock_path = $this->get_lock_path( $lock_filename ); |
| 282 | - if ( ! file_exists( $lock_path ) ) { | |
| 283 | - return false; | |
| 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 ); | |
| 284 | 283 | } |
| 285 | - $time = $wp_filesystem->get_contents( $lock_path ); | |
| 286 | - if ( strtotime( '+90 seconds', $time ) < time() ) { | |
| 287 | - // 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. | |
| 288 | 289 | return false; |
| 289 | 290 | } |
| 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 | |
| 290 | 294 | |
| 291 | 295 | return true; |
| 292 | 296 | } |
| 293 | 297 | |