= (int) @filemtime( $src ); } /** * Copy the source to the destination via a unique per-request temp file. * * @param string $src Source path. * @param string $dst Destination path. */ private static function install( $src, $dst ) { $dir = dirname( $dst ); if ( ! is_dir( $dir ) && ! wp_mkdir_p( $dir ) ) { return; } // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable if ( ! is_writable( $dir ) ) { return; } // Unique temp name per request, kept inside the target dir so the final // rename stays on one filesystem. Concurrent requests right after a // plugin update must not share one temp path and rename a half-written // file into place: MU plugins load on every request, so a truncated // drop-in would fatal the whole site. wp_rand() plus uniqid() stays // distinct across separate processes and threads of one process alike. $tmp = $dst . '.' . wp_rand() . '-' . uniqid( '', true ) . '.tmp'; // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged if ( ! @copy( $src, $tmp ) ) { // A failed copy may still leave a partial temp file; clean it up. // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink, WordPress.PHP.NoSilencedErrors.Discouraged @unlink( $tmp ); return; } // rename() is atomic within a filesystem, so readers see either the old // drop-in or the complete new one, never a partial write. // phpcs:ignore WordPress.WP.AlternativeFunctions.rename_rename, WordPress.PHP.NoSilencedErrors.Discouraged if ( ! @rename( $tmp, $dst ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink, WordPress.PHP.NoSilencedErrors.Discouraged @unlink( $tmp ); } } }