Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -0,0 +1,56 @@
<?php
namespace Xentral\Components\Backup\Adapter;
use Xentral\Components\Database\DatabaseConfig;
/**
* Interface AdapterInterface
*
* @package Xentral\Components\Backup\Adapter
*/
interface AdapterInterface
{
/** @var string STATUS_WORKING */
const STATUS_WORKING = 'working';
/** @var string STATUS_WAIT */
const STATUS_WAITING = 'waiting';
/**
* Makes MySQL DUMP
*
* @param DatabaseConfig $config
*
* @param string $file
*
* @param null|string|array $sTable
*
* @param null|string $where
*
* @param bool $quickMode Without SET INNODB_STRICT_MODE=0; Advantage quick and space-saving
*
* @return int PidFile
*/
public function createDump(DatabaseConfig $config, $file, $sTable = null, $where = null, $quickMode=true);
/**
* Makes Backup or System template recovery
*
* @param DatabaseConfig $config
* @param string $file
*
* @return int pidFile
*/
public function restoreDump(DatabaseConfig $config, $file);
/**
* returns the current status
*
* @param string $pidFile
*
* @return string|self::STATUS_WORKING|self::STATUS_WAITING
*/
public function getStatus($pidFile);
}
@@ -0,0 +1,83 @@
<?php
namespace Xentral\Components\Backup\Adapter;
use Xentral\Components\Database\DatabaseConfig;
final class ExecAdapter implements AdapterInterface
{
/** @var DatabaseConfig $config */
private $config;
/** @var int timeout */
const TIME_OUT = 3600;
/**
* @param DatabaseConfig $config
* @param string $file
*
* @param null|string|array $tables
*
* @param null|string $where
*
* @param bool $quickMode Without SET INNODB_STRICT_MODE=0; Advantage quick and space-saving
*
* @return void
*/
public function createDump(DatabaseConfig $config, $file, $tables = null, $where = null, $quickMode = true)
{
$this->config = $config;
$sAsBackup = $this->config->getDatabase();
if ($tables !== null) {
if (is_array($tables)) {
$tables = implode(' ', $tables);
}
$sAsBackup .= ' --tables ' . $tables;
}
if ($where !== null) {
$sAsBackup .= " --where=\"$where\"";
}
if ($quickMode !== true) {
$cmd = "echo 'SET INNODB_STRICT_MODE=0;' > {$file} && mysqldump --no-tablespaces --extended-insert {$sAsBackup} --no-create-db -h{$this->config->getHostname()} -u{$this->config->getUsername()} -p'{$this->config->getPassword()}' >> {$file} && gzip -c {$file} > " . $file . '.gz && rm -f' . $file;
} else {
$cmd = "mysqldump --no-tablespaces --extended-insert {$sAsBackup} --no-create-db -h{$this->config->getHostname()} -u{$this->config->getUsername()} -p'{$this->config->getPassword()}' | gzip > " . $file . '.gz';
}
$this->execute($cmd);
}
/**
* @param DatabaseConfig $config
* @param string $file
*
* @return void
*/
public function restoreDump(DatabaseConfig $config, $file)
{
$this->config = $config;
$cmd = "gunzip < {$file} | mysql -D{$this->config->getDatabase()} -h{$this->config->getHostname()} -u{$this->config->getUsername()} -p'{$this->config->getPassword()}'";
$this->execute($cmd);
}
/**
* @param string $pidFile
*
* @return string
*/
public function getStatus($pidFile)
{
if (file_exists($pidFile) && ($time = file_get_contents($pidFile)) && (time() - (int)$time) < static::TIME_OUT) {
return AdapterInterface::STATUS_WORKING;
}
return AdapterInterface::STATUS_WAITING;
}
/**
* @param string $cmd
*/
protected function execute($cmd)
{
@exec($cmd);
}
}
+67
View File
@@ -0,0 +1,67 @@
<?php
namespace Xentral\Components\Backup;
use ApplicationCore;
use Xentral\Components\Backup\Exception\BackupException;
use Xentral\Components\Backup\Adapter\ExecAdapter;
use Xentral\Components\Backup\Logger\BackupLog;
use Xentral\Core\DependencyInjection\ContainerInterface;
final class Bootstrap
{
/**
* @return array
*/
public static function registerServices()
{
return [
'DatabaseBackup' => 'onInitDatabaseBackup',
'FileBackup' => 'onInitFileBackup',
'BackupLog' => 'onInitBackupLogger',
];
}
/**
*
* @param ContainerInterface $container
*
* @return DatabaseBackup
*/
public static function onInitDatabaseBackup(ContainerInterface $container)
{
//@codeCoverageIgnoreStart
if (!function_exists('exec')) {
throw new BackupException(sprintf('function "%s" is missing!', 'exec'));
}
//@codeCoverageIgnoreEnd
/** @var ApplicationCore $app */
$app = $container->get('LegacyApplication');
return new DatabaseBackup(new ExecAdapter(), $app->erp->getTMP());
}
/**
* @param ContainerInterface $container
*
* @return FileBackup
*/
public static function onInitFileBackup(ContainerInterface $container)
{
/** @var ApplicationCore $app */
$app = $container->get('LegacyApplication');
return new FileBackup($container->get('BackupLog'), $app->erp->getTMP());
}
public static function onInitBackupLogger(ContainerInterface $container)
{
/** @var ApplicationCore $app */
$app = $container->get('LegacyApplication');
/** @var string $path */
$path = $app->erp->GetRootPath() . DIRECTORY_SEPARATOR . 'backup' . DIRECTORY_SEPARATOR;
return new BackupLog($path, 'status.txt');
}
}
@@ -0,0 +1,190 @@
<?php
namespace Xentral\Components\Backup;
use Xentral\Components\Backup\Adapter\AdapterInterface;
use Xentral\Components\Database\DatabaseConfig;
use Xentral\Components\Backup\Exception\BackupException;
final class DatabaseBackup
{
/**
* @var AdapterInterface
*/
private $adapter;
/** @var string $tmpPath */
private $tmpPath;
/** @var string lock */
const PID_NAME = 'backup.lock';
/**
* DatabaseBackup constructor.
*
* @param AdapterInterface $adapter
*
* @param string $tmpPath
*/
public function __construct(AdapterInterface $adapter, $tmpPath)
{
$this->adapter = $adapter;
$this->tmpPath = $tmpPath;
}
/**
* Creates MySQL Dump
*
* @param DatabaseConfig $config
* @param string $file
* @param null|string|array $sTable
*
* @param null|string $where
*
* @return void
*/
public function createDump(DatabaseConfig $config, $file, $sTable = null, $where = null)
{
$sPidFile = $this->getLockFile();
file_put_contents($sPidFile, time());
$this->adapter->createDump($config, $file, $sTable, $where);
@unlink($sPidFile);
}
/**
* Restores Database DUMP
*
* @param DatabaseConfig $config
* @param string $file
*
* @return void
*/
public function restoreDump(DatabaseConfig $config, $file)
{
if (!file_exists($file)) {
throw new BackupException(sprintf('Database Dump %s not found!', $file));
}
$sPidFile = $this->getLockFile();
file_put_contents($sPidFile, time());
$this->adapter->restoreDump($config, $file);
@unlink($sPidFile);
}
/**
* @param string $metaFile
*
* @return string|null
*/
public function getMetaInfo($metaFile)
{
if (!empty($metaFile) && file_exists($metaFile) && ($sMetaEnc = file_get_contents($metaFile))) {
return $this->decodeJson(base64_decode($sMetaEnc), true);
}
return null;
}
/**
* @param string $sJSON
* @param bool $bAsHash
*
* @return mixed|null
*/
protected function decodeJson($sJSON, $bAsHash = false)
{
if (($xData = json_decode($sJSON, $bAsHash)) !== null
&& (json_last_error() === JSON_ERROR_NONE)) {
return $xData;
}
return null;
}
/**
*
* @return string|AdapterInterface
*/
public function getLockStatus()
{
return $this->adapter->getStatus($this->getLockFile());
}
/**
* @return string
*/
protected function getLockFile()
{
return rtrim($this->tmpPath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . static::PID_NAME;
}
/**
* @param array $tables
* @param array $excludeKeys
*
* @return mixed
*/
public function excludeCheckSumTables($tables, $excludeKeys = [])
{
$default = [
'backup',
'useronline',
'logfile',
'cronjob_starter_running',
'wiki',
'protokoll',
'cronjob_log',
'module_stat',
'checkaltertable',
'konfiguration',
'permissionhistory',
'adapterbox_request_log',
'hook',
'module_action',
'prozessstarter',
'sqlcache',
'systemhealth',
'userkonfiguration',
'artikel',
'shopimport_amazon_throttling',
'lieferschein',
'report_column',
'report_parameter',
'notification_message',
'module_stat_detail',
];
$excludeKeys = array_merge($default, $excludeKeys);
foreach ($excludeKeys as $key) {
if (!array_key_exists($key, $tables)) {
continue;
}
unset($tables[$key]);
}
return $tables;
}
/**
* @param string $backupFile
*
* @return string
*/
public function getMetaFileName($backupFile)
{
$asFile = explode('.', $backupFile);
array_pop($asFile);
$filename = implode('.', $asFile) . '.meta';
return str_replace('.backup', 'backup/snapshots', $filename);
}
/**
* @param string $filePath
*
* @return string|null
*/
public function getDumpMetaData($filePath = null)
{
return $this->getMetaInfo($this->getMetaFileName($filePath));
}
}
@@ -0,0 +1,9 @@
<?php
namespace Xentral\Components\Backup\Exception;
use RuntimeException;
class BackupException extends RuntimeException implements BackupExceptionInterface
{
}
@@ -0,0 +1,14 @@
<?php
namespace Xentral\Components\Backup\Exception;
use Xentral\Core\Exception\ComponentExceptionInterface;
/**
* Interface BackupExceptionInterface
*
* @package Xentral\Components\Backup\Exception
*/
interface BackupExceptionInterface extends ComponentExceptionInterface
{
}
@@ -0,0 +1,12 @@
<?php
namespace Xentral\Components\Backup\Exception;
use RuntimeException;
class LogException extends RuntimeException implements BackupExceptionInterface
{
}
+451
View File
@@ -0,0 +1,451 @@
<?php
namespace Xentral\Components\Backup;
use PHPUnit\Runner\Exception;
use Xentral\Components\Backup\Logger\BackupLog;
use Xentral\Components\Backup\Exception\BackupException;
use ZipArchive;
final class FileBackup implements FileBackupInterface
{
/** @var string backup path */
private $sUserPath;
/** @var BackupLog $logger */
private $logger;
/** @var string $cacheTmp */
private $cacheTmp;
/**
* @param BackupLog $logger
* @param string $cacheTmp
*/
public function __construct(BackupLog $logger, $cacheTmp)
{
$this->logger = $logger;
$this->cacheTmp = $cacheTmp;
}
/**
* @return string
*/
protected function getMainPath()
{
$asPath = explode(DIRECTORY_SEPARATOR, $this->sUserPath);
array_pop($asPath);
return implode(DIRECTORY_SEPARATOR, $asPath) . DIRECTORY_SEPARATOR;
}
/**
* returns the full file name path
*
* @param string $filename
* @param bool $bIsSnapshots
* @param null $userPath
*
* @throws BackupException
* @return string
*/
public function getLocalPath($filename, $userPath = null, $bIsSnapshots = true)
{
if (null !== $userPath) {
$this->sUserPath = $userPath;
}
$path = $this->getMainPath();
if ($bIsSnapshots === true) {
$path .= FileBackupInterface::SNAPSHOTS_FOLDER . DIRECTORY_SEPARATOR;
}
if (!file_exists($path) && !@mkdir($path) && !is_dir($path)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not created', $path));
throw new BackupException(sprintf('Directory "%s" was not created', $path));
}
return $path . $filename;
}
/**
* @return string
*/
private function tmpDir()
{
return $this->getMainPath() . 'backup/.backup' . DIRECTORY_SEPARATOR;
}
/**
* @return string
*/
public function getSnapshotsDir()
{
return $this->getMainPath() . FileBackupInterface::SNAPSHOTS_FOLDER . DIRECTORY_SEPARATOR;
}
/**
* @param $path
*
* @return false|int
*/
protected function addLock($path)
{
return $this->logger->write(time(), $path, FileBackupInterface::PID_FILE, false, false);
}
/**
* @return bool
*/
private function tryPurgePidFile()
{
$pidFile = $this->tmpDir() . FileBackupInterface::PID_FILE;
$time = file_get_contents($pidFile);
if ((time() - (int)$time > FileBackupInterface::TIME_OUT)) {
return unlink($pidFile);
}
return false;
}
/**
* @param string|null $userPath
*
* @throws BackupException
* @return string|null
*/
public function begin($userPath = null)
{
if (null !== $userPath) {
$this->sUserPath = $userPath;
}
$path = $this->tmpDir();
if (is_dir($path)) {
@exec('rm -rf ' . $path);
}
$backupDir = $this->getMainPath() . 'backup';
if (file_exists($backupDir . DIRECTORY_SEPARATOR . 'status.txt')) {
@unlink($backupDir . DIRECTORY_SEPARATOR . 'status.txt');
}
if (file_exists($backupDir . DIRECTORY_SEPARATOR . 'session.txt')) {
@unlink($backupDir . DIRECTORY_SEPARATOR . 'session.txt');
}
if (!file_exists($path) && !@mkdir($path, 0777, true) && !is_dir($path)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not created', $path));
throw new BackupException(sprintf('Directory "%s" was not created', $path));
}
if ($this->getLockStatus() === FileBackupInterface::STATUS_WORKING && $this->tryPurgePidFile() === false) {
return null;
//throw new BackupException(sprintf('Backup is Running'));
}
if ($this->addLock($path) === false) {
$this->logger->writePersistent('Failed start backup');
throw new BackupException('Failed start backup');
}
return $path;
}
/**
* @param string $file
*
* @return bool
*/
protected function cleanUp($file)
{
$path = $this->tmpDir();
if ($this->moveDir($path . $file, $this->getLocalPath($file)) === true) {
return $this->deleteDir($path);
}
$this->logger->writePersistent(sprintf('Clean Up of %s failed', $path));
throw new BackupException(sprintf('Clean Up of %s failed', $path));
}
/**
* @param string $class_name
*
* @return bool
*/
protected function classExists($class_name)
{
return class_exists($class_name);
}
/**
* @param ZipArchive $oZip
* @param string $fileName
* @param int $flags
*
* @return mixed
*/
protected function openZipObject($oZip, $fileName, $flags = 0)
{
return $oZip->open($fileName, $flags);
}
/**
* @param string $oldDir
* @param string $newDir
*
* @return bool
*/
protected function moveDir($oldDir, $newDir)
{
return @rename($oldDir, $newDir);
}
/**
* @param string $dir
*
* @return bool
*/
protected function isDir($dir)
{
return @mkdir($dir) || is_dir($dir);
}
/**
* @return string
*/
public function getBackupExtension()
{
return FileBackupInterface::COMPRESS_EXTENSION;
}
/**
* @param string $filename Zipped file name
* @param string $userPath local directory to backup
* @param string|null $sMySQLFile MySQL Backup file
*
* @return bool
*/
public function createBackup($filename, $userPath, $sMySQLFile = null)
{
$this->sUserPath = $userPath;
$rootPath = realpath($userPath);
if (!file_exists($userPath)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not found', $userPath));
throw new BackupException(sprintf('Directory "%s" was not found', $userPath));
}
$tmpFilename = $this->tmpDir() . $filename;
$sMySQLFullPath = $this->tmpDir() . $sMySQLFile;
if (null !== $sMySQLFile && is_file($sMySQLFullPath) && filesize($sMySQLFullPath) > 1024) {
$this->logger->write('Add MySQL file to Zip');
exec('cd ' . $rootPath . ' && mv ' . $sMySQLFullPath . ' ' . $sMySQLFile);
}
exec('cd ' . $rootPath . ' && zip -r -9 ' . $tmpFilename . ' * .[^.]* -x "wiki/*"');
if (null !== $sMySQLFile) {
exec('cd ' . $rootPath . ' && rm -f ' . $sMySQLFile);
}
return $this->cleanUp($filename);
}
/**
* @param string $dirPath
*
* @return bool
*/
private function deleteDir($dirPath)
{
if (is_dir($dirPath)) {
if (substr($dirPath, strlen($dirPath) - 1, 1) !== '/') {
$dirPath .= '/';
}
$files = glob($dirPath . '*', GLOB_MARK);
foreach ($files as $file) {
if (is_dir($file)) {
$this->deleteDir($file);
} else {
unlink($file);
}
}
return rmdir($dirPath);
}
$this->logger->writePersistent(sprintf('Deleted DIR %s failed', $dirPath));
throw new BackupException(sprintf('Deleted DIR %s failed', $dirPath));
}
/**
* @param string $backupFile
* @param string $userPath
* @param array $options
*
* @return bool
*/
public function restoreFileSystem($backupFile, $userPath, $options = [])
{
$default = ['template_file_dir' => null, 'exclude_dir' => ['wiki']];
$options = array_merge($default, $options);
$templateFileDir = $options['template_file_dir'];
$this->sUserPath = $userPath;
$bIsSnapshots = null === $templateFileDir;
$this->sUserPath = null === $templateFileDir ? $userPath : $templateFileDir;
if (file_exists($file = $this->getLocalPath($backupFile, null, $bIsSnapshots))) {
$userDataPath = realpath($userPath);
$tmpExtract = $this->tmpDir() . FileBackupInterface::LOCAL_FILES_DIR_NAME . 'tmp';
if (!file_exists($tmpExtract) && !@mkdir($tmpExtract) && !is_dir($tmpExtract)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not created', $tmpExtract));
throw new BackupException(sprintf('Directory "%s" was not created', $tmpExtract));
}
if (!$this->classExists('ZipArchive')) {
$this->logger->writePersistent('Class ZipArchive is missing!');
throw new BackupException('Class ZipArchive is missing!');
}
$oZip = new ZipArchive();
if ($this->openZipObject($oZip, $file, ZipArchive::CHECKCONS) !== true) {
$this->logger->writePersistent(sprintf('Failure to open file in "%s"', $file));
throw new BackupException(sprintf('Failure to open file in "%s"', $file));
}
$oZip->extractTo($tmpExtract);
$oZip->close();
// move user data
$shortTmp = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '.rmTmp';
$sBeforeTmp = $shortTmp . uniqid('', true) . 'before';
if (!$this->isDir($sBeforeTmp)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not created', $sBeforeTmp));
throw new BackupException(sprintf('Directory "%s" was not created', $sBeforeTmp));
}
$this->logger->write('Moving userdata away');
if (!$this->moveDir($userDataPath, $sBeforeTmp)) {
$this->logger->writePersistent(sprintf('Moving %s into %s failed! ', $userDataPath, $sBeforeTmp));
throw new BackupException(sprintf('Moving %s into %s failed! ', $userDataPath, $sBeforeTmp));
}
if (array_key_exists('exclude_dir', $options) && is_array($options['exclude_dir'])) {
$this->excludeDirectory($options['exclude_dir'], $tmpExtract, $sBeforeTmp);
}
$this->logger->write('Recovering userData');
if (!$this->moveDir($tmpExtract, $userDataPath)) {
$this->logger->writePersistent(sprintf('Moving %s into %s failed!', $tmpExtract, $userDataPath));
throw new BackupException(sprintf('Moving %s into %s failed!', $tmpExtract, $userDataPath));
}
// FIX TMP ISSUE
if (!empty($this->cacheTmp) && is_dir($this->cacheTmp)) {
$this->logger->write('Delete DB tmp');
$this->deleteDir($this->cacheTmp);
}
// remove DB if exists
$backupFileExploded = explode('.', $backupFile);
array_pop($backupFileExploded);
$tmpSql = implode('.', $backupFileExploded) . '.sql.gz';
if (is_file($userDataPath . DIRECTORY_SEPARATOR . $tmpSql)) {
exec('cd ' . $userDataPath . ' && rm -f ' . $tmpSql);
}
return $this->deleteDir($this->tmpDir()) && $this->deleteDir($sBeforeTmp);
}
return false;
}
/**
* @param array $excludeDir
* @param string $tmpDir extracted temporally directory
* @param string $oldUserDataDir
*/
protected function excludeDirectory($excludeDir = [], $tmpDir, $oldUserDataDir)
{
foreach ($excludeDir as $directory) {
// EXCLUDE WIKI DIRECTORY
$keepPath = $tmpDir . DIRECTORY_SEPARATOR . $directory;
$keepDirTmp = $oldUserDataDir . DIRECTORY_SEPARATOR . $directory;
if (!is_dir($keepPath) && $directory !== 'wiki') {
$this->logger->writePersistent(sprintf('Directory "%s" cannot be skipped', $keepPath));
throw new BackupException(sprintf('Directory "%s" cannot be skipped', $keepPath));
}
if ($directory !== 'wiki') {
$this->deleteDir($keepPath);
}
if (file_exists($keepDirTmp)) {
$oldDirTmp = rtrim(
sys_get_temp_dir(),
DIRECTORY_SEPARATOR
) . DIRECTORY_SEPARATOR . '.' . $directory . 'Tmp' . uniqid('', true);
if (!$this->isDir($oldDirTmp)) {
$this->logger->writePersistent(sprintf('Directory "%s" was not created', $oldDirTmp));
throw new BackupException(sprintf('Directory "%s" was not created', $oldDirTmp));
}
$oldDir = $oldDirTmp . DIRECTORY_SEPARATOR . $directory;
if (!$this->moveDir($keepDirTmp, $oldDir)) {
$this->logger->writePersistent(sprintf('Could not move %s directory into "%s"', $directory,
$oldDir));
throw new BackupException(sprintf('Could not move %s directory into "%s"', $directory,
$oldDir));
}
}
// Reset Latest WIKI Directory
if (isset($oldDir) && is_dir($oldDir)) {
$this->logger->write('Reset Wiki Directory');
if (!$this->moveDir($oldDir, $keepPath)) {
$this->logger->writePersistent(sprintf('Could not move %s directory into "%s"', $oldDir,
$keepPath));
throw new BackupException(sprintf('Could not move %s directory into "%s"', $oldDir, $keepPath));
}
}
}
}
/**
* @param string|null $userDataDir
*
* @return string
*/
public function getLockStatus($userDataDir = null)
{
if (null !== $userDataDir) {
$this->sUserPath = $userDataDir;
}
$path = $this->tmpDir();
if (file_exists($path . FileBackupInterface::PID_FILE) &&
($time = file_get_contents($path . FileBackupInterface::PID_FILE)) &&
(time() - (int)$time < FileBackupInterface::TIME_OUT)
) {
return FileBackupInterface::STATUS_WORKING;
}
return FileBackupInterface::STATUS_WAITING;
}
/**
* Clean everything without files move. This might be used, when breaking started backup job
*
* @return bool
*/
public function breakCleanUp()
{
return $this->deleteDir($this->tmpDir());
}
}
@@ -0,0 +1,56 @@
<?php
namespace Xentral\Components\Backup;
use Xentral\Components\Backup\Exception\BackupException;
interface FileBackupInterface
{
/** @var string STATUS_WAIT */
const STATUS_WAITING = 'waiting';
/** @var string STATUS_WORKING */
const STATUS_WORKING = 'working';
/** @var string Extension for the whole backup */
const COMPRESS_EXTENSION = 'zip';
/** @var string pid file */
const PID_FILE = 'backup.lock';
/** @var int Timeout */
const TIME_OUT = 3600;
/** @var string snapshots folder */
const SNAPSHOTS_FOLDER = 'backup/snapshots';
/** @var string user data directory */
const LOCAL_FILES_DIR_NAME = 'userdata';
/**
* @param string|null $userPath
*
* @throws BackupException
* @return string|null
*/
public function begin($userPath = null);
/**
* @param string $filename
* @param string $userPath
* @param string|null $sMySQLFile
*
* @return bool
*/
public function createBackup($filename, $userPath, $sMySQLFile = null);
/**
* @param string $backupFile
* @param string $userPath
* @param array $options
*
* @return bool
*/
public function restoreFileSystem($backupFile, $userPath, $options = []);
/**
* @return string
*/
public function getLockStatus();
}
@@ -0,0 +1,172 @@
<?php
namespace Xentral\Components\Backup\Logger;
use Xentral\Components\Backup\Exception\LogException;
final class BackupLog
{
/** @var string|null $path */
private $fullPath;
/** @var string|null $storagePath */
private $storagePath;
/** @var string|null $fileName */
private $fileName;
/** @var string $persistentFile */
private static $persistentFile = 'backup_logger.txt';
public function __construct($path = null, $fileName = null)
{
if (null !== $path && null !== $fileName) {
$this->fullPath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName;
}
$this->storagePath = $path;
$this->fileName = $fileName;
}
/**
* @param string $message
*
* @param string|null $path
* @param string|null $fileName
*
* @param bool $withDate
*
* @param bool $append
*
* @return false|int
*/
public function write($message, $path = null, $fileName = null, $withDate = true, $append = true)
{
$flag = FILE_APPEND | LOCK_EX;
$path = $this->getFullPath($path, $fileName);
if (null === $path || (!file_exists($path) && !@touch($path))) {
throw new LogException(sprintf('cannot access or create file %s', $path));
}
$message = $withDate === true ? time() . ': ' . $message : $message;
if ($append === false) {
$flag &= ~FILE_APPEND;
}
return file_put_contents($path, $message . "\n", $flag);
}
/**
* @param int $linePosition
*
* @param string|null $path
*
* @param string|null $fileName
*
* @return mixed|string
*/
public function tail($linePosition = 0, $path = null, $fileName = null)
{
$path = $this->getFullPath($path, $fileName);
if (null === $path || !file_exists($path)) {
throw new LogException(sprintf('File %s cannot be found!', $path));
}
$output = '';
if (($xData = file($path, FILE_SKIP_EMPTY_LINES)) && count($xData) > 0) {
$key = (int)$linePosition === 0 ? count($xData) - 1 : $linePosition;
if (!array_key_exists($key, $xData)) {
throw new LogException(sprintf('Offset %d is missing', (int)$linePosition));
}
$output = $xData[$key];
}
return $output;
}
/**
* @param string|null $path
*
* @param string|null $fileName
*
* @return bool|false|string
*/
public function getContent($path = null, $fileName = null)
{
$path = $this->getFullPath($path, $fileName);
if (null === $path || !file_exists($path)) {
throw new LogException(sprintf('File %s cannot be found!', $path));
}
return file_get_contents($path);
}
/**
* @param null $path
*
* @param string|null $fileName
*
* @throws LogException
* @return bool
*/
public function delete($path = null, $fileName = null)
{
$path = $this->getFullPath($path, $fileName);
if (null !== $path && !file_exists($path)) {
return false;
//throw new LogException(sprintf('File %s cannot be deleted!', $path));
}
return unlink($path);
}
/**
* @param null $path
* @param null $fileName
*
* @return string|null
*/
private function getFullPath($path = null, $fileName = null)
{
if ($path === null && $fileName === null) {
return $this->fullPath;
}
if ($path !== null && $fileName !== null) {
return rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName;
}
if ($fileName !== null && $path === null && $this->storagePath !== null) {
return rtrim($this->storagePath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $fileName;
}
if ($path !== null && $fileName === null && $this->fileName !== null) {
return rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $this->fileName;
}
return null;
}
/**
* @param string $message
*
* @return void
*/
public function writePersistent($message)
{
$this->write($message, null, self::$persistentFile, true, false);
}
/**
* @return string
*/
public function getPersistentFileName()
{
return self::$persistentFile;
}
}