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/export/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/ilovecveti.ru/bitrix/modules/translate/lib/controller/export/exportaction.php
<?php
namespace Bitrix\Translate\Controller\Export;

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

/**
 * Harvester of the lang files disposition.
 *
 * @method array run(string $path, bool $runBefore)
 *
 */
abstract class ExportAction extends Translate\Controller\Action
{
	protected static string $documentRoot = '';

	protected static bool $useTranslationRepository = false;
	/** @var string[] */
	protected static array $translationRepositoryLanguages = [];

	protected int $tabId = 0;

	protected string $exportFilePath = '';
	protected string $exportFileName = '';
	protected string $exportFileType = 'application/csv';
	protected int $exportFileSize = 0;

	protected bool $convertEncoding;

	protected string $encodingOut;

	protected bool $collectUntranslated;

	/* Look for translation samples */
	protected bool $appendSamples = false;
	protected int $samplesCount = 10;
	protected array $samplesRestriction = [];
	protected string $samplesFilePath = '';
	protected string $samplesFileName = '';
	protected int $samplesFileSize = 0;

	/* Don't look for samples for a long text */
	protected int $maxSampleSourceLength = 500;

	/** @var string[] */
	protected array $languages = [];

	protected int $exportedPhraseCount = 0;

	protected int $exportedSamplesCount = 0;

	protected Translate\Filter $filter;

	protected array $fullPathCache = [];


	/**
	 * \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 = [])
	{
		$this->filter = new Translate\Filter();

		Loc::loadLanguageFile(__FILE__);

		if ($this instanceof Translate\Controller\IProcessParameters)
		{
			$this->keepField([
				'tabId',
				'exportFileName',
				'exportFilePath',
				'exportFileSize',
				'exportedPhraseCount',
				'collectUntranslated',
				'appendSamples',
				'samplesCount',
				'samplesRestriction',
				'samplesFileName',
				'samplesFilePath',
				'samplesFileSize',
				'exportedSamplesCount',
				'convertEncoding',
				'encodingOut',
				'languages'
			]);
		}

		$fields = [
			'collectUntranslated',
			'appendSamples',
			'samplesCount',
			'samplesRestriction',
			'convertEncoding',
			'encodingOut',
			'languages',
			'filter'
		];
		foreach ($fields as $key)
		{
			if (isset($config[$key]))
			{
				if ($key == 'filter')
				{
					if (!$config[$key] instanceof Translate\Filter)
					{
						continue;
					}
				}
				$this->{$key} = $config[$key];
			}
		}

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

		self::$useTranslationRepository = Main\Localization\Translation::useTranslationRepository();
		if (self::$useTranslationRepository)
		{
			self::$translationRepositoryLanguages = Translate\Config::getTranslationRepositoryLanguages();
		}

		if (in_array('all', $this->languages) || empty($this->languages))
		{
			$this->languages = Translate\Config::getEnabledLanguages();
		}

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


	/**
	 * Creates temporary file for writing data.
	 *
	 * @param string $exportFileName
	 * @return Translate\IO\CsvFile
	 */
	protected function createExportTempFile(string $exportFileName): Translate\IO\CsvFile
	{
		/** @var Translate\IO\CsvFile $csvFile */
		$exportFolder = Translate\Config::getExportFolder();
		if (!empty($exportFolder))
		{
			$tempDir = new Translate\IO\Directory($exportFolder);
			if ($tempDir->isExists())
			{
				$tempDir->wipe(function(Main\IO\FileSystemEntry $entry){
					// clear .csv files older than 3 hours
					return (
						$entry->isFile() &&
						\preg_match("#.+_([0-9]+)\.csv$#", $entry->getName(), $matches) &&
						(\time() - (int)$matches[1] > 3 * 3600)
					);
				});
			}
			else
			{
				$tempDir->create();
			}

			$fileName = \preg_replace("#(.+)\.csv$#", "$1_".\time().'.csv',  $exportFileName);

			$csvFile = new Translate\IO\CsvFile($tempDir->getPhysicalPath() .'/'. $fileName);
		}
		else
		{
			$csvFile = Translate\IO\CsvFile::generateTemporalFile('translate', '.csv', 3);
		}

		$this->configureExportCsvFile($csvFile);

		$csvFile->openWrite();

		$row = ['file', 'key'];
		foreach ($this->languages as $langId)
		{
			$row[] = $langId;
		}
		$csvFile->put($row);
		$csvFile->close();

		return $csvFile;
	}

