403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/catalog/lib/controller/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/modules/catalog/lib/controller/productimage.php
<?php

namespace Bitrix\Catalog\Controller;

use Bitrix\Catalog\Access\ActionDictionary;
use Bitrix\Iblock\PropertyTable;
use Bitrix\Main\Application;
use Bitrix\Main\DB\SqlQueryException;
use Bitrix\Main\Engine\Response\DataType\Page;
use Bitrix\Main\Error;
use Bitrix\Main\FileTable;
use Bitrix\Main\Loader;
use Bitrix\Main\Result;

final class ProductImage extends Controller
{
	use CheckExists; // default implementation of existence check

	//region Actions
	/**
	 * REST method catalog.productImage.getFiles
	 *
	 * @param int $productId
	 * @param array $select
	 * @param \CRestServer|null $restServer
	 *
	 * @return Page|null
	 */
	public function getFieldsAction(): array
	{
		return [$this->getServiceItemName() => $this->getViewFields()];
	}

	/**
	 * REST method catalog.productImage.list
	 *
	 * @param int $productId
	 * @param array $select
	 * @param \CRestServer|null $restServer
	 *
	 * @return Page|null
	 */
	public function listAction(int $productId, array $select = [], \CRestServer $restServer = null): ?Page
	{
		if ($productId <= 0)
		{
			$this->addError(new Error('Empty productID'));

			return null;
		}

		$product = $this->getProduct($productId);
		if (!$product)
		{
			$this->addError(new Error('Product was not found'));

			return null;
		}

		$r = $this->checkPermissionProductRead($product);
		if (!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());

			return null;
		}

		$imageIds = [];
		if ($product['PREVIEW_PICTURE'])
		{
			$imageIds[] = $product['PREVIEW_PICTURE'];
		}
		if ($product['DETAIL_PICTURE'])
		{
			$imageIds[] = $product['DETAIL_PICTURE'];
		}
		if ($this->getMorePhotoPropertyId((int)$product['IBLOCK_ID']))
		{
			$imageIds = [...$imageIds, ...$this->getMorePhotoPropertyValues($product)];
		}

		$result = [];
		$fileTableResult = FileTable::getList(['filter' => ['=ID' => $imageIds]]);
		while ($image = $fileTableResult->fetch())
		{
			if ($product['PREVIEW_PICTURE'] === $image['ID'])
			{
				$type = 'PREVIEW_PICTURE';
			}
			elseif ($product['DETAIL_PICTURE'] === $image['ID'])
			{
				$type = 'DETAIL_PICTURE';
			}
			else
			{
				$type = 'MORE_PHOTO';
			}
			$image['TYPE'] = $type;
			$image['PRODUCT_ID'] = $product['ID'];

			$result[] = $this->prepareFileStructure($image, $restServer, $select);
		}

