479 lines
13 KiB
PHP
479 lines
13 KiB
PHP
<?php
|
|
|
|
namespace SGalinski\Lfeditor\Service;
|
|
|
|
/***************************************************************
|
|
* Copyright notice
|
|
*
|
|
* (c) sgalinski Internet Services (https://www.sgalinski.de)
|
|
*
|
|
* All rights reserved
|
|
*
|
|
* This script is part of the TYPO3 project. The TYPO3 project is
|
|
* free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* The GNU General Public License can be found at
|
|
* http://www.gnu.org/copyleft/gpl.html.
|
|
*
|
|
* This script is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* This copyright notice MUST APPEAR in all copies of the script!
|
|
***************************************************************/
|
|
|
|
use Exception;
|
|
use SGalinski\Lfeditor\Exceptions\LFException;
|
|
use SGalinski\Lfeditor\Utility\SgLib;
|
|
use SGalinski\Lfeditor\Utility\Typo3Lib;
|
|
use TYPO3\CMS\Core\Core\Environment;
|
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
|
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
|
|
|
|
/**
|
|
* backup class
|
|
*/
|
|
class FileBackupService extends FileService {
|
|
/**
|
|
* @var string $metaFile
|
|
*/
|
|
private $metaFile;
|
|
|
|
/**
|
|
* @var array $metaArray
|
|
*/
|
|
private $metaArray = [];
|
|
|
|
/**
|
|
* @var string $extName
|
|
*/
|
|
private $extName = '';
|
|
|
|
/**
|
|
* @var string $extPath
|
|
*/
|
|
private $extPath = '';
|
|
|
|
/**
|
|
* @var string $langFile
|
|
*/
|
|
private $langFile = '';
|
|
|
|
/**
|
|
* extended init
|
|
*
|
|
* @throws LFException raised if the meta file cant be correctly read
|
|
* @param string $file name of the file (can be a path, if you need this (no check))
|
|
* @param string $path path to the file
|
|
* @param string $metaFile absolute path to the meta file (includes filename)
|
|
* @return void
|
|
*/
|
|
public function init($file, $path, $metaFile) {
|
|
// init
|
|
$this->setVar(['metaFile' => $metaFile]);
|
|
parent::init($file, $path, $metaFile);
|
|
|
|
// read meta file
|
|
try {
|
|
if (is_file($this->metaFile)) {
|
|
$this->readMetaFile();
|
|
}
|
|
} catch (LFException $e) {
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
#####################
|
|
###### Set/Get ######
|
|
#####################
|
|
|
|
/**
|
|
* sets information
|
|
*
|
|
* structure:
|
|
* $infos["metaFile"] = absolute path to the meta file (includes filename)
|
|
* $infos["extPath"] = extension path
|
|
* $infos["langFile"] = language file
|
|
*
|
|
* @param array $informations information (see above)
|
|
* @return void
|
|
*/
|
|
public function setVar($informations) {
|
|
if (!empty($informations['metaFile'])) {
|
|
$this->metaFile = Typo3Lib::fixFilePath($informations['metaFile']);
|
|
}
|
|
|
|
if (!empty($informations['extPath'])) {
|
|
$this->extPath = Typo3Lib::fixFilePath($informations['extPath']);
|
|
$this->extName = basename($informations['extPath']);
|
|
}
|
|
|
|
if (!empty($informations['langFile'])) {
|
|
$this->langFile = Typo3Lib::fixFilePath($informations['langFile']);
|
|
}
|
|
|
|
parent::setVar($informations);
|
|
}
|
|
|
|
/**
|
|
* returns requested information
|
|
*
|
|
* @param string $info
|
|
* @return mixed
|
|
*/
|
|
public function getVar($info) {
|
|
if ($info == 'metaFile') {
|
|
return $this->metaFile;
|
|
} elseif ($info == 'extName') {
|
|
return $this->extName;
|
|
} elseif ($info == 'extPath') {
|
|
return $this->extPath;
|
|
} elseif ($info == 'langFile') {
|
|
return $this->langFile;
|
|
} else {
|
|
return parent::getVar($info);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* returns meta information about backup files
|
|
*
|
|
* Modes:
|
|
* - 0 => full meta information (default)
|
|
* - 1 => only meta information of given extension key
|
|
* - 2 => only meta information of given extension key and workspace
|
|
* - 3 => only meta information of given extension key, workspace and language file
|
|
*
|
|
* @param integer $mode
|
|
* @param string $extName extension Name (default = $this->extName)
|
|
* @param string $workspace (default = $this->workspace)
|
|
* @param string $langFile language file (default = $this->langFile)
|
|
* @return array
|
|
*/
|
|
public function getMetaInfos($mode = 0, $extName = '', $workspace = '', $langFile = '') {
|
|
$extName = empty($extName) ? $this->extName : $extName;
|
|
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
|
$workspace = empty($workspace) ? $this->workspace : $workspace;
|
|
|
|
// build return value
|
|
if (!$mode) {
|
|
return $this->metaArray;
|
|
} elseif ($mode == 1) {
|
|
return $this->metaArray[$extName] ?? [];
|
|
} elseif ($mode == 2) {
|
|
return $this->metaArray[$extName][$workspace] ?? [];
|
|
} elseif ($mode == 3) {
|
|
return $this->metaArray[$extName][$workspace][$langFile] ?? [];
|
|
} else {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* rewrites current meta information array with the given equivalent
|
|
*
|
|
* Modes:
|
|
* - 0 => full meta information (default)
|
|
* - 1 => only meta information of given extension key
|
|
* - 2 => only meta information of given extension key and workspace
|
|
* - 3 => only meta information of given extension key, workspace and language file
|
|
*
|
|
* @param array $metaArray meta information
|
|
* @param integer $mode
|
|
* @param string $extName extension Name (default = $this->extName)
|
|
* @param string $workspace (default = $this->workspace)
|
|
* @param string $langFile language file (default = $this->langFile)
|
|
* @return void
|
|
*/
|
|
private function setMetaInfos($metaArray, $mode = 0, $extName = '', $workspace = '', $langFile = '') {
|
|
$extName = empty($extName) ? $this->extName : $extName;
|
|
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
|
$workspace = empty($workspace) ? $this->workspace : $workspace;
|
|
|
|
// build new meta information array
|
|
if (is_array($metaArray) && count($metaArray)) {
|
|
if (!$mode) {
|
|
$this->metaArray = $metaArray;
|
|
} elseif ($mode == 1) {
|
|
$this->metaArray[$extName] = $metaArray;
|
|
} elseif ($mode == 2) {
|
|
$this->metaArray[$extName][$workspace] = $metaArray;
|
|
} elseif ($mode == 3) {
|
|
$this->metaArray[$extName][$workspace][$langFile] = $metaArray;
|
|
}
|
|
} else {
|
|
if (!$mode) {
|
|
unset($this->metaArray);
|
|
} elseif ($mode == 1) {
|
|
unset($this->metaArray[$extName]);
|
|
} elseif ($mode == 2) {
|
|
unset($this->metaArray[$extName][$workspace]);
|
|
} elseif ($mode == 3) {
|
|
unset($this->metaArray[$extName][$workspace][$langFile]);
|
|
}
|
|
}
|
|
}
|
|
|
|
###############################
|
|
###### Meta FileService Methods ######
|
|
###############################
|
|
|
|
/**
|
|
* reads the meta information file and parses the content into $this->metaArray
|
|
*
|
|
* @throws LFException raised if no meta content was generated
|
|
* @return void
|
|
*/
|
|
private function readMetaFile() {
|
|
// read file and parse xml to array
|
|
$metaArray = GeneralUtility::xml2array(file_get_contents($this->metaFile));
|
|
if (!is_array($metaArray)) {
|
|
throw new LFException('failure.backup.metaFile.notRead');
|
|
}
|
|
|
|
$this->metaArray = $metaArray;
|
|
}
|
|
|
|
/**
|
|
* generate meta XML
|
|
*
|
|
* @return string meta information (xml)
|
|
*/
|
|
private function genMetaXML() {
|
|
$options = [];
|
|
// define assocTagNames
|
|
$options['parentTagMap'] = [
|
|
'' => 'extKey',
|
|
'extKey' => 'workspace',
|
|
'workspace' => 'langFile',
|
|
'langFile' => 'file',
|
|
];
|
|
return GeneralUtility::array2xml($this->getMetaInfos(), '', 0, 'LFBackupMeta', 0, $options);
|
|
}
|
|
|
|
/**
|
|
* writes the meta information file
|
|
*
|
|
* @throws LFException raised if the meta file cant be written
|
|
* @return void
|
|
*/
|
|
private function writeMetaFile() {
|
|
$metaXML = $this->genMetaXML();
|
|
if (empty($metaXML)) {
|
|
throw new LFException('failure.backup.metaFile.notWritten');
|
|
}
|
|
|
|
if (!GeneralUtility::writeFile($this->metaFile, $this->getXMLHeader() . $metaXML)) {
|
|
throw new LFException('failure.backup.metaFile.notWritten');
|
|
}
|
|
}
|
|
|
|
#################################
|
|
###### Backup FileService Methods ######
|
|
#################################
|
|
|
|
/**
|
|
* generates the xml header
|
|
*
|
|
* @return string xml header
|
|
*/
|
|
private function getXMLHeader() {
|
|
return '<?xml version="1.0" encoding="utf-8" standalone="yes" ?>' . "\n";
|
|
}
|
|
|
|
/**
|
|
* removes the meta information entry and the backup file
|
|
*
|
|
* @param string $filename
|
|
* @param string $extName (default = $this->extName)
|
|
* @param string $langFile (default = $this->langFile)
|
|
* @throws Exception|LFException
|
|
* @throws LFException
|
|
* @return void
|
|
*/
|
|
public function deleteSpecFile($filename, $extName = '', $langFile = '') {
|
|
// get needed meta information
|
|
$extName = empty($extName) ? $this->extName : $extName;
|
|
$langFile = empty($langFile) ? $this->langFile : $langFile;
|
|
$metaArray = $this->getMetaInfos(3, $extName, '', $langFile);
|
|
|
|
// check backup file
|
|
if (!isset($metaArray[$filename])) {
|
|
throw new LFException('failure.backup.notDeleted');
|
|
}
|
|
|
|
// get file
|
|
$backupPath = $metaArray[$filename]['pathBackup'];
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
$file = GeneralUtility::fixWindowsFilePath($pathSite . $backupPath . '/' . $filename);
|
|
|
|
// build new meta information file
|
|
unset($metaArray[$filename]);
|
|
if (!count($metaArray)) {
|
|
$metaArray = NULL;
|
|
}
|
|
$this->setMetaInfos($metaArray, 3, $extName, '', $langFile);
|
|
|
|
$extMetaArray = $this->getMetaInfos(2, $extName);
|
|
if (!count($extMetaArray)) {
|
|
$extMetaArray = NULL;
|
|
}
|
|
$this->setMetaInfos($extMetaArray, 2, $extName);
|
|
|
|
// write meta information
|
|
try {
|
|
$this->writeMetaFile();
|
|
} catch (LFException $e) {
|
|
throw $e;
|
|
}
|
|
|
|
// delete backup file
|
|
try {
|
|
SgLib::deleteFiles([$file]);
|
|
} catch (Exception $e) {
|
|
throw new LFException(
|
|
'failure.backup.notDeleted',
|
|
0,
|
|
'(' . $e->getMessage() . ')',
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* wrapper for deleteSpecFile()
|
|
*
|
|
* @throws LFException raised if the backup or meta file cant be written
|
|
* @return void
|
|
*/
|
|
public function deleteFile() {
|
|
try {
|
|
$this->deleteSpecFile($this->relFile);
|
|
} catch (LFException $e) {
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* reads a backup file
|
|
*
|
|
* @throws LFException raised if the backup file can't be read
|
|
* @return void
|
|
*/
|
|
public function readFile() {
|
|
if (!is_file($this->absFile)) {
|
|
throw new LFException('failure.backup.notRead');
|
|
}
|
|
|
|
// read file and transform from xml to array
|
|
$phpArray = GeneralUtility::xml2array(file_get_contents($this->absFile));
|
|
if (!is_array($phpArray)) {
|
|
throw new LFException('failure.backup.notRead');
|
|
}
|
|
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
// read array
|
|
$localLang = $originLang = [];
|
|
foreach ($phpArray['data'] as $langKey => $informations) {
|
|
// read origin
|
|
try {
|
|
$originLang[$langKey] = Typo3Lib::transTypo3File($informations['meta']['origin'], TRUE);
|
|
} catch (Exception $e) {
|
|
$originLang[$langKey] = $pathSite . $informations['meta']['origin'];
|
|
}
|
|
|
|
// read data
|
|
if (is_array($informations['langData'])) {
|
|
foreach ($informations['langData'] as $const => $value) {
|
|
$localLang[$langKey][$const] = $value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check
|
|
if (!count($localLang) || !count($originLang)) {
|
|
throw new LFException('failure.backup.notRead');
|
|
}
|
|
|
|
$this->localLang = $localLang;
|
|
$this->originLang = $originLang;
|
|
$this->meta = $phpArray['meta'];
|
|
}
|
|
|
|
/**
|
|
* prepares the final Content
|
|
*
|
|
* @return string prepared content (xml)
|
|
*/
|
|
private function prepareBackupContent() {
|
|
$phpArray = [];
|
|
$options = [];
|
|
// set meta
|
|
$phpArray['meta'] = $this->meta;
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
// set array
|
|
foreach ($this->originLang as $lang => $origin) {
|
|
// set origin
|
|
try {
|
|
$phpArray['data'][$lang]['meta']['origin'] = Typo3Lib::transTypo3File($origin, FALSE);
|
|
} catch (Exception $e) {
|
|
$phpArray['data'][$lang]['meta']['origin'] = substr($origin, strlen($pathSite));
|
|
}
|
|
|
|
// set data
|
|
if (\array_key_exists($lang, $this->localLang) && \is_array($this->localLang[$lang])) {
|
|
foreach ($this->localLang[$lang] as $labelKey => $labelVal) {
|
|
$phpArray['data'][$lang]['langData'][$labelKey] = $labelVal;
|
|
}
|
|
}
|
|
}
|
|
|
|
// define assocTagNames
|
|
$options['parentTagMap'] = [
|
|
'data' => 'languageKey',
|
|
'langData' => 'label'
|
|
];
|
|
|
|
// get xml
|
|
return GeneralUtility::array2xml($phpArray, '', 0, 'LFBackup', 0, $options);
|
|
}
|
|
|
|
/**
|
|
* prepares the backup file and writes the new meta information
|
|
*
|
|
* @param array | NULL $editedLanguages
|
|
* @return array raised if meta file cant be written
|
|
* @throws Exception
|
|
* @throws LFException
|
|
* @return array
|
|
*/
|
|
protected function prepareFileContents($editedLanguages = NULL) {
|
|
$backupFiles = [];
|
|
// get content
|
|
$xml = $this->prepareBackupContent();
|
|
|
|
// get and set name of backup
|
|
$backupName = 'locallang_' . substr(md5(md5($xml)), 0, 10) . '.bak';
|
|
$this->setVar(['relFile' => $backupName]);
|
|
$pathSite = Environment::getPublicPath() . '/';
|
|
// get new meta information
|
|
$metaArray = $this->getMetaInfos(3);
|
|
$metaArray[$this->relFile]['createdAt'] = time();
|
|
$metaArray[$this->relFile]['pathBackup'] = str_replace($pathSite, '', $this->absPath);
|
|
$this->setMetaInfos($metaArray, 3);
|
|
|
|
// write meta information file
|
|
try {
|
|
$this->writeMetaFile();
|
|
} catch (LFException $e) {
|
|
throw $e;
|
|
}
|
|
|
|
$backupFiles[$this->absPath . $this->relFile] = $this->getXMLHeader() . $xml;
|
|
return $backupFiles;
|
|
}
|
|
}
|