if (($p_is_dir) && (substr($p_dir, -1)=='/'))
$p_dir = substr($p_dir, 0, strlen($p_dir)-1);
// ----- Check the directory availability
if ((is_dir($p_dir)) || ($p_dir == ""))
// ----- Extract parent directory
$p_parent_dir = dirname($p_dir);
if ($p_parent_dir != $p_dir)
// ----- Look for parent directory
if (($v_result = $this->privDirCheck($p_parent_dir)) != 1)
// ----- Create the directory
if (!@mkdir($p_dir, 0777))
PclZip::privErrorLog(PCLZIP_ERR_DIR_CREATE_FAIL, "Unable to create directory '$p_dir'");
return PclZip::errorCode();
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privMerge()
// If $p_archive_to_add does not exist, the function exit with a success result.
// --------------------------------------------------------------------------------
function privMerge(&$p_archive_to_add)
// ----- Look if the archive_to_add exists
if (!is_file($p_archive_to_add->zipname))
// ----- Nothing to merge, so merge is a success
// ----- Look if the archive exists
if (!is_file($this->zipname))
$v_result = $this->privDuplicate($p_archive_to_add->zipname);
// ----- Open the zip file
if (($v_result=$this->privOpenFd('rb')) != 1)
// ----- Read the central directory informations
$v_central_dir = array();
if (($v_result = $this->privReadEndCentralDir($v_central_dir)) != 1)
// ----- Go to beginning of File
// ----- Open the archive_to_add file
if (($v_result=$p_archive_to_add->privOpenFd('rb')) != 1)
// ----- Read the central directory informations
$v_central_dir_to_add = array();
if (($v_result = $p_archive_to_add->privReadEndCentralDir($v_central_dir_to_add)) != 1)
$p_archive_to_add->privCloseFd();
// ----- Go to beginning of File
@rewind($p_archive_to_add->zip_fd);
// ----- Creates a temporay file
$v_zip_temp_name = PCLZIP_TEMPORARY_DIR.uniqid('pclzip-').'.tmp';
// ----- Open the temporary file in write mode
if (($v_zip_temp_fd = @fopen($v_zip_temp_name, 'wb')) == 0)
$p_archive_to_add->privCloseFd();
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open temporary file \''.$v_zip_temp_name.'\' in binary write mode');
return PclZip::errorCode();
// ----- Copy the files from the archive to the temporary file
// TBC : Here I should better append the file and go back to erase the central dir
$v_size = $v_central_dir['offset'];
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = fread($this->zip_fd, $v_read_size);
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
// ----- Copy the files from the archive_to_add into the temporary file
$v_size = $v_central_dir_to_add['offset'];
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = fread($p_archive_to_add->zip_fd, $v_read_size);
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
// ----- Store the offset of the central dir
$v_offset = @ftell($v_zip_temp_fd);
// ----- Copy the block of file headers from the old archive
$v_size = $v_central_dir['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);
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
// ----- Copy the block of file headers from the archive_to_add
$v_size = $v_central_dir_to_add['size'];
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = @fread($p_archive_to_add->zip_fd, $v_read_size);
@fwrite($v_zip_temp_fd, $v_buffer, $v_read_size);
// ----- Merge the file comments
$v_comment = $v_central_dir['comment'].' '.$v_central_dir_to_add['comment'];
// ----- Calculate the size of the (new) central header
$v_size = @ftell($v_zip_temp_fd)-$v_offset;
// ----- Swap the file descriptor
// Here is a trick : I swap the temporary fd with the zip fd, in order to use
// the following methods on the temporary fil and not the real archive fd
$this->zip_fd = $v_zip_temp_fd;
$v_zip_temp_fd = $v_swap;
// ----- Create the central dir footer
if (($v_result = $this->privWriteCentralHeader($v_central_dir['entries']+$v_central_dir_to_add['entries'], $v_size, $v_offset, $v_comment)) != 1)
$p_archive_to_add->privCloseFd();
// ----- Reset the file list
// ----- Swap back the file descriptor
$this->zip_fd = $v_zip_temp_fd;
$v_zip_temp_fd = $v_swap;
$p_archive_to_add->privCloseFd();
// ----- Close the temporary file
// ----- Delete the zip file
// TBC : I should test the result ...
// ----- Rename the temporary file
// TBC : I should test the result ...
//@rename($v_zip_temp_name, $this->zipname);
PclZipUtilRename($v_zip_temp_name, $this->zipname);
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privDuplicate()
// --------------------------------------------------------------------------------
function privDuplicate($p_archive_filename)
// ----- Look if the $p_archive_filename exists
if (!is_file($p_archive_filename))
// ----- Nothing to duplicate, so duplicate is a success.
// ----- Open the zip file
if (($v_result=$this->privOpenFd('wb')) != 1)
// ----- Open the temporary file in write mode
if (($v_zip_temp_fd = @fopen($p_archive_filename, 'rb')) == 0)
PclZip::privErrorLog(PCLZIP_ERR_READ_OPEN_FAIL, 'Unable to open archive file \''.$p_archive_filename.'\' in binary write mode');
return PclZip::errorCode();
// ----- Copy the files from the archive to the temporary file
// TBC : Here I should better append the file and go back to erase the central dir
$v_size = filesize($p_archive_filename);
$v_read_size = ($v_size < PCLZIP_READ_BLOCK_SIZE ? $v_size : PCLZIP_READ_BLOCK_SIZE);
$v_buffer = fread($v_zip_temp_fd, $v_read_size);
@fwrite($this->zip_fd, $v_buffer, $v_read_size);
// ----- Close the temporary file
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privErrorLog()
// --------------------------------------------------------------------------------
function privErrorLog($p_error_code=0, $p_error_string='')
if (PCLZIP_ERROR_EXTERNAL == 1) {
PclError($p_error_code, $p_error_string);
$this->error_code = $p_error_code;
$this->error_string = $p_error_string;
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privErrorReset()
// --------------------------------------------------------------------------------
function privErrorReset()
if (PCLZIP_ERROR_EXTERNAL == 1) {
$this->error_string = '';
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privDisableMagicQuotes()
// --------------------------------------------------------------------------------
function privDisableMagicQuotes()
// ----- Look if function exists
if ( (!function_exists("get_magic_quotes_runtime"))
|| (!function_exists("set_magic_quotes_runtime"))) {
// ----- Look if already done
if ($this->magic_quotes_status != -1) {
// ----- Get and memorize the magic_quote value
$this->magic_quotes_status = @get_magic_quotes_runtime();
// ----- Disable magic_quotes
if ($this->magic_quotes_status == 1) {
@set_magic_quotes_runtime(0);
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : privSwapBackMagicQuotes()
// --------------------------------------------------------------------------------
function privSwapBackMagicQuotes()
// ----- Look if function exists
if ( (!function_exists("get_magic_quotes_runtime"))
|| (!function_exists("set_magic_quotes_runtime"))) {
// ----- Look if something to do
if ($this->magic_quotes_status != -1) {
// ----- Swap back magic_quotes
if ($this->magic_quotes_status == 1) {
@set_magic_quotes_runtime($this->magic_quotes_status);
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : PclZipUtilPathReduction()
// --------------------------------------------------------------------------------
function PclZipUtilPathReduction($p_dir)
// ----- Look for not empty path
// ----- Explode path by directory names
$v_list = explode("/", $p_dir);
// ----- Study directories from last to first
for ($i=sizeof($v_list)-1; $i>=0; $i--) {
// ----- Look for current path
if ($v_list[$i] == ".") {
// ----- Ignore this directory
// Should be the first $i=0, but no check is done
else if ($v_list[$i] == "..") {
else if ($v_list[$i] == "") {
// ----- First '/' i.e. root slash
$v_result = "/".$v_result;
// ----- It is an invalid path, so the path is not modified
// ----- Last '/' i.e. indicates a directory
else if ($i == (sizeof($v_list)-1)) {
// ----- Double '/' inside the path
// ----- Ignore only the double '//' in path,
// but not the first and last '/'
// ----- Look for item to skip
$v_result = $v_list[$i].($i!=(sizeof($v_list)-1)?"/".$v_result:"");
$v_result = '../'.$v_result;
// --------------------------------------------------------------------------------
// --------------------------------------------------------------------------------
// Function : PclZipUtilPathInclusion()
// This function indicates if the path $p_path is under the $p_dir tree. Or,
// said in an other way, if the file or sub-dir $p_path is inside the dir
// The function indicates also if the path is exactly the same as the dir.
// This function supports path with duplicated '/' like '//', but does not
// support '.' or '..' statements.
// 0 if $p_path is not inside directory $p_dir
// 1 if $p_path is inside directory $p_dir
// 2 if $p_path is exactly the same as $p_dir
// --------------------------------------------------------------------------------
function PclZipUtilPathInclusion($p_dir, $p_path)
// ----- Look for path beginning by ./
|| ((strlen($p_dir) >=2) && (substr($p_dir, 0, 2) == './'))) {
$p_dir = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_dir, 1);
|| ((strlen($p_path) >=2) && (substr($p_path, 0, 2) == './'))) {
$p_path = PclZipUtilTranslateWinPath(getcwd(), FALSE).'/'.substr($p_path, 1);
// ----- Explode dir and path by directory separator
$v_list_dir = explode("/", $p_dir);
$v_list_dir_size = sizeof($v_list_dir);
$v_list_path = explode("/", $p_path);
$v_list_path_size = sizeof($v_list_path);
// ----- Study directories paths