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
$file
stringrequired- Full path and filename of ZIP archive.
$to
stringrequired- Full path on the filesystem to extract archive to.
$needed_dirs
string[]optional- A partial list of required folders needed to be created.
Default:
array()
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. |
User Contributed Notes
You must log in before being able to contribute a note or feedback.