query( $wpdb->prepare( "INSERT IGNORE INTO %i (option_name, option_value, autoload) VALUES (%s, %s, 'no')", $wpdb->options, $option, $value ) ); if ( $inserted ) { wp_cache_delete( $option, 'options' ); wp_cache_delete( 'notoptions', 'options' ); return $token; } // Break stale lock. // phpcs:ignore WordPress.DB.DirectDatabaseQuery $current = $wpdb->get_var( $wpdb->prepare( 'SELECT option_value FROM %i WHERE option_name = %s', $wpdb->options, $option ) ); if ( is_string( $current ) ) { $parts = explode( '|', $current, 2 ); if ( (int) $parts[0] < time() ) { // Compare-and-swap so two workers cannot both break the same stale lock. // phpcs:ignore WordPress.DB.DirectDatabaseQuery $updated = $wpdb->query( $wpdb->prepare( 'UPDATE %i SET option_value = %s WHERE option_name = %s AND option_value = %s', $wpdb->options, $value, $option, $current ) ); if ( $updated ) { wp_cache_delete( $option, 'options' ); return $token; } } } return false; } /** * Release a lock if we still own it. * * @param string $name Lock name. * @param string $token Token from acquire(). */ public static function release( $name, $token ) { global $wpdb; $option = self::PREFIX . sanitize_key( $name ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE option_name = %s AND option_value LIKE %s', $wpdb->options, $option, '%|' . $wpdb->esc_like( $token ) ) ); wp_cache_delete( $option, 'options' ); } /** * Remove all plugin locks (deactivation/uninstall). */ public static function release_all() { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE option_name LIKE %s', $wpdb->options, $wpdb->esc_like( self::PREFIX ) . '%' ) ); } }