Files
2026-09-15 10:35:56 +08:00

129 lines
4.3 KiB
PHP

<?php
declare(strict_types=1);
namespace Esun\MultiLocaleTranslation\Model\Config\Backend;
use Magento\Config\Model\Config\Backend\File;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem;
use Magento\Framework\Filesystem\DriverInterface;
class ServiceAccountFile extends File
{
private const REQUIRED_FIELDS = ['type', 'project_id', 'private_key', 'client_email'];
private string $oldCredentialFile = '';
private string $credentialFileToDelete = '';
public function __construct(
\Magento\Framework\Model\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\App\Config\ScopeConfigInterface $config,
\Magento\Framework\App\Cache\TypeListInterface $cacheTypeList,
\Magento\MediaStorage\Model\File\UploaderFactory $uploaderFactory,
\Magento\Config\Model\Config\Backend\File\RequestData\RequestDataInterface $requestData,
Filesystem $filesystem,
private readonly DriverInterface $fileDriver,
?\Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
?\Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
array $data = []
) {
parent::__construct(
$context,
$registry,
$config,
$cacheTypeList,
$uploaderFactory,
$requestData,
$filesystem,
$resource,
$resourceCollection,
$data
);
$this->_mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
$this->_maxFileSize = 64;
}
public function beforeSave(): static
{
$this->oldCredentialFile = basename((string)$this->getOldValue());
$file = $this->getFileData();
$deleteRequested = is_array($this->getValue()) && !empty($this->getValue()['delete']);
if ($file !== []) {
$this->validateServiceAccountFile((string)$file['tmp_name']);
}
parent::beforeSave();
$newFile = basename((string)$this->getValue());
if ($file !== [] && $newFile !== '') {
$this->fileDriver->changePermissions($this->getCredentialPath($newFile), 0600);
}
if ($this->oldCredentialFile !== ''
&& ($deleteRequested || ($newFile !== '' && $newFile !== $this->oldCredentialFile))
) {
$this->credentialFileToDelete = $this->oldCredentialFile;
}
return $this;
}
public function afterSave(): static
{
parent::afterSave();
if ($this->credentialFileToDelete !== '') {
$oldPath = $this->getCredentialPath($this->credentialFileToDelete);
if ($this->fileDriver->isExists($oldPath)) {
$this->fileDriver->deleteFile($oldPath);
}
}
return $this;
}
protected function _getAllowedExtensions(): array
{
return ['json'];
}
private function validateServiceAccountFile(string $path): void
{
try {
$credentials = json_decode(
$this->fileDriver->fileGetContents($path),
true,
32,
JSON_THROW_ON_ERROR
);
} catch (\Throwable $exception) {
throw new LocalizedException(__('The service account JSON file is invalid.'));
}
if (!is_array($credentials) || ($credentials['type'] ?? '') !== 'service_account') {
throw new LocalizedException(__('The uploaded JSON is not a Google service account key.'));
}
foreach (self::REQUIRED_FIELDS as $field) {
if (!is_string($credentials[$field] ?? null) || trim($credentials[$field]) === '') {
throw new LocalizedException(__('The service account JSON is missing "%1".', $field));
}
}
$privateKey = openssl_pkey_get_private($credentials['private_key']);
if ($privateKey === false) {
throw new LocalizedException(__('The service account private key is invalid.'));
}
}
private function getCredentialPath(string $filename): string
{
return $this->_mediaDirectory->getAbsolutePath(
'esun/multilocale_translation/google/' . basename($filename)
);
}
}