		return new Page(
			'PRODUCT_IMAGES',
			$result,
			count($result)
		);
	}

	/**
	 * REST method catalog.productImage.get
	 *
	 * @param int $id
	 * @param int $productId
	 * @param \CRestServer|null $restServer
	 *
	 * @return array[]|null
	 */
	public function getAction(int $id, int $productId, \CRestServer $restServer = null): ?array
	{
		$product = $this->getProduct($productId);
		if (!$product)
		{
			$this->addError(new Error('Product was not found'));

			return null;
		}

		$r = $this->checkPermissionProductRead($product);
		if (!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());

			return null;
		}

		$image = $this->getImageById($id, $product);
		if (!$image)
		{
			$this->addError($this->getErrorEntityNotExists());

			return null;
		}

		return [$this->getServiceItemName() => $this->prepareFileStructure($image, $restServer)];
	}

	/**
	 * REST method catalog.productImage.add
	 *
	 * @param array $fields
	 * @param array $fileContent
	 * @param \CRestServer|null $restServer
	 *
	 * @return void
	 */
	public function addAction(array $fields, array $fileContent, \CRestServer $restServer = null): ?array
	{
		if (!Loader::includeModule('rest'))
		{
			return null;
		}

		$product = $this->getProduct((int)$fields['PRODUCT_ID']);
		if (!$product)
		{
			$this->addError(new Error('Product was not found'));
			return null;
		}

		$r = $this->checkPermissionProductWrite($product);
		if (!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());
			return null;
		}

		$fileData = \CRestUtil::saveFile($fileContent);
		if (!$fileData)
		{
			$this->addError(new Error('Could not save image.'));
			return null;
		}

		$checkPictureResult = \CFile::CheckFile($fileData, 0 ,false, \CFile::GetImageExtensions());
		if ($checkPictureResult !== '')
		{
			$this->addError(new Error($checkPictureResult));
			return null;
		}

		if ($fields['TYPE'] === 'DETAIL_PICTURE' || $fields['TYPE'] === 'PREVIEW_PICTURE')
		{
			$updateFields = [$fields['TYPE'] => $fileData];
		}
		else
		{
			$fields['TYPE'] = 'MORE_PHOTO';
			$morePhotoProperty = $this->getMorePhotoProperty((int)$product['IBLOCK_ID']);
			if (!$morePhotoProperty->isSuccess())
			{
				$this->addErrors($morePhotoProperty->getErrors());

				return null;
			}

			$updateFields = [
				'n0' => [
					'VALUE' => $fileData,
				],
			];
		}

		$connection = Application::getConnection();
		$connection->startTransaction();
		try
		{
			if ($fields['TYPE'] === 'DETAIL_PICTURE' || $fields['TYPE'] === 'PREVIEW_PICTURE')
			{
				$error = $this->updateProductImage((int)$product['ID'], $updateFields);
			}
			else
			{
				$error = $this->updateProductMorePhoto((int)$product['ID'], (int)$product['IBLOCK_ID'], $updateFields);
			}
		}
		catch (SqlQueryException)
		{
			$error = 'Internal error adding product image. Try adding again.';
		}
		if ($error !== '')
		{
			$connection->rollbackTransaction();
			$this->addError(new Error($error));

			return null;
		}
		$connection->commitTransaction();

		if ($fields['TYPE'] === 'DETAIL_PICTURE' || $fields['TYPE'] === 'PREVIEW_PICTURE')
		{
			$product = $this->getProduct((int)$fields['PRODUCT_ID'], [$fields['TYPE']]);
			$imageId = $product[$fields['TYPE']];
		}
		else
		{
			$morePhotoIds = $this->getMorePhotoPropertyValues($product);
			if (!$morePhotoIds)
			{
				$this->addError(new Error('Empty image.'));

				return null;
			}
			$imageId = end($morePhotoIds);
		}
		$image = FileTable::getRowById($imageId);
		if (!$image)
		{
			$this->addError($this->getErrorEntityNotExists());

			return null;
		}
		$image['TYPE'] = $fields['TYPE'];
		$image['PRODUCT_ID'] = $fields['PRODUCT_ID'];

		return [$this->getServiceItemName() => $this->prepareFileStructure($image, $restServer)];
	}

	/**
	 * REST method catalog.productImage.delete
	 *
	 * @param int $id
	 * @param int $productId
	 *
	 * @return void
	 */
	public function deleteAction(int $id, int $productId): ?bool
	{
		if (!$this->exists($id))
		{
			$this->addError($this->getErrorEntityNotExists());

			return null;
		}

		$product = $this->getProduct($productId);
		if (!$product)
		{
			$this->addError(new Error('Product was not found'));

			return null;
		}

		$r = $this->checkPermissionProductWrite($product);
		if (!$r->isSuccess())
		{
			$this->addErrors($r->getErrors());

			return null;
		}

		if ($id === (int)$product['PREVIEW_PICTURE'])
		{
			$updateFields = ['PREVIEW_PICTURE' => \CIBlock::makeFileArray(null, true)];
		}
		elseif ($id === (int)$product['DETAIL_PICTURE'])
		{
			$updateFields = ['DETAIL_PICTURE' => \CIBlock::makeFileArray(null, true)];
		}
		else
		{
			$morePhotoPropertyValueId = $this->getMorePhotoPropertyValueId($product, $id);
			if (!$morePhotoPropertyValueId)
			{
				$this->addError($this->getErrorEntityNotExists());

				return null;
			}
			$updateFields = [$morePhotoPropertyValueId => \CIBlock::makeFileArray(null, true)];
		}

		$connection = Application::getConnection();
		$connection->startTransaction();
		try
		{
			if ($id === (int)$product['PREVIEW_PICTURE'] || $id === (int)$product['DETAIL_PICTURE'])
			{
				$error = $this->updateProductImage((int)$product['ID'], $updateFields);
			}
			else
			{
				$error = $this->updateProductMorePhoto((int)$product['ID'], (int)$product['IBLOCK_ID'], $updateFields);
			}
		}
		catch (SqlQueryException)
		{
			$error = 'Internal error deleting product image. Try deleting again.';
		}
		if ($error !== '')
		{
			$connection->rollbackTransaction();
			$this->addError(new Error($error));

			return null;
		}
		$connection->commitTransaction();

		return true;
	}
	//endregion

	private function prepareFileStructure(
		array $image,
		\CRestServer $restServer = null,
		array $selectedFields = null
	): array
	{
		$result = [];
		if (!$selectedFields)
		{
			$selectedFields = array_keys($this->getViewManager()->getView($this)->getFields());
		}

		foreach ($selectedFields as $name)
		{
			if ($name === 'ID')
			{
				$result[$name] = (int)$image['ID'];
			}
			if ($name === 'NAME')
			{
				$result[$name] = $image['FILE_NAME'];
			}
			elseif ($name === 'DETAIL_URL')
			{
				$result[$name] = \CFile::getFileSRC($image);
			}
			elseif ($name === 'DOWNLOAD_URL')
			{
				$result[$name] =
					$restServer
						? \CRestUtil::getDownloadUrl(['id' => $image['ID']], $restServer)
						: \CFile::getFileSRC($image)
				;
			}
			elseif ($name === 'CREATE_TIME')
			{
				$result[$name] = $image['TIMESTAMP_X'];
			}
			elseif ($name === 'PRODUCT_ID')
			{
				$result[$name] = (int)$image['PRODUCT_ID'];
			}
			elseif ($name === 'TYPE')
			{
				$result[$name] = $image['TYPE'];
			}
		}

		return $result;
	}

	protected function getEntityTable()
	{
		return new FileTable();
	}

	private function getProduct(int $productId, ?array $select = null): ?array
	{
		return \Bitrix\Iblock\ElementTable::getRow([
			'select' => $select ?: ['ID', 'IBLOCK_ID', 'PREVIEW_PICTURE', 'DETAIL_PICTURE'],
			'filter' => ['=ID' => $productId],
		]);
	}

	private function getImageById(int $id, array $product): ?array
	{
		if ((int)$product['PREVIEW_PICTURE'] === $id)
		{
			$type = 'PREVIEW_PICTURE';
		}
		elseif ((int)$product['DETAIL_PICTURE'] === $id)
		{
			$type = 'DETAIL_PICTURE';
		}
		else
		{
			$morePhotoIds = $this->getMorePhotoPropertyValues($product);
			if (!in_array($id, $morePhotoIds))
			{
				return null;
			}

			$type = 'MORE_PHOTO';
		}

		$image = FileTable::getRowById($id);
		if (!$image)
		{
			return null;
		}

		$image['TYPE'] = $type;
		$image['PRODUCT_ID'] = $product['ID'];

		return $image;
	}

	private function getMorePhotoPropertyValueId(array $product, int $value): ?int
	{
		$morePhotoPropertyId = $this->getMorePhotoPropertyId((int)$product['IBLOCK_ID']);
		if (!$morePhotoPropertyId)
		{
			return null;
		}

		$propertyValuesResult = $this->getPropertyValues($product, $morePhotoPropertyId, true);
		$morePhotoPropertyIds = $propertyValuesResult[$morePhotoPropertyId];
		if (!$morePhotoPropertyIds)
		{
			return null;
		}

		$valueIndex = array_search($value, $morePhotoPropertyIds);
		if ($valueIndex === false)
		{
			return null;
		}

		return (int)$propertyValuesResult['PROPERTY_VALUE_ID'][$morePhotoPropertyId][$valueIndex] ?? null;
	}

	private function getMorePhotoPropertyValues(array $product): array
	{
		$morePhotoPropertyId = $this->getMorePhotoPropertyId((int)$product['IBLOCK_ID']);
		if (!$morePhotoPropertyId)
		{
			return [];
		}
		$propertyValuesResult = $this->getPropertyValues($product, $morePhotoPropertyId);

		return $propertyValuesResult[$morePhotoPropertyId] ?? [];
	}

	private function getPropertyValues(array $product, int $propertyId, bool $extMode = false): array
	{
		return \CIBlockElement::getPropertyValues(
			$product['IBLOCK_ID'],
			[
				'ID' => $product['ID'],
				'IBLOCK_ID' => $product['IBLOCK_ID'],
			],
			$extMode,
			[
				'ID' => $propertyId,
			],
		)->Fetch() ?: [];
	}

	private function getMorePhotoPropertyId(int $iblockId): ?int
	{
		return PropertyTable::getRow([
			'select' => ['ID'],
			'filter' => [
				'=IBLOCK_ID' => $iblockId,
				'=CODE' => 'MORE_PHOTO',
				'=ACTIVE' => 'Y',
				'=PROPERTY_TYPE' => PropertyTable::TYPE_FILE,
			],
			'cache' => [
				'ttl' => 86400,
			],
		])['ID'] ?? null;
	}

	private function getMorePhotoProperty(int $iblockId): Result
	{
		$result = new Result();
		$row = PropertyTable::getRow([
			'select' => [
				'ID',
				'ACTIVE',
				'PROPERTY_TYPE',
			],
			'filter' => [
				'=IBLOCK_ID' => $iblockId,
				'=CODE' => 'MORE_PHOTO',
			],
			'cache' => [
				'ttl' => 86400,
			],
		]);

		if (!$row)
		{
			$result->addError(new Error(
				'Image product property does not exists. Create MORE_PHOTO property'
			));

			return $result;
		}

		if ($row['ACTIVE'] !== 'Y')
		{
			$result->addError(new Error(
				'Image product property does not active. Activate MORE_PHOTO property'
			));

			return $result;
		}

		if ($row['PROPERTY_TYPE'] !== PropertyTable::TYPE_FILE)
		{
			$result->addError(new Error(
				'Image product property is of the wrong type'
			));

			return $result;
		}

		$result->setData(['ID' => (int)$row['ID']]);

		return $result;
	}

	private function updateProductImage(int $productId, array $updateFields): string
	{
		$iblockElement = new \CIBlockElement();
		$iblockElement->update($productId, $updateFields);

		return $iblockElement->getLastError();
	}

	private function updateProductMorePhoto(int $productId, int $iblockId, array $updateFields): string
	{
		\CIBlockElement::SetPropertyValues(
			$productId,
			$iblockId,
			$updateFields,
			'MORE_PHOTO',
		);
		$exception = self::getApplication()->GetException();
		if ($exception)
		{
			return $exception->GetString();
		}

		return '';
	}

	private function checkPermissionProductRead(array $product): Result
	{
		$r = $this->checkReadPermissionEntity();
		if (!$r->isSuccess())
		{
			return $r;
		}

		return $this->checkPermissionProduct($product, self::IBLOCK_ELEMENT_READ, $this->getErrorCodeReadAccessDenied());
	}

	private function checkPermissionProductWrite(array $product): Result
	{
		$r = $this->checkModifyPermissionEntity();
		if (!$r->isSuccess())
		{
			return $r;
		}

		return $this->checkPermissionProduct($product, self::IBLOCK_ELEMENT_EDIT, $this->getErrorCodeModifyAccessDenied());
	}

	private function checkPermissionProduct(array $product, string $permission, int $errorCode): Result
	{
		$r = new Result();
		if(!\CIBlockElementRights::UserHasRightTo($product['IBLOCK_ID'], $product['ID'], $permission))
		{
			$r->addError(new Error('Access Denied', $errorCode));
		}

		return $r;
	}

	protected function checkModifyPermissionEntity(): Result
	{
		$r = new Result();

		if (!$this->accessController->check(ActionDictionary::ACTION_CATALOG_VIEW))
		{
			$r->addError($this->getErrorModifyAccessDenied());
		}

		return $r;
	}

	protected function checkReadPermissionEntity(): Result
	{
		$r = new Result();

		if (
			!$this->accessController->check(ActionDictionary::ACTION_CATALOG_READ)
			&& !$this->accessController->check(ActionDictionary::ACTION_CATALOG_VIEW)
		)
		{
			$r->addError($this->getErrorReadAccessDenied());
		}

		return $r;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit