Files
LiveCartaWP/html/wp-content/plugins/duplicator/src/Libs/DupArchive/DupArchive.php

287 lines
9.3 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace Duplicator\Libs\DupArchive;
use Duplicator\Libs\DupArchive\Headers\DupArchiveReaderDirectoryHeader;
use Duplicator\Libs\DupArchive\Headers\DupArchiveReaderFileHeader;
use Duplicator\Libs\DupArchive\Headers\DupArchiveReaderGlobHeader;
use Duplicator\Libs\DupArchive\Headers\DupArchiveReaderHeader;
use Error;
use Exception;
class DupArchive
{
const DUPARCHIVE_VERSION = '1.0.0';
const INDEX_FILE_NAME = '__dup__archive__index.json';
const INDEX_FILE_SIZE = 2000; // reserver 2K
const EXTRA_FILES_POS_KEY = 'extraPos';
const HEADER_TYPE_NONE = 0;
const HEADER_TYPE_FILE = 1;
const HEADER_TYPE_DIR = 2;
const HEADER_TYPE_GLOB = 3;
/**
* Get header type enum
*
* @param resource $archiveHandle archive resource
*
* @return int
*/
protected static function getNextHeaderType($archiveHandle)
{
$retVal = self::HEADER_TYPE_NONE;
$marker = fgets($archiveHandle, 4);
if (feof($archiveHandle) === false) {
switch ($marker) {
case '<D>':
$retVal = self::HEADER_TYPE_DIR;
break;
case '<F>':
$retVal = self::HEADER_TYPE_FILE;
break;
case '<G>':
$retVal = self::HEADER_TYPE_GLOB;
break;
default:
throw new Exception("Invalid header marker {$marker}. Location:" . ftell($archiveHandle));
}
}
return $retVal;
}
/**
* Get archive index data
*
* @param string $archivePath archive path
*
* @return bool|array return index data, false if don't exists
*/
public static function getIndexData($archivePath)
{
try {
$indexContent = self::getSrcFile($archivePath, self::INDEX_FILE_NAME, 0, 3000, false);
if ($indexContent === false) {
return false;
}
$indexData = json_decode(rtrim($indexContent, "\0"), true);
if (!is_array($indexData)) {
return false;
}
} catch (Exception $e) {
return false;
} catch (Error $e) {
return false;
}
return $indexData;
}
/**
* Get extra files offset if set or 0
*
* @param string $archivePath archive path
*
* @return int
*/
public static function getExtraOffset($archivePath)
{
if (($indexData = self::getIndexData($archivePath)) === false) {
return 0;
}
return (isset($indexData[self::EXTRA_FILES_POS_KEY]) ? $indexData[self::EXTRA_FILES_POS_KEY] : 0);
}
/**
* Add file in archive from src
*
* @param string $archivePath archive path
* @param string $relativePath relative path
* @param int $offset start search location
* @param int $sizeToSearch max size where search
*
* @return bool|int false if file not found of path position
*/
public static function seachPathInArchive($archivePath, $relativePath, $offset = 0, $sizeToSearch = 0)
{
if (($archiveHandle = fopen($archivePath, 'rb')) === false) {
throw new Exception("Cant open archive at $archivePath!");
}
$result = self::searchPath($archivePath, $relativePath, $offset, $sizeToSearch);
@fclose($archiveHandle);
return $result;
}
/**
* Search path, if found set and return position
*
* @param resource $archiveHandle dup archive resource
* @param string $relativePath relative path to extract
* @param int $offset start search location
* @param int $sizeToSearch max size where search
*
* @return bool|int false if file not found of path position
*/
public static function searchPath($archiveHandle, $relativePath, $offset = 0, $sizeToSearch = 0)
{
if (!is_resource($archiveHandle)) {
throw new Exception('Archive handle must be a resource');
}
if (fseek($archiveHandle, $offset, SEEK_SET) < 0) {
return false;
}
if ($offset == 0) {
DupArchiveReaderHeader::readFromArchive($archiveHandle);
}
$result = false;
$position = ftell($archiveHandle);
$continue = true;
do {
switch (($type = self::getNextHeaderType($archiveHandle))) {
case self::HEADER_TYPE_FILE:
$currentFileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, true, true);
if ($currentFileHeader->relativePath == $relativePath) {
$continue = false;
$result = $position;
}
break;
case self::HEADER_TYPE_DIR:
$directoryHeader = DupArchiveReaderDirectoryHeader::readFromArchive($archiveHandle, true);
if ($directoryHeader->relativePath == $relativePath) {
$continue = false;
$result = $position;
}
break;
case self::HEADER_TYPE_NONE:
$continue = false;
break;
default:
throw new Exception('Invali header type "' . $type . '"');
}
$position = ftell($archiveHandle);
if ($sizeToSearch > 0 && ($position - $offset) >= $sizeToSearch) {
break;
}
} while ($continue);
if ($result !== false) {
if (fseek($archiveHandle, $result, SEEK_SET) < 0) {
return false;
}
}
return $result;
}
/**
* Get file content
*
* @param string $archivePath archvie path
* @param string $relativePath relative path to extract
* @param int $offset start search location
* @param int $sizeToSearch max size where search
* @param bool $isCompressed true if is compressed
*
* @return bool|string false if file not found
*/
public static function getSrcFile($archivePath, $relativePath, $offset = 0, $sizeToSearch = 0, $isCompressed = null)
{
if (($archiveHandle = fopen($archivePath, 'rb')) === false) {
throw new Exception("Cant open archive at $archivePath!");
}
$archiveHeader = DupArchiveReaderHeader::readFromArchive($archiveHandle);
if (is_null($isCompressed)) {
$isCompressed = $archiveHeader->isCompressed;
}
if (self::searchPath($archiveHandle, $relativePath, $offset, $sizeToSearch) === false) {
return false;
}
if (self::getNextHeaderType($archiveHandle) != self::HEADER_TYPE_FILE) {
return false;
}
$header = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, false, true);
$result = self::getSrcFromHeader($archiveHandle, $header, $isCompressed);
@fclose($archiveHandle);
return $result;
}
/**
* Get src file form header
*
* @param resource $archiveHandle archive handle
* @param DupArchiveReaderFileHeader $fileHeader file header
* @param bool $isCompressed true if is compressed
*
* @return string
*/
protected static function getSrcFromHeader($archiveHandle, DupArchiveReaderFileHeader $fileHeader, $isCompressed)
{
if ($fileHeader->fileSize == 0) {
return '';
}
$dataSize = 0;
$result = '';
do {
$globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle);
$result .= DupArchiveReaderGlobHeader::readContent($archiveHandle, $globHeader, $isCompressed);
$dataSize += $globHeader->originalSize;
} while ($dataSize < $fileHeader->fileSize);
return $result;
}
/**
* Skip file in archive
*
* @param resource $archiveHandle dup archive resource
* @param DupArchiveFileHeader $fileHeader file header
*
* @return void
*/
protected static function skipFileInArchive($archiveHandle, DupArchiveReaderFileHeader $fileHeader)
{
if ($fileHeader->fileSize == 0) {
return;
}
$dataSize = 0;
do {
$globHeader = DupArchiveReaderGlobHeader::readFromArchive($archiveHandle, true);
$dataSize += $globHeader->originalSize;
} while ($dataSize < $fileHeader->fileSize);
}
/**
* Assumes we are on one header and just need to get to the next
*
* @param resource $archiveHandle dup archive resource
*
* @return void
*/
protected static function skipToNextHeader($archiveHandle)
{
$headerType = self::getNextHeaderType($archiveHandle);
switch ($headerType) {
case self::HEADER_TYPE_FILE:
$fileHeader = DupArchiveReaderFileHeader::readFromArchive($archiveHandle, false, true);
self::skipFileInArchive($archiveHandle, $fileHeader);
break;
case self::HEADER_TYPE_DIR:
DupArchiveReaderDirectoryHeader::readFromArchive($archiveHandle, true);
break;
case self::HEADER_TYPE_NONE:
false;
}
}
}