Skip to content

Commit 323aaff

Browse files
committed
refactor: simplified the Backup class
1 parent 499998f commit 323aaff

File tree

2 files changed

+168
-33
lines changed

2 files changed

+168
-33
lines changed

phpmyfaq/src/phpMyFAQ/Administration/Backup.php

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,17 @@
3636
*/
3737
readonly class Backup
3838
{
39+
/** @var BackupRepository */
40+
private BackupRepository $repository;
41+
3942
/**
4043
* Constructor.
4144
*/
4245
public function __construct(
4346
private Configuration $configuration,
4447
private DatabaseHelper $databaseHelper,
4548
) {
49+
$this->repository = new BackupRepository($this->configuration);
4650
}
4751

4852
/**
@@ -58,17 +62,8 @@ public function createBackup(string $backupType, string $backupFile): string
5862
$authKey = sodium_crypto_auth_keygen();
5963
$authCode = sodium_crypto_auth($backupFile, $authKey);
6064

61-
$query = sprintf(
62-
"INSERT INTO %sfaqbackup (id, filename, authkey, authcode, created) VALUES (%d, '%s', '%s', '%s', '%s')",
63-
Database::getTablePrefix(),
64-
$this->configuration->getDb()->nextId(Database::getTablePrefix() . 'faqbackup', 'id'),
65-
$this->configuration->getDb()->escape($fileName),
66-
$this->configuration->getDb()->escape(sodium_bin2hex($authKey)),
67-
$this->configuration->getDb()->escape(sodium_bin2hex($authCode)),
68-
$backupDate,
69-
);
70-
71-
$this->configuration->getDb()->query($query);
65+
// persist backup metadata via repository
66+
$this->getRepository()->add($fileName, sodium_bin2hex($authKey), sodium_bin2hex($authCode), $backupDate);
7267

7368
return $fileName;
7469
}
@@ -78,17 +73,8 @@ public function createBackup(string $backupType, string $backupFile): string
7873
*/
7974
public function verifyBackup(string $backup, string $backupFileName): bool
8075
{
81-
$query = sprintf(
82-
"SELECT id, filename, authkey, authcode, created FROM %sfaqbackup WHERE filename = '%s'",
83-
Database::getTablePrefix(),
84-
$this->configuration->getDb()->escape($backupFileName),
85-
);
86-
87-
$result = $this->configuration->getDb()->query($query);
88-
89-
if ($this->configuration->getDb()->numRows($result) > 0) {
90-
$row = $this->configuration->getDb()->fetchObject($result);
91-
76+
$row = $this->getRepository()->findByFilename($backupFileName);
77+
if ($row !== null) {
9278
return sodium_crypto_auth_verify(
9379
sodium_hex2bin((string) $row->authcode),
9480
$backup,
@@ -101,21 +87,29 @@ public function verifyBackup(string $backup, string $backupFileName): bool
10187

10288
public function generateBackupQueries(string $tableNames): string
10389
{
104-
$backup = implode("\r\n", $this->getBackupHeader($tableNames));
105-
106-
foreach (explode(' ', $tableNames) as $table) {
107-
if ('' !== $table) {
108-
$backup .= implode("\r\n", $this->databaseHelper->buildInsertQueries(
109-
'SELECT * FROM ' . $table,
110-
$table,
111-
));
90+
$backup = implode(
91+
separator: "\r\n",
92+
array: $this->getBackupHeader($tableNames),
93+
);
94+
95+
foreach (explode(
96+
separator: ' ',
97+
string: $tableNames,
98+
) as $tableName) {
99+
if ('' !== $tableName) {
100+
$backup .= implode(
101+
separator: "\r\n",
102+
array: $this->databaseHelper->buildInsertQueries('SELECT * FROM ' . $tableName, $tableName),
103+
);
112104
}
113105
}
114106

115107
return $backup;
116108
}
117109

118-
public function getBackupTableNames(BackupType $backupType): string
110+
/**
111+
* @throws \Exception
112+
*/ public function getBackupTableNames(BackupType $backupType): string
119113
{
120114
$tables = $this->configuration->getDb()->getTableNames(Database::getTablePrefix());
121115
$tableNames = '';
@@ -146,6 +140,8 @@ public function getBackupTableNames(BackupType $backupType): string
146140
}
147141

148142
break;
143+
case BackupType::BACKUP_TYPE_CONTENT:
144+
throw new \Exception(message: 'To be implemented');
149145
}
150146

151147
return $tableNames;
@@ -176,8 +172,8 @@ public function createContentFolderBackup(): string
176172
$zipFile = PMF_ROOT_DIR . DIRECTORY_SEPARATOR . 'content.zip';
177173

178174
$zipArchive = new ZipArchive();
179-
if ($zipArchive->open($zipFile, ZipArchive::CREATE) !== true) {
180-
throw new Exception('Error while creating ZipArchive');
175+
if (!$zipArchive->open($zipFile, ZipArchive::CREATE)) {
176+
throw new Exception(message: 'Error while creating ZipArchive');
181177
}
182178

183179
$files = new RecursiveIteratorIterator(
@@ -197,4 +193,9 @@ public function createContentFolderBackup(): string
197193

198194
return $zipFile;
199195
}
196+
197+
private function getRepository(): BackupRepository
198+
{
199+
return $this->repository;
200+
}
200201
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<?php
2+
3+
/**
4+
* Backup Repository.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public License,
7+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
8+
* obtain one at https://mozilla.org/MPL/2.0/.
9+
*
10+
* @package phpMyFAQ
11+
* @author Thorsten Rinne <[email protected]>
12+
* @copyright 2025 phpMyFAQ Team
13+
* @license https://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
14+
* @link https://www.phpmyfaq.de
15+
* @since 2025-10-16
16+
*/
17+
18+
declare(strict_types=1);
19+
20+
namespace phpMyFAQ\Administration;
21+
22+
use phpMyFAQ\Configuration;
23+
use phpMyFAQ\Database;
24+
25+
readonly class BackupRepository
26+
{
27+
public function __construct(
28+
private Configuration $configuration,
29+
) {
30+
}
31+
32+
public function getNumberOfEntries(): int
33+
{
34+
$query = sprintf('SELECT id FROM %sfaqbackup', Database::getTablePrefix());
35+
36+
return $this->configuration->getDb()->numRows($this->configuration->getDb()->query($query));
37+
}
38+
39+
/**
40+
* @return array<int, object>
41+
*/
42+
public function getAll(): array
43+
{
44+
$table = Database::getTablePrefix() . 'faqbackup';
45+
$query = sprintf('SELECT id, filename, authkey, authcode, created FROM %s ORDER BY id DESC', $table);
46+
47+
$result = $this->configuration->getDb()->query($query);
48+
$data = $this->configuration->getDb()->fetchAll($result);
49+
50+
return is_array($data) ? $data : [];
51+
}
52+
53+
public function findByFilename(string $filename): ?object
54+
{
55+
if ($filename === '') {
56+
return null;
57+
}
58+
59+
$table = Database::getTablePrefix() . 'faqbackup';
60+
$filenameEscaped = $this->configuration->getDb()->escape($filename);
61+
$query = sprintf(
62+
"SELECT id, filename, authkey, authcode, created FROM %s WHERE filename = '%s'",
63+
$table,
64+
$filenameEscaped,
65+
);
66+
67+
$result = $this->configuration->getDb()->query($query);
68+
if ($this->configuration->getDb()->numRows($result) > 0) {
69+
return $this->configuration->getDb()->fetchObject($result) ?: null;
70+
}
71+
72+
return null;
73+
}
74+
75+
public function add(string $filename, string $authKeyHex, string $authCodeHex, string $created): bool
76+
{
77+
if ($filename === '' || $authKeyHex === '' || $authCodeHex === '' || $created === '') {
78+
return false;
79+
}
80+
81+
$table = Database::getTablePrefix() . 'faqbackup';
82+
$id = $this->configuration->getDb()->nextId($table, 'id');
83+
84+
$filenameEscaped = $this->configuration->getDb()->escape($filename);
85+
$authKeyEscaped = $this->configuration->getDb()->escape($authKeyHex);
86+
$authCodeEscaped = $this->configuration->getDb()->escape($authCodeHex);
87+
$createdEscaped = $this->configuration->getDb()->escape($created);
88+
89+
$query = sprintf(
90+
"INSERT INTO %s (id, filename, authkey, authcode, created) VALUES (%d, '%s', '%s', '%s', '%s')",
91+
$table,
92+
$id,
93+
$filenameEscaped,
94+
$authKeyEscaped,
95+
$authCodeEscaped,
96+
$createdEscaped,
97+
);
98+
99+
return (bool) $this->configuration->getDb()->query($query);
100+
}
101+
102+
public function deleteById(int $id): bool
103+
{
104+
if ($id <= 0) {
105+
return false;
106+
}
107+
108+
$table = Database::getTablePrefix() . 'faqbackup';
109+
$query = sprintf('DELETE FROM %s WHERE id = %d', $table, $id);
110+
111+
return (bool) $this->configuration->getDb()->query($query);
112+
}
113+
114+
public function deleteByFilename(string $filename): bool
115+
{
116+
if ($filename === '') {
117+
return false;
118+
}
119+
120+
$table = Database::getTablePrefix() . 'faqbackup';
121+
$filenameEscaped = $this->configuration->getDb()->escape($filename);
122+
$query = sprintf("DELETE FROM %s WHERE filename = '%s'", $table, $filenameEscaped);
123+
124+
return (bool) $this->configuration->getDb()->query($query);
125+
}
126+
127+
public function deleteAll(): bool
128+
{
129+
$table = Database::getTablePrefix() . 'faqbackup';
130+
$query = sprintf('DELETE FROM %s', $table);
131+
132+
return (bool) $this->configuration->getDb()->query($query);
133+
}
134+
}

0 commit comments

Comments
 (0)