HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux mail.btech-izolacje.pl 5.15.0-140-generic #150-Ubuntu SMP Sat Apr 12 06:00:09 UTC 2025 x86_64
User: pewna6876 (1017)
PHP: 8.2.28
Disabled: NONE
Upload Files
File: /home/pewnabryka.pl/public_html/wp-content/plugins/duplicator-pro/src/Libs/Index/IndexList.php
<?php

/**
 *
 * @package   Duplicator
 * @copyright (c) 2022, Snap Creek LLC
 */

namespace Duplicator\Libs\Index;

use Duplicator\Libs\Binary\BinaryFormat;
use Duplicator\Libs\Binary\BinaryIO;
use Duplicator\Libs\Snap\SnapIO;
use Duplicator\Libs\Snap\SnapUtil;
use Generator;

/**
 * Index List class
 */
class IndexList implements IndexListInfoInterface
{
    const NAME_PREFIX      = 'index_list_';
    const NAME_SUFFIX      = '.txt';
    const NAME_HASH_LENGTH = 8;

    /**
     * The prefix format for the length of the binary data
     *
     * @var string
     */
    const PREFIX_FORMAT = 'N';

    /**
     * The end-of-line flag.
     *
     * @var string
     */
    const END_OF_LINE = "\n";

    /** @var int */
    protected int $type = -1;

    /** @var string */
    protected string $path = '';

    /** @var int */
    protected int $count = 0;

    /** @var ?resource */
    protected $handle;

    /**
     * Class constructor
     *
     * @param string $dirPath The path to the dir in which the temporary index list is created
     * @param int    $type    The list type of this index list
     *
     * @return void
     */
    public function __construct(string $dirPath, int $type)
    {
        $this->type = $type;
        if (is_dir($dirPath) === false) {
            throw new \Exception('Index list directory does not exist');
        }

        $this->path = SnapIO::trailingslashit($dirPath) . self::getNewIndexName();

        if (($this->handle = fopen($this->path, 'c+b')) === false) {
            throw new \Exception('Could not open index file for writing');
        }
    }

    /**
     * Generates a new index name.
     *
     * @return string The newly generated index name.
     */
    protected static function getNewIndexName(): string
    {
        return  self::NAME_PREFIX . date('YmdHis') . '_' . SnapUtil::generatePassword(self::NAME_HASH_LENGTH, false, false) . self::NAME_SUFFIX;
    }

    /**
     * Returns the path of the single index list file
     *
     * @return string The path
     */
    public function getPath(): string
    {
        return $this->path;
    }

    /**
     * Returns the number of items in the list
     *
     * @return int The number of items in the list
     */
    public function getCount(): int
    {
        return $this->count;
    }

    /**
     * Returns the number of items in the list
     *
     * @param int $count The number of items in the list
     *
     * @return void
     */
    public function setCount($count): void
    {
        $this->count = $count;
    }

    /**
     * Gets the size of the index list
     *
     * @return int Size of the index list in bytes
     */
    public function getSize(): int
    {
        if (($size = filesize($this->path)) === false) {
            throw new \Exception("Couldn't get the size of the index list file.");
        }

        return $size;
    }

    /**
     * Writes a node item into the list
     *
     * @param array<int|string, mixed> $data    The data to write
     * @param BinaryFormat[]           $formats The formats of the data
     *
     * @return void
     */
    public function add(array $data, array $formats): void
    {
        if (fseek($this->handle, 0, SEEK_END) !== 0) {
            throw new \Exception("Couldn't seek to the end of the index list file.");
        }

        self::writeLine($this->handle, BinaryIO::encode($formats, $data));

        $this->count++;
    }

    /**
     * Copies all the content of the list to the handle
     *
     * @param resource $toHandle Stream to copy to
     *
     * @return void
     */
    public function copyToMain($toHandle): void
    {
        if ($this->getSize() === 0) {
            return;
        }

        if (rewind($this->handle) === false) {
            throw new \Exception("Couldn't seek to start before copy to main");
        }

        if (stream_copy_to_stream($this->handle, $toHandle) === false) {
            throw new \Exception("Couldn't copy index list contents");
        }
    }

