函数文档

_unzip_file_pclzip()

💡 云策文档标注

概述

_unzip_file_pclzip() 是一个内部函数,用于通过 PclZip 库解压 ZIP 归档文件。它不应直接调用,而应使用 unzip_file() 函数。该函数假设 WP_Filesystem() 已初始化,并处理文件提取、目录创建和错误检查。

关键要点

  • 函数不应直接调用,推荐使用 unzip_file() 作为替代。
  • 需要 WP_Filesystem() 已设置,依赖全局变量 $wp_filesystem。
  • 参数包括 $file(ZIP 文件路径)、$to(解压目标路径)和可选的 $needed_dirs(所需目录数组)。
  • 返回 true 表示成功,或 WP_Error 对象表示失败。
  • 函数内部使用 PclZip 类提取文件,跳过 __MACOSX/ 目录,并验证文件有效性。
  • 检查磁盘空间(在 cron 请求中),确保有足够空间解压文件(带 10% 缓冲)。
  • 创建必要的目录结构,使用 $wp_filesystem->mkdir() 和 $wp_filesystem->put_contents() 操作文件系统。
  • 包含过滤器:pre_unzip_file 和 unzip_file,允许自定义解压过程。

代码示例

function _unzip_file_pclzip( $file, $to, $needed_dirs = array() ) {
	global $wp_filesystem;

	mbstring_binary_safe_encoding();

	require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';

	$archive = new PclZip( $file );

	$archive_files = $archive->extract( PCLZIP_OPT_EXTRACT_AS_STRING );

	reset_mbstring_encoding();

	// 检查归档有效性
	if ( ! is_array( $archive_files ) ) {
		return new WP_Error( 'incompatible_archive', __( 'Incompatible Archive.' ), $archive->errorInfo( true ) );
	}

	if ( 0 === count( $archive_files ) ) {
		return new WP_Error( 'empty_archive_pclzip', __( 'Empty archive.' ) );
	}

	// 更多代码...
}

注意事项

  • 函数是内部实现,直接调用可能导致兼容性问题,应通过 unzip_file() 使用。
  • 在 cron 请求中会检查磁盘空间,其他情况下可能跳过此检查。
  • 使用过滤器 pre_unzip_file 和 unzip_file 可以干预解压过程,例如提前返回或修改结果。
  • 错误处理返回 WP_Error 对象,包含特定错误代码和消息,便于调试。

📄 原文内容

Attempts to unzip an archive using the PclZip library.

Description

This function should not be called directly, use unzip_file() instead.

Assumes that WP_Filesystem() has already been called and set up.

See also

Parameters

$filestringrequired
Full path and filename of ZIP archive.
$tostringrequired
Full path on the filesystem to extract archive to.
$needed_dirsstring[]optional
A partial list of required folders needed to be created.

Default:array()

Return

true|WP_Error True on success, WP_Error on failure.

Source

function _unzip_file_pclzip( $file, $to, $needed_dirs = array() ) {
	global $wp_filesystem;

	mbstring_binary_safe_encoding();

	require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';

	$archive = new PclZip( $file );

	$archive_files = $archive->extract( PCLZIP_OPT_EXTRACT_AS_STRING );

	reset_mbstring_encoding();

	// Is the archive valid?
	if ( ! is_array( $archive_files ) ) {
		return new WP_Error( 'incompatible_archive', __( 'Incompatible Archive.' ), $archive->errorInfo( true ) );
	}

	if ( 0 === count( $archive_files ) ) {
		return new WP_Error( 'empty_archive_pclzip', __( 'Empty archive.' ) );
	}

	$uncompressed_size = 0;

	// Determine any children directories needed (From within the archive).
	foreach ( $archive_files as $file ) {
		if ( str_starts_with( $file['filename'], '__MACOSX/' ) ) { // Skip the OS X-created __MACOSX directory.
			continue;
		}

		$uncompressed_size += $file['size'];

		$needed_dirs[] = $to . untrailingslashit( $file['folder'] ? $file['filename'] : dirname( $file['filename'] ) );
	}

	// Enough space to unzip the file and copy its contents, with a 10% buffer.
	$required_space = $uncompressed_size * 2.1;

	/*
	 * disk_free_space() could return false. Assume that any falsey value is an error.
	 * A disk that has zero free bytes has bigger problems.
	 * Require we have enough space to unzip the file and copy its contents, with a 10% buffer.
	 */
	if ( wp_doing_cron() ) {
		$available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( WP_CONTENT_DIR ) : false;

		if ( $available_space && ( $required_space > $available_space ) ) {
			return new WP_Error(
				'disk_full_unzip_file',
				__( 'Could not copy files. You may have run out of disk space.' ),
				compact( 'uncompressed_size', 'available_space' )
			);
		}
	}

	$needed_dirs = array_unique( $needed_dirs );

	foreach ( $needed_dirs as $dir ) {
		// Check the parent folders of the folders all exist within the creation array.
		if ( untrailingslashit( $to ) === $dir ) { // Skip over the working directory, we know this exists (or will exist).
			continue;
		}

		if ( ! str_contains( $dir, $to ) ) { // If the directory is not within the working directory, skip it.
			continue;
		}

		$parent_folder = dirname( $dir );

		while ( ! empty( $parent_folder )
			&& untrailingslashit( $to ) !== $parent_folder
			&& ! in_array( $parent_folder, $needed_dirs, true )
		) {
			$needed_dirs[] = $parent_folder;
			$parent_folder = dirname( $parent_folder );
		}
	}

	asort( $needed_dirs );

	// Create those directories if need be:
	foreach ( $needed_dirs as $_dir ) {
		// Only check to see if the dir exists upon creation failure. Less I/O this way.
		if ( ! $wp_filesystem->mkdir( $_dir, FS_CHMOD_DIR ) && ! $wp_filesystem->is_dir( $_dir ) ) {
			return new WP_Error( 'mkdir_failed_pclzip', __( 'Could not create directory.' ), $_dir );
		}
	}

	/** This filter is documented in src/wp-admin/includes/file.php */
	$pre = apply_filters( 'pre_unzip_file', null, $file, $to, $needed_dirs, $required_space );

	if ( null !== $pre ) {
		return $pre;
	}

	// Extract the files from the zip.
	foreach ( $archive_files as $file ) {
		if ( $file['folder'] ) {
			continue;
		}

		if ( str_starts_with( $file['filename'], '__MACOSX/' ) ) { // Don't extract the OS X-created __MACOSX directory files.
			continue;
		}

		// Don't extract invalid files:
		if ( 0 !== validate_file( $file['filename'] ) ) {
			continue;
		}

		if ( ! $wp_filesystem->put_contents( $to . $file['filename'], $file['content'], FS_CHMOD_FILE ) ) {
			return new WP_Error( 'copy_failed_pclzip', __( 'Could not copy file.' ), $file['filename'] );
		}
	}

	/** This action is documented in src/wp-admin/includes/file.php */
	$result = apply_filters( 'unzip_file', true, $file, $to, $needed_dirs, $required_space );

	unset( $needed_dirs );

	return $result;
}

Hooks

apply_filters( ‘pre_unzip_file’, null|true|WP_Error $result, string $file, string $to, string[] $needed_dirs, float $required_space )

Filters archive unzipping to override with a custom process.

apply_filters( ‘unzip_file’, true|WP_Error $result, string $file, string $to, string[] $needed_dirs, float $required_space )

Filters the result of unzipping an archive.

Changelog

Version Description
3.0.0 Introduced.