copy_dir()
云策文档标注
概述
copy_dir() 函数通过 WordPress 文件系统抽象层将目录从源位置复制到目标位置。它要求 WP_Filesystem() 已调用并设置,支持跳过特定文件或文件夹,并递归处理子目录。
关键要点
- 函数用途:复制目录,依赖 WordPress 文件系统抽象层(如 $wp_filesystem)进行操作。
- 参数说明:$from(源目录,字符串,必需),$to(目标目录,字符串,必需),$skip_list(跳过列表,字符串数组,可选,默认为空数组)。
- 返回值:成功时返回 true,失败时返回 WP_Error 对象。
- 前提条件:调用前需确保 WP_Filesystem() 已初始化,否则可能无法正常工作。
- 错误处理:包括目录列表失败、目标目录创建失败、文件复制失败等场景,均返回 WP_Error。
- 递归机制:自动处理子目录复制,并为子目录生成相应的 $sub_skip_list 以保持跳过逻辑。
- 文件类型处理:区分文件('f')和目录('d'),文件复制失败时会尝试更改权限后重试,并调用 wp_opcache_invalidate() 清除 opcode 缓存。
代码示例
// 连接到文件系统
if ( ! WP_Filesystem() ) {
// 无法连接到文件系统,可能需要 FTP 凭据等
// 可以使用 request_filesystem_credentials() 请求凭据
exit;
}
// 确保目标目录存在,如果不存在则创建
global $wp_filesystem;
$wp_filesystem->mkdir( $target_dir );
// 复制源目录中的所有文件到目标目录
copy_dir( $src_dir, $target_dir );注意事项
- 使用前必须调用 WP_Filesystem() 设置文件系统抽象,否则函数可能无法执行或出错。
- 目标目录需存在或可创建,否则复制会失败并返回 WP_Error。
- $skip_list 参数支持跳过特定文件或文件夹,对于子目录,函数会自动调整跳过列表以匹配路径。
- 复制文件时,如果首次失败,会尝试更改文件权限(chmod 到 FS_CHMOD_FILE)后重试,以提高兼容性。
- 函数递归处理目录,适用于嵌套结构,但需注意性能影响,尤其是在大型目录中。
- 相关函数包括 move_dir()、WP_Upgrader::install_package() 等,常用于 WordPress 核心升级和插件/主题安装场景。
原文内容
Copies a directory from one location to another via the WordPress Filesystem Abstraction.
Description
Assumes that WP_Filesystem() has already been called and setup.
Parameters
$fromstringrequired-
Source directory.
$tostringrequired-
Destination directory.
$skip_liststring[]optional-
An array of files/folders to skip copying.
Default:
array()
Source
function copy_dir( $from, $to, $skip_list = array() ) {
global $wp_filesystem;
$dirlist = $wp_filesystem->dirlist( $from );
if ( false === $dirlist ) {
return new WP_Error( 'dirlist_failed_copy_dir', __( 'Directory listing failed.' ), basename( $from ) );
}
$from = trailingslashit( $from );
$to = trailingslashit( $to );
if ( ! $wp_filesystem->exists( $to ) && ! $wp_filesystem->mkdir( $to ) ) {
return new WP_Error(
'mkdir_destination_failed_copy_dir',
__( 'Could not create the destination directory.' ),
basename( $to )
);
}
foreach ( (array) $dirlist as $filename => $fileinfo ) {
if ( in_array( $filename, $skip_list, true ) ) {
continue;
}
if ( 'f' === $fileinfo['type'] ) {
if ( ! $wp_filesystem->copy( $from . $filename, $to . $filename, true, FS_CHMOD_FILE ) ) {
// If copy failed, chmod file to 0644 and try again.
$wp_filesystem->chmod( $to . $filename, FS_CHMOD_FILE );
if ( ! $wp_filesystem->copy( $from . $filename, $to . $filename, true, FS_CHMOD_FILE ) ) {
return new WP_Error( 'copy_failed_copy_dir', __( 'Could not copy file.' ), $to . $filename );
}
}
wp_opcache_invalidate( $to . $filename );
} elseif ( 'd' === $fileinfo['type'] ) {
if ( ! $wp_filesystem->is_dir( $to . $filename ) ) {
if ( ! $wp_filesystem->mkdir( $to . $filename, FS_CHMOD_DIR ) ) {
return new WP_Error( 'mkdir_failed_copy_dir', __( 'Could not create directory.' ), $to . $filename );
}
}
// Generate the $sub_skip_list for the subdirectory as a sub-set of the existing $skip_list.
$sub_skip_list = array();
foreach ( $skip_list as $skip_item ) {
if ( str_starts_with( $skip_item, $filename . '/' ) ) {
$sub_skip_list[] = preg_replace( '!^' . preg_quote( $filename, '!' ) . '/!i', '', $skip_item );
}
}
$result = copy_dir( $from . $filename, $to . $filename, $sub_skip_list );
if ( is_wp_error( $result ) ) {
return $result;
}
}
}
return true;
}
Changelog
| Version | Description |
|---|---|
| 2.5.0 | Introduced. |
Skip to note 2 content
J.D. Grimes
// Connecting to the filesystem. if ( ! WP_Filesystem() ) { // Unable to connect to the filesystem, FTP credentials may be required or something. // You can request these with request_filesystem_credentials() exit; } // Don't forget that the target directory needs to exist. // If it doesn't already, you'll need to create it. global $wp_filesystem; $wp_filesystem->mkdir( $target_dir ); // Now copy all the files in the source directory to the target directory. copy_dir( $src_dir, $target_dir );