    /**
     * Copies all the content of the list to the handle
     *
     * @param resource $fromHandle Stream to copy to
     * @param int      $offset     Offset of the list
     * @param int      $length     Length of the list
     *
     * @return void
     */
    public function copyFromMain($fromHandle, $offset, $length): void
    {
        if (ftruncate($this->handle, 0) === false) {
            throw new \Exception("Couldn't truncate index list before copying into it.");
        }

        if (rewind($this->handle) === false) {
            throw new \Exception("Couldn't rewind index list before copying into it.");
        }

        if (stream_copy_to_stream($fromHandle, $this->handle, $length, $offset) === false) {
            throw new \Exception("Couldn't copy index list contents");
        }
    }

    /**
     * Resets the index list
     *
     * @return void
     */
    public function reset(): void
    {
        $this->count = 0;

        if (ftruncate($this->handle, 0) === false) {
            throw new \Exception("Couldn't truncate index list to reset.");
        }

        if (rewind($this->handle) === false) {
            throw new \Exception("Couldn't rewind index list to reset.");
        }
    }

    /**
     * Generator method to iterate over the contents of the index list.
     *
     * @param BinaryFormat[] $formats The formats of the data
     * @param int            $seek    Seek to a specific line before iterating
     *
     * @return Generator<int, array<int|string, mixed>> The generator for iteration
     */
    public function iterate($formats, $seek = -1): Generator
    {
        return self::iterateFromHandle($this->handle, $formats, $seek);
    }

    /**
     * Generator method to iterate over the contents of the index list.
     *
     * @param resource       $handle  Optional handle to iterate over. Default is the internal handle
     * @param BinaryFormat[] $formats The formats of the data
     * @param int            $seek    Seek to a specific line before iterating
     * @param int            $start   The start position for the list. Default is 0
     * @param int            $end     The end position for the list. Default is -1 (EOF)
     *
     * @return Generator<int, array<int|string, mixed>> The generator for iteration
     */
    public static function iterateFromHandle($handle, $formats, $seek = -1, $start = 0, $end = -1): Generator
    {
        if (fseek($handle, $start) === -1) {
            throw new \Exception("Couldn't seek to iterate on index list file.");
        }

        if ($seek !== -1) {
            $i = 0;
            while ($i < $seek && self::readLine($handle) !== false) {
                $i++;
            }
        }

        while (($binary = self::readLine($handle)) !== false && ($end === -1 || ftell($handle) <= $end)) {
            yield BinaryIO::decode($formats, $binary);
        }
    }

    /**
     * Reads an item line from the handle. It is expected that the pointer is at the start of an item line,
     * otherwise an exception will be thrown.
     *
     * @param resource $handle The handle to read from
     *
     * @return string|false The binary string or false if EOF
     */
    protected static function readLine($handle)
    {
        $prefixLength = BinaryFormat::getBinaryLengthMap()[self::PREFIX_FORMAT];
        if (
            ($lengtBinary = fread($handle, $prefixLength)) === false ||
            feof($handle)
        ) {
            return false;
        }

        $length = unpack(self::PREFIX_FORMAT, $lengtBinary)[1];
        if (($result = fread($handle, $length)) === false) {
            throw new \Exception("Couldn't read index list item.");
        }

        if (fread($handle, strlen(self::END_OF_LINE)) !== self::END_OF_LINE) {
            throw new \Exception("Not an index item. End of line not found.");
        }

        return $result;
    }

    /**
     * Writes a item line to the handle
     *
     * @param resource $handle The handle to write to
     * @param string   $binary The binary string to write
     *
     * @return void
     */
    protected static function writeLine($handle, $binary): void
    {
        $line  = BinaryIO::encode([(new BinaryFormat(self::PREFIX_FORMAT))->setVariableLength()], $binary);
        $line .= self::END_OF_LINE;

        if (fwrite($handle, $line) === false) {
            throw new \Exception("Couldn't write to index list.");
        }
    }

    /**
     * Class destructor
     *
     * @return void
     */
    public function __destruct()
    {
        if (is_resource($this->handle)) {
            fclose($this->handle);
        }

        if (file_exists($this->path)) {
            unlink($this->path);
        }
    }
}