	/**
	 * Apply module configuration to exporting csv file.
	 *
	 * @param Translate\IO\CsvFile $csvFile Object to configure.
	 *
	 * @return void
	 */
	protected function configureExportCsvFile(Translate\IO\CsvFile $csvFile): void
	{
		$csvFile
			->setRowDelimiter(Translate\IO\CsvFile::LINE_DELIMITER_WIN)
			->prefaceWithUtf8Bom($this->encodingOut === 'utf-8')
		;

		switch (Translate\Config::getOption(Translate\Config::OPTION_EXPORT_CSV_DELIMITER))
		{
			case 'TAB':
				$csvFile->setFieldDelimiter(Translate\IO\CsvFile::DELIMITER_TAB);
				break;
			case 'ZPT':
				$csvFile->setFieldDelimiter(Translate\IO\CsvFile::DELIMITER_ZPT);
				break;
			case 'TZP':
			default:
				$csvFile->setFieldDelimiter(Translate\IO\CsvFile::DELIMITER_TZP);
		}
	}

	/**
	 * Generate name for exporting file.
	 *
	 * @param string $path Exporting path.
	 * @param string[] $languages List of exporting languages.
	 *
	 * @return string
	 */
	protected function generateExportFileName(string $path, array $languages): string
	{
		return \trim(\str_replace(['.php', '/'], ['', '_'], $path), '_').'_'.\implode('_', $languages).'.csv';
	}

	/**
	 * Returns exported file properties.
	 *
	 * @return array
	 */
	public function getDownloadingParameters(): array
	{
		return [
			'fileName' => $this->exportFileName,
			'filePath' => $this->exportFilePath,
			'fileType' => $this->exportFileType,
			'fileSize' => $this->exportFileSize,
		];
	}

	/**
	 * Returns exported file properties.
	 *
	 * @return array
	 */
	public function getDownloadingSamplesParameters(): array
	{
		return [
			'fileName' => $this->samplesFileName,
			'filePath' => $this->samplesFilePath,
			'fileType' => $this->exportFileType,
			'fileSize' => $this->samplesFileSize,
		];
	}

	/**
	 * Merges all language files into one array.
	 *
	 * @param string $langFilePath Relative project path of the language file.
	 * @param string[] $fullLangFilePaths Array of full paths to lang files.
	 * @param bool $collectUntranslated Collect only untranslated phrases.
	 * @param string[] $filterByCodeList Array of prase codes to filter.
	 *
	 * @return array
	 */
	public function mergeLangFiles(
		string $langFilePath,
		array $fullLangFilePaths,
		bool $collectUntranslated = false,
		array $filterByCodeList = []
	): array
	{
		$mergedContent = [];

		$rowLang0 = [];
		foreach ($this->languages as $langId)
		{
			$rowLang0[$langId] = '';
		}

		$filterByCode = !empty($filterByCodeList);

		foreach ($this->languages as $langId)
		{
			if (empty($fullLangFilePaths[$langId]))
			{
				continue;
			}

			$fullPath = $fullLangFilePaths[$langId];
			$file = new Translate\File($fullPath);
			$file->setLangId($langId);

			if ($this->convertEncoding)
			{
				$file->setOperatingEncoding($this->encodingOut);
			}
			else
			{
				$file->setOperatingEncoding(Main\Localization\Translation::getSourceEncoding($langId));
			}

			if (!$file->loadTokens())
			{
				if (!$file->load())
				{
					continue;
				}
			}

			foreach ($file as $code => $phrase)
			{
				if ($filterByCode)
				{
					if (!\in_array($code, $filterByCodeList))
					{
						continue;
					}
				}
				if (!isset($mergedContent[$code]))
				{
					$mergedContent[$code] = \array_merge(['file' => $langFilePath, 'key' => $code], $rowLang0);
				}
				$mergedContent[$code][$langId] = $phrase;
			}
		}

		if ($collectUntranslated)
		{
			// settings
			$hasObligatorySetting = false;
			if ($settingsFile = Translate\Settings::instantiateByPath(self::$documentRoot. '/'. $langFilePath))
			{
				if ($settingsFile->load())
				{
					$langSettings = $settingsFile->getOptions($langFilePath);
					$hasObligatorySetting = !empty($langSettings[Translate\Settings::OPTION_LANGUAGES]);
				}
			}

			foreach ($mergedContent as $code => $row)
			{
				foreach ($row as $langId => $phr)
				{
					if ($langId == 'file' || $langId == 'key')
					{
						continue;
					}
					$isObligatory = true;
					if ($hasObligatorySetting)
					{
						$isObligatory = \in_array($langId, $langSettings[Translate\Settings::OPTION_LANGUAGES]);
					}
					if (empty($phr) && ($phr !== '0') && $isObligatory)
					{
						continue 2;
					}
				}
				unset($mergedContent[$code]);
			}
		}

		return $mergedContent;
	}


	/**
	 * Runs through lang folder and collects full path to lang files.
	 *
	 * @param string $langPath Relative project path of the language folder.
	 *
	 * @return \Generator|array|iterable
	 */
	public function lookThroughLangFolder(string $langPath): iterable
	{
		$files = [];
		$folders = [];

		foreach ($this->languages as $langId)
		{
			$langFolderRelPath = Translate\IO\Path::replaceLangId($langPath, $langId);
			$langFolderFullPath = Translate\IO\Path::tidy(self::$documentRoot.'/'.$langFolderRelPath);

			if (self::$useTranslationRepository && \in_array($langId, self::$translationRepositoryLanguages))
			{
				$langFolderFullPath = Main\Localization\Translation::convertLangPath($langFolderFullPath, $langId);
			}

			$childrenList = Translate\IO\FileSystemHelper::getFileList($langFolderFullPath);
			if (!empty($childrenList))
			{
				foreach ($childrenList as $fullPath)
				{
					$name = \basename($fullPath);
					if (\in_array($name, Translate\IGNORE_FS_NAMES))
					{
						continue;
					}

					if (Translate\IO\Path::isPhpFile($fullPath, true))
					{
						$files[$langPath.'/'.$name][$langId] = $fullPath;
					}
				}
			}

			// dir only
			$childrenList = Translate\IO\FileSystemHelper::getFolderList($langFolderFullPath);
			if (!empty($childrenList))
			{
				$ignoreDev = \implode('|', Translate\IGNORE_MODULE_NAMES);
				foreach ($childrenList as $fullPath)
				{
					$name = \basename($fullPath);
					if (\in_array($name, Translate\IGNORE_FS_NAMES))
					{
						continue;
					}

					$relPath = $langFolderRelPath.'/'.$name;

					if (!\is_dir($fullPath))
					{
						continue;
					}

					if (\in_array($relPath, Translate\IGNORE_BX_NAMES))
					{
						continue;
					}

					// /bitrix/modules/[smth]/dev/
					if (\preg_match("#^bitrix/modules/[^/]+/({$ignoreDev})$#", \trim($relPath, '/')))
					{
						continue;
					}

					if (\in_array($name, Translate\IGNORE_LANG_NAMES))
					{
						continue;
					}

					$folders[$langPath.'/'.$name] = $langPath.'/'.$name;
				}
			}
		}

		if (\count($files) > 0)
		{
			yield $files;
		}

		if (\count($folders) > 0)
		{
			foreach ($folders as $subFolderPath)
			{
				foreach ($this->lookThroughLangFolder($subFolderPath) as $subFiles)// go deeper
				{
					yield $subFiles;
				}
			}
		}
	}

	/**
	 * Looks for exact translation sample of the phrase.
	 *
	 * @param string $searchPhrase Phrase to look for.
	 * @param string $searchLangId Phrase lang to look for.
	 * @param int|string $stripPath Strip current file.
	 * @param int $limit Limit search result.
	 * @param int[] $restrictByPathId
	 * @return array
	 */
	public function findSamples(string $searchPhrase, string $searchLangId, $stripPath, int $limit = 50, array $restrictByPathId = []): array
	{
		$select = [
			'PATH_ID' => 'PATH_ID',
			'PHRASE_CODE' => 'CODE',
			'FILE_PATH' => 'PATH.PATH',
		];

		$phraseFilter = [];

		if (!Index\PhraseIndexSearch::disallowFtsIndex($searchLangId))
		{
			$minLengthFulltextWorld = Index\PhraseIndexSearch::getFullTextMinLength();
			$fulltextIndexSearchStr = Index\PhraseIndexSearch::prepareTextForFulltextSearch($searchPhrase);
			if (\mb_strlen($fulltextIndexSearchStr) > $minLengthFulltextWorld)
			{
				$phraseFilter['*=PHRASE'] = $fulltextIndexSearchStr;
			}
		}

		$phraseFilter['=PHRASE'] = $searchPhrase;
		if (is_numeric($stripPath))
		{
			$phraseFilter['!=PATH_ID'] = $stripPath;
		}
		else
		{
			$phraseFilter['!=PATH.PATH'] = $stripPath;
		}

		if (!empty($restrictByPathId))
		{
			$phraseFilter['=PATH.DESCENDANTS.PARENT_ID'] = $restrictByPathId; //ancestor
		}

		$ftsClass = Index\Internals\PhraseFts::getFtsEntityClass($searchLangId);

		/** @var Main\ORM\Query\Result $cachePathRes */
		$phraseInxRes = $ftsClass::getList([
			'filter' => $phraseFilter,
			'select' => $select,
			'limit' => $limit,
		]);

		$samples = [];
		$fileInxCache = [];
		while ($phraseInx = $phraseInxRes->fetch())
		{
			$pathId = (int)$phraseInx['PATH_ID'];
			$phraseCode = $phraseInx['PHRASE_CODE'];

			if (!isset($fileInxCache[$pathId]))
			{
				$fullPaths = $this->getFullPath($pathId);
				$fileInxCache[$pathId] = $this->mergeLangFiles($phraseInx['FILE_PATH'], $fullPaths);
			}

			if (
				isset($fileInxCache[$pathId][$phraseCode])
				&& $fileInxCache[$pathId][$phraseCode][$searchLangId] == $searchPhrase
			)
			{
				$samples[] = $fileInxCache[$pathId][$phraseCode];
			}
		}

		return $samples;
	}

	/**
	 * Returns list of full paths for lang path.
	 * @param int $pathId
	 * @return array
	 */
	protected function getFullPath(int $pathId): array
	{
		if (!isset($this->fullPathCache[$pathId]))
		{
			$this->fullPathCache[$pathId] = [];
			$fileInxRes = Translate\Index\Internals\FileIndexTable::getList([
				'filter' => ['=PATH_ID' => $pathId],
				'order' => ['ID' => 'ASC'],
				'select' => ['LANG_ID', 'FULL_PATH'],
			]);
			while ($fileInx = $fileInxRes->fetch())
			{
				$this->fullPathCache[$pathId][$fileInx['LANG_ID']] = $fileInx['FULL_PATH'];
			}
		}

		return $this->fullPathCache[$pathId];
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit