$this->privSwapBackMagicQuotes();
PclZip::privErrorLog(PCLZIP_ERR_INVALID_ARCHIVE_ZIP, 'Invalid archive size');
return PclZip::errorCode();
// ----- Look for extraction as string
if ($p_options[PCLZIP_OPT_EXTRACT_AS_STRING]) {
// ----- Extracting the file
$v_result1 = $this->privExtractFileAsString($v_header, $v_string, $p_options);
$this->privSwapBackMagicQuotes();
// ----- Get the only interesting attributes
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted])) != 1)
// ----- Close the zip file
$this->privSwapBackMagicQuotes();
// ----- Set the file content
$p_file_list[$v_nb_extracted]['content'] = $v_string;
// ----- Next extracted file
// ----- Look for user callback abort
// ----- Look for extraction in standard output
elseif ( (isset($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT]))
&& ($p_options[PCLZIP_OPT_EXTRACT_IN_OUTPUT])) {
// ----- Extracting the file in standard output
$v_result1 = $this->privExtractFileInOutput($v_header, $p_options);
$this->privSwapBackMagicQuotes();
// ----- Get the only interesting attributes
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1) {
$this->privSwapBackMagicQuotes();
// ----- Look for user callback abort
// ----- Look for normal extraction
// ----- Extracting the file
$v_result1 = $this->privExtractFile($v_header,
$this->privSwapBackMagicQuotes();
// ----- Get the only interesting attributes
if (($v_result = $this->privConvertHeader2FileInfo($v_header, $p_file_list[$v_nb_extracted++])) != 1)
// ----- Close the zip file
$this->privSwapBackMagicQuotes();
// ----- Look for user callback abort
// ----- Close the zip file
$this->privSwapBackMagicQuotes();
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privExtractFile()
// PCLZIP_ERR_USER_ABORTED(2) : User ask for extraction stop in callback
// --------------------------------------------------------------------------------
function privExtractFile(&$p_entry, $p_path, $p_reCopy_path, $p_reCopy_all_path, &$p_options)
// ----- Read the file header
if (($v_result = $this->privReadFileHeader($v_header)) != 1)
// ----- Check that the file header is coherent with $p_entry info
if ($this->privCheckFileHeaders($v_header, $p_entry) != 1) {
// ----- Look for all path to reCopy
if ($p_reCopy_all_path == true) {
// ----- Look for folder entry that not need to be extracted
if (($p_entry['external']&0x00000010)==0x00000010) {
$p_entry['status'] = "filtered";
// ----- Get the basename of the path
$p_entry['filename'] = basename($p_entry['filename']);
// ----- Look for path to reCopy
else if ($p_reCopy_path != "")
if (PclZipUtilPathInclusion($p_reCopy_path, $p_entry['filename']) == 2)
// ----- Change the file status
$p_entry['status'] = "filtered";
$p_reCopy_path_size = strlen($p_reCopy_path);
if (substr($p_entry['filename'], 0, $p_reCopy_path_size) == $p_reCopy_path)
$p_entry['filename'] = substr($p_entry['filename'], $p_reCopy_path_size);
$p_entry['filename'] = $p_path."/".$p_entry['filename'];
// ----- Check a base_dir_restriction
if (isset($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION])) {
= PclZipUtilPathInclusion($p_options[PCLZIP_OPT_EXTRACT_DIR_RESTRICTION],
PclZip::privErrorLog(PCLZIP_ERR_DIRECTORY_RESTRICTION,
"Filename '".$p_entry['filename']."' is "
."outside PCLZIP_OPT_EXTRACT_DIR_RESTRICTION");
return PclZip::errorCode();
// ----- Look for pre-extract callback
if (isset($p_options[PCLZIP_CB_PRE_EXTRACT])) {
// ----- Generate a local information
$v_local_header = array();
$this->privConvertHeader2FileInfo($p_entry, $v_local_header);
// ----- Call the callback
// Here I do not use call_user_func() because I need to send a reference to the
// eval('$v_result = '.$p_options[PCLZIP_CB_PRE_EXTRACT].'(PCLZIP_CB_PRE_EXTRACT, $v_local_header);');
$v_result = $p_options[PCLZIP_CB_PRE_EXTRACT](PCLZIP_CB_PRE_EXTRACT, $v_local_header);
// ----- Change the file status
$p_entry['status'] = "skipped";
// ----- Look for abort result
// ----- This status is internal and will be changed in 'skipped'
$p_entry['status'] = "aborted";
$v_result = PCLZIP_ERR_USER_ABORTED;
// ----- Update the informations
// Only some fields can be modified
$p_entry['filename'] = $v_local_header['filename'];
// ----- Look if extraction should be done
if ($p_entry['status'] == 'ok') {
// ----- Look for specific actions while the file exist
if (file_exists($p_entry['filename']))
// ----- Look if file is a directory
if (is_dir($p_entry['filename']))
// ----- Change the file status
$p_entry['status'] = "already_a_directory";
// ----- Look for PCLZIP_OPT_STOP_ON_ERROR
// For historical reason first PclZip implementation does not stop
// when this kind of error occurs.
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
PclZip::privErrorLog(PCLZIP_ERR_ALREADY_A_DIRECTORY,
"Filename '".$p_entry['filename']."' is "
."already used by an existing directory");
return PclZip::errorCode();
// ----- Look if file is write protected
else if (!is_writeable($p_entry['filename']))
// ----- Change the file status
$p_entry['status'] = "write_protected";
// ----- Look for PCLZIP_OPT_STOP_ON_ERROR
// For historical reason first PclZip implementation does not stop
// when this kind of error occurs.
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
"Filename '".$p_entry['filename']."' exists "
."and is write protected");
return PclZip::errorCode();
// ----- Look if the extracted file is older
else if (filemtime($p_entry['filename']) > $p_entry['mtime'])
// ----- Change the file status
if ( (isset($p_options[PCLZIP_OPT_REPLACE_NEWER]))
&& ($p_options[PCLZIP_OPT_REPLACE_NEWER]===true)) {
$p_entry['status'] = "newer_exist";
// ----- Look for PCLZIP_OPT_STOP_ON_ERROR
// For historical reason first PclZip implementation does not stop
// when this kind of error occurs.
if ( (isset($p_options[PCLZIP_OPT_STOP_ON_ERROR]))
&& ($p_options[PCLZIP_OPT_STOP_ON_ERROR]===true)) {
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL,
"Newer version of '".$p_entry['filename']."' exists "
."and option PCLZIP_OPT_REPLACE_NEWER is not selected");
return PclZip::errorCode();
// ----- Check the directory availability and create it if necessary
if ((($p_entry['external']&0x00000010)==0x00000010) || (substr($p_entry['filename'], -1) == '/'))
$v_dir_to_check = $p_entry['filename'];
else if (!strstr($p_entry['filename'], "/"))
$v_dir_to_check = dirname($p_entry['filename']);
if (($v_result = $this->privDirCheck($v_dir_to_check, (($p_entry['external']&0x00000010)==0x00000010))) != 1) {
// ----- Change the file status
$p_entry['status'] = "path_creation_fail";
// ----- Look if extraction should be done
if ($p_entry['status'] == 'ok') {
// ----- Do the extraction (if not a folder)
if (!(($p_entry['external']&0x00000010)==0x00000010))
// ----- Look for not compressed file
if ($p_entry['compression'] == 0) {
// ----- Opening destination file
if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0)
// ----- Change the file status
$p_entry['status'] = "write_error";
// ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
$v_size = $p_entry['compressed_size'];
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = @fread($this->zip_fd, $v_read_size);
/* Try to speed up the code
$v_binary_data = pack('a'.$v_read_size, $v_buffer);
@fwrite($v_dest_file, $v_binary_data, $v_read_size);
@fwrite($v_dest_file, $v_buffer, $v_read_size);
// ----- Closing the destination file
// ----- Change the file mtime
touch($p_entry['filename'], $p_entry['mtime']);
if (($p_entry['flag'] & 1) == 1) {
PclZip::privErrorLog(PCLZIP_ERR_UNSUPPORTED_ENCRYPTION, 'File \''.$p_entry['filename'].'\' is encrypted. Encrypted files are not supported.');
return PclZip::errorCode();
// ----- Look for using temporary file to unzip
if ( (!isset($p_options[PCLZIP_OPT_TEMP_FILE_OFF]))
&& (isset($p_options[PCLZIP_OPT_TEMP_FILE_ON])
|| (isset($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD])
&& ($p_options[PCLZIP_OPT_TEMP_FILE_THRESHOLD] <= $p_entry['size'])) ) ) {
$v_result = $this->privExtractFileUsingTempFile($p_entry, $p_options);
if ($v_result < PCLZIP_ERR_NO_ERROR) {
// ----- Look for extract in memory
// ----- Read the compressed file in a buffer (one shot)
$v_buffer = @fread($this->zip_fd, $p_entry['compressed_size']);
// ----- Decompress the file
$v_file_content = @gzinflate($v_buffer);
if ($v_file_content === FALSE) {
// ----- Change the file status
$p_entry['status'] = "error";
// ----- Opening destination file
if (($v_dest_file = @fopen($p_entry['filename'], 'wb')) == 0) {
// ----- Change the file status
$p_entry['status'] = "write_error";
// ----- Write the uncompressed data
@fwrite($v_dest_file, $v_file_content, $p_entry['size']);
// ----- Closing the destination file
// ----- Change the file mtime
@touch($p_entry['filename'], $p_entry['mtime']);
// ----- Look for chmod option
if (isset($p_options[PCLZIP_OPT_SET_CHMOD])) {
// ----- Change the mode of the file
@chmod($p_entry['filename'], $p_options[PCLZIP_OPT_SET_CHMOD]);
// ----- Change abort status
if ($p_entry['status'] == "aborted") {
$p_entry['status'] = "skipped";
// ----- Look for post-extract callback
elseif (isset($p_options[PCLZIP_CB_POST_EXTRACT])) {
// ----- Generate a local information
$v_local_header = array();
$this->privConvertHeader2FileInfo($p_entry, $v_local_header);
// ----- Call the callback
// Here I do not use call_user_func() because I need to send a reference to the
// eval('$v_result = '.$p_options[PCLZIP_CB_POST_EXTRACT].'(PCLZIP_CB_POST_EXTRACT, $v_local_header);');
$v_result = $p_options[PCLZIP_CB_POST_EXTRACT](PCLZIP_CB_POST_EXTRACT, $v_local_header);
// ----- Look for abort result
$v_result = PCLZIP_ERR_USER_ABORTED;
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privExtractFileUsingTempFile()
// --------------------------------------------------------------------------------
function privExtractFileUsingTempFile(&$p_entry, &$p_options)
// ----- Creates a temporary file
$v_gzip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.gz';
if (($v_dest_file = @fopen($v_gzip_temp_name, "wb")) == 0) {
PclZip::privErrorLog(PCLZIP_ERR_WRITE_OPEN_FAIL, 'Unable to open temporary file \''.$v_gzip_temp_name.'\' in binary write mode');
return PclZip::errorCode();
// ----- Write gz file format header
$v_binary_data = pack('va1a1Va1a1', 0x8b1f, Chr($p_entry['compression']), Chr(0x00), time(), Chr(0x00), Chr(3));
@fwrite($v_dest_file, $v_binary_data, 10);
// ----- Read the file by PCLZIP_READ_BLOCK_SIZE octets blocks
$v_size = $p_entry['compressed_size'];
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = @fread($this->zip_fd, $v_read_size);
//$v_binary_data = pack('a'.$v_read_size, $v_buffer);
@fwrite($v_dest_file, $v_buffer, $v_read_size);
// ----- Write gz file format footer
$v_binary_data = pack('VV', $p_entry['crc'], $p_entry['size']);
@fwrite($v_dest_file, $v_binary_data, 8);