• Модуль: main
  • Путь к файлу: ~/bitrix/modules/main/classes/general/zip.php
  • Класс: CZip
  • Вызов: CZip::_extractFile
private function _extractFile(&$arEntry, $path, $removePath, $removeAllPath, $arParams)
{
	if (($res = $this->_readFileHeader($header)) != 1)
	{
		return $res;
	}
	//to be checked: file header should be coherent with $arEntry info

	$arEntry["filename"] = BitrixMainTextEncoding::convertEncoding($arEntry["filename"], "cp866", $this->fileSystemEncoding);
	$arEntry["stored_filename"] = BitrixMainTextEncoding::convertEncoding($arEntry["stored_filename"], "cp866", $this->fileSystemEncoding);

	//protecting against ../ etc. in file path
	//only absolute path should be in the $arEntry
	$arEntry['filename'] = _normalizePath($arEntry['filename']);
	$arEntry['stored_filename'] = _normalizePath($arEntry['stored_filename']);

	if ($removeAllPath)
	{
		$arEntry['filename'] = basename($arEntry['filename']);
	}
	else
	{
		if ($removePath != "")
		{
			if ($this->_containsPath($removePath, $arEntry['filename']) == 2)
			{
				//change file status
				$arEntry['status'] = "filtered";
				return $res;
			}

			$removePath_size = mb_strlen($removePath);
			if (mb_substr($arEntry['filename'], 0, $removePath_size) == $removePath)
			{
				//remove path
				$arEntry['filename'] = mb_substr($arEntry['filename'], $removePath_size);
			}
		}
	}

	//making absolute path to the extracted file out of filename stored in the zip header and passed extracting path
	if ($path != '')
	{
		$arEntry['filename'] = $path . "/" . $arEntry['filename'];
	}

	//pre-extract callback
	if ((isset($arParams['callback_pre_extract']))
		&& ($arParams['callback_pre_extract'] != ''))
	{
		//generate local info
		$arLocalHeader = [];
		$this->_convertHeader2FileInfo($arEntry, $arLocalHeader);

		//callback call
		eval('$res = ' . $arParams['callback_pre_extract'] . '('callback_pre_extract', $arLocalHeader);');

		//change file status
		if ($res == 0)
		{
			$arEntry['status'] = "skipped";
			$res = 1;
		}

		//update the info, only some fields can be modified
		$arEntry['filename'] = $arLocalHeader['filename'];
	}

	//check if extraction should be done
	if ($arEntry['status'] == 'ok')
	{
		if ($this->checkPermissions && !CBXArchive::IsFileSafe($arEntry['filename']))
		{
			$arEntry['status'] = "no_permissions";
		}
		else
		{
			//if the file exists, change status
			if (file_exists($arEntry['filename']))
			{
				if (is_dir($arEntry['filename']))
				{
					$arEntry['status'] = "already_a_directory";
				}
				else
				{
					if (!is_writeable($arEntry['filename']))
					{
						$arEntry['status'] = "write_protected";
					}
					else
					{
						if ((filemtime($arEntry['filename']) > $arEntry['mtime']) && (!$this->replaceExistentFiles))
						{
							$arEntry['status'] = "newer_exist";
						}
					}
				}
			}
			else
			{
				//check the directory availability and create it if necessary
				if ((($arEntry['external'] & 0x00000010) == 0x00000010) || (mb_substr($arEntry['filename'], -1) == '/'))
				{
					$checkDir = $arEntry['filename'];
				}
				else
				{
					if (!mb_strstr($arEntry['filename'], "/"))
					{
						$checkDir = "";
					}
					else
					{
						$checkDir = dirname($arEntry['filename']);
					}
				}

				if (($res = $this->_checkDir($checkDir, (($arEntry['external'] & 0x00000010) == 0x00000010))) != 1)
				{
					//change file status
					$arEntry['status'] = "path_creation_fail";

					//return $res;
					$res = 1;
				}
			}
		}
	}

	//check if extraction should be done
	if ($arEntry['status'] == 'ok')
	{
		//if not a folder - extract
		if (!(($arEntry['external'] & 0x00000010) == 0x00000010))
		{
			//if zip file with 0 compression
			if (($arEntry['compression'] == 0) && ($arEntry['compressed_size'] == $arEntry['size']))
			{
				if (($destFile = @fopen($arEntry['filename'], 'wb')) == 0)
				{
					$arEntry['status'] = "write_error";
					return $res;
				}

				//reading the fileby by self::ReadBlockSize octets blocks
				$size = $arEntry['compressed_size'];
				while ($size != 0)
				{
					$length = ($size < self::ReadBlockSize ? $size : self::ReadBlockSize);
					$buffer = fread($this->zipfile, $length);
					$binary_data = pack('a' . $length, $buffer);
					@fwrite($destFile, $binary_data, $length);
					$size -= $length;
				}

				//close the destination file
				fclose($destFile);

				//changing file modification time
				touch($arEntry['filename'], $arEntry['mtime']);
			}
			else
			{
				if (($destFile = @fopen($arEntry['filename'], 'wb')) == 0)
				{
					//change file status
					$arEntry['status'] = "write_error";
					return $res;
				}

				//read the compressed file in a buffer (one shot)
				$buffer = @fread($this->zipfile, $arEntry['compressed_size']);

				//decompress the file
				$fileContent = gzinflate($buffer);
				unset($buffer);

				//write uncompressed data
				@fwrite($destFile, $fileContent, $arEntry['size']);
				unset($fileContent);
				@fclose($destFile);
				touch($arEntry['filename'], $arEntry['mtime']);
			}

			if ((isset($arParams['set_chmod'])) && ($arParams['set_chmod'] != 0))
			{
				chmod($arEntry['filename'], $arParams['set_chmod']);
			}
		}
	}

	//post-extract callback
	if ((isset($arParams['callback_post_extract'])) && ($arParams['callback_post_extract'] != ''))
	{
		//make local info
		$arLocalHeader = [];
		$this->_convertHeader2FileInfo($arEntry, $arLocalHeader);

		//callback call
		eval('$res = ' . $arParams['callback_post_extract'] . '('callback_post_extract', $arLocalHeader);');
	}
	return $res;
}