Your IP : 18.118.198.47


Current Path : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/ui/lib/FileUploader/
Upload File :
Current File : /var/www/www-root/data/www/info.monolith-realty.ru/bitrix/modules/ui/lib/FileUploader/Chunk.php

<?php

namespace Bitrix\UI\FileUploader;

use Bitrix\Main\Error;
use Bitrix\Main\File;
use Bitrix\Main\HttpRequest;
use Bitrix\Main\IO;
use Bitrix\Main\Result;
use Bitrix\Main\Text\Encoding;

class Chunk
{
	protected int $size = 0;
	protected ?int $fileSize = null;
	protected ?int $startRange = null;
	protected ?int $endRange = null;
	protected string $type = '';
	protected string $name = '';
	protected int $width = 0;
	protected int $height = 0;

	protected IO\File $file;

	protected function __construct(IO\File $file)
	{
		$this->setFile($file);
	}

	public static function createFromRequest(HttpRequest $request): Result
	{
		$result = new Result();

		$fileMimeType = (string)$request->getHeader('Content-Type');
		if (!preg_match('~\w+/[-+.\w]+~', $fileMimeType))
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_TYPE));
		}

		$contentLength = $request->getHeader('Content-Length');
		if ($contentLength === null)
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_LENGTH));
		}

		$contentLength = (int)$contentLength;
		$filename = static::normalizeFilename((string)$request->getHeader('X-Upload-Content-Name'));
		if (empty($filename))
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_NAME));
		}

		if (!static::isValidFilename($filename))
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_FILENAME));
		}

		$contentRangeResult = static::getContentRange($request);
		if (!$contentRangeResult->isSuccess())
		{
			return $result->addErrors($contentRangeResult->getErrors());
		}

		$file = static::getFileFromHttpInput();
		$contentRange = $contentRangeResult->getData();
		$rangeChunkSize = empty($contentRange) ? 0 : ($contentRange['endRange'] - $contentRange['startRange'] + 1);

		if ($rangeChunkSize && $contentLength !== $rangeChunkSize)
		{
			return $result->addError(new UploaderError(
				UploaderError::INVALID_RANGE_SIZE,
				[
					'rangeChunkSize' => $rangeChunkSize,
					'contentLength' => $contentLength,
				]
			));
		}

		$chunk = new Chunk($file);
		if ($chunk->getSize() !== $contentLength)
		{
			return $result->addError(new UploaderError(
				UploaderError::INVALID_CHUNK_SIZE,
				[
					'chunkSize' => $chunk->getSize(),
					'contentLength' => $contentLength,
				]
			));
		}

		$chunk->setName($filename);
		$chunk->setType($fileMimeType);

		if (!empty($contentRange))
		{
			$chunk->setStartRange($contentRange['startRange']);
			$chunk->setEndRange($contentRange['endRange']);
			$chunk->setFileSize($contentRange['fileSize']);
		}

		$result->setData(['chunk' => $chunk]);

		return $result;
	}

	private static function getFileFromHttpInput(): IO\File
	{
		// This file will be automatically removed on shutdown
		$tmpFilePath = TempFile::generateLocalTempFile();
		$file = new IO\File($tmpFilePath);
		$file->putContents(HttpRequest::getInput());

		return $file;
	}

	private static function getContentRange(HttpRequest $request): Result
	{
		$contentRange = $request->getHeader('Content-Range');
		if ($contentRange === null)
		{
			return new Result();
		}

		$result = new Result();
		if (!preg_match('/(\d+)-(\d+)\/(\d+)$/', $contentRange, $match))
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_RANGE));
		}

		[$startRange, $endRange, $fileSize] = [(int)$match[1], (int)$match[2], (int)$match[3]];

		if ($startRange > $endRange)
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_RANGE));
		}

		if ($fileSize <= $endRange)
		{
			return $result->addError(new UploaderError(UploaderError::INVALID_CONTENT_RANGE));
		}

		$result->setData([
			'startRange' => $startRange,
			'endRange' => $endRange,
			'fileSize' => $fileSize,
		]);

		return $result;
	}

	private static function normalizeFilename(string $filename): string
	{
		$filename = urldecode($filename);
		$filename = Encoding::convertEncodingToCurrent($filename);

		return \getFileName($filename);
	}

	private static function isValidFilename(string $filename): bool
	{
		if (mb_strlen($filename) > 255)
		{
			return false;
		}

		if (mb_strpos($filename, '\0') !== false)
		{
			return false;
		}

		return true;
	}

	public function getFile(): IO\File
	{
		return $this->file;
	}

	/**
	 * @internal
	 */
	public function setFile(IO\File $file): void
	{
		$this->file = $file;
		$this->size = $file->getSize();
	}

	public function getSize(): int
	{
		return $this->size;
	}

	public function getFileSize(): int
	{
		return $this->fileSize ?? $this->size;
	}

	protected function setFileSize(int $fileSize): void
	{
		$this->fileSize = $fileSize;
	}

	public function getType(): string
	{
		return $this->type;
	}

	public function setType(string $type): void
	{
		$this->type = $type;
	}

	public function getName(): string
	{
		return $this->name;
	}

	public function setName(string $name): void
	{
		$this->name = $name;
	}

	public function getWidth(): int
	{
		return $this->width;
	}

	public function setWidth(int $width): void
	{
		$this->width = $width;
	}

	public function getHeight(): int
	{
		return $this->height;
	}

	public function setHeight(int $height): void
	{
		$this->height = $height;
	}

	public function getStartRange(): ?int
	{
		return $this->startRange;
	}

	protected function setStartRange(int $startRange): void
	{
		$this->startRange = $startRange;
	}

	public function getEndRange(): ?int
	{
		return $this->endRange;
	}

	protected function setEndRange(int $endRange): void
	{
		$this->endRange = $endRange;
	}

	public function isFirst(): bool
	{
		return $this->startRange === null || $this->startRange === 0;
	}

	public function isLast(): bool
	{
		return $this->endRange === null || ($this->endRange + 1) === $this->fileSize;
	}

	public function isOnlyOne(): bool
	{
		return (
			$this->startRange === null
			|| ($this->startRange === 0 && ($this->endRange - $this->startRange + 1) === $this->fileSize)
		);
	}

	public function validate(Configuration $config): Result
	{
		$result = new Result();

		if (in_array(mb_strtolower($this->getName()), $config->getIgnoredFileNames()))
		{
			return $result->addError(new UploaderError(UploaderError::FILE_NAME_NOT_ALLOWED));
		}

		if ($config->getMaxFileSize() !== null && $this->getFileSize() > $config->getMaxFileSize())
		{
			return $result->addError(
				new UploaderError(
					UploaderError::MAX_FILE_SIZE_EXCEEDED,
					[
						'maxFileSize' => \CFile::formatSize($config->getMaxFileSize()),
						'maxFileSizeInBytes' => $config->getMaxFileSize(),
					]
				)
			);
		}

		if ($this->getFileSize() < $config->getMinFileSize())
		{
			return $result->addError(
				new UploaderError(
					UploaderError::MIN_FILE_SIZE_EXCEEDED,
					[
						'minFileSize' => \CFile::formatSize($config->getMinFileSize()),
						'minFileSizeInBytes' => $config->getMinFileSize(),
					]
				)
			);
		}

		if (!$this->validateFileType($config->getAcceptedFileTypes()))
		{
			return $result->addError(new UploaderError(UploaderError::FILE_TYPE_NOT_ALLOWED));
		}

		$width = 0;
		$height = 0;
		if (\CFile::isImage($this->getName(), $this->getType()))
		{
			$image = new File\Image($this->getFile()->getPhysicalPath());
			$imageInfo = $image->getInfo(false);
			if (!$imageInfo)
			{
				if ($config->getIgnoreUnknownImageTypes())
				{
					$result->setData(['width' => $width, 'height' => $height]);

					return $result;
				}
				else
				{
					return $result->addError(new UploaderError(UploaderError::IMAGE_TYPE_NOT_SUPPORTED));
				}
			}

			$width = $imageInfo->getWidth();
			$height = $imageInfo->getHeight();
			if ($imageInfo->getFormat() === File\Image::FORMAT_JPEG)
			{
				$exifData = $image->getExifData();
				if (isset($exifData['Orientation']) && $exifData['Orientation'] >= 5 && $exifData['Orientation'] <= 8)
				{
					[$width, $height] = [$height, $width];
				}
			}

			if (!$config->shouldTreatOversizeImageAsFile())
			{
				$imageData = new FileData($this->getName(), $this->getType(), $this->getSize());
				$imageData->setWidth($width);
				$imageData->setHeight($height);

				$validationResult = $config->validateImage($imageData);
				if (!$validationResult->isSuccess())
				{
					return $result->addErrors($validationResult->getErrors());
				}
			}
		}

		$result->setData(['width' => $width, 'height' => $height]);

		return $result;
	}

	private function validateFileType(array $fileTypes): bool
	{
		if (count($fileTypes) === 0)
		{
			return true;
		}

		$mimeType = $this->getType();
		$baseMimeType = preg_replace('/\/.*$/', '', $mimeType);

		foreach ($fileTypes as $type)
		{
			if (!is_string($type) || mb_strlen($type) === 0)
			{
				continue;
			}

			$type = mb_strtolower(trim($type));
			if ($type[0] === '.') // extension case
			{
				$filename = mb_strtolower($this->getName());
				$offset = mb_strlen($filename) - mb_strlen($type);
				if (mb_strpos($filename, $type, $offset) !== false)
				{
					return true;
				}
			}
			elseif (preg_match('/\/\*$/', $type)) // image/* mime type case
			{
				if ($baseMimeType === preg_replace('/\/.*$/', '', $type))
				{
					return true;
				}
			}
			elseif ($mimeType === $type)
			{
				return true;
			}
		}

		return false;
	}
}