| Server IP : 193.86.120.172 / Your IP : 216.73.216.215 Web Server : Apache/2.4.63 (Unix) System : Linux JServices 3.10.108 #86003 SMP Wed Oct 22 13:20:46 CST 2025 x86_64 User : kubec ( 1026) PHP Version : 8.2.28 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /volume1/web/jservices_cz/ |
Upload File : |
<?php
/**
* J Services – zálohovací skript
*
* Použití:
* Manuálně přes SSH:
* /var/packages/PHP8.2/target/usr/local/bin/php82 /volume1/web/jservices_cz/backup.php
*
* Z administrace: volá se přes require z admin.php
*/
// Konfigurace
define('WEB_SLOZKA', '/volume1/web/jservices_cz');
define('BACKUP_SLOZKA', '/volume1/web/_ADMIN/auto_backup/J Services');
define('MAX_ZALOH', 30);
// DB konstanty jsou již definované v config.php pokud voláno z admin.php
// Při přímém CLI volání je definujeme zde
if (!defined('DB_HOST')) define('DB_HOST', 'localhost');
if (!defined('DB_NAME')) define('DB_NAME', 'jservices_cz');
if (!defined('DB_USER')) define('DB_USER', 'jservices_cz');
if (!defined('DB_PASS')) define('DB_PASS', ')WeKK.O3g8dV0kCk');
// Zjistíme jestli běžíme z CLI nebo HTTP
$jeCli = (php_sapi_name() === 'cli');
function log_msg(string $zprava, bool $jeCli): void
{
if ($jeCli) {
echo $zprava . "\n";
}
}
function zaloha_selhala(string $duvod, bool $jeCli): void
{
log_msg('CHYBA: ' . $duvod, $jeCli);
exit(1);
}
log_msg('=== J Services záloha ===', $jeCli);
log_msg('Čas: ' . date('Y-m-d H:i:s'), $jeCli);
// 1. Vytvoříme zálohovací složku pokud neexistuje
if (!is_dir(BACKUP_SLOZKA)) {
if (!mkdir(BACKUP_SLOZKA, 0750, true)) {
zaloha_selhala('Nelze vytvořit zálohovací složku: ' . BACKUP_SLOZKA, $jeCli);
}
}
$casovaZnacka = date('Ymd_His');
$tmpSlozka = BACKUP_SLOZKA . '/tmp_' . $casovaZnacka;
$zipSoubor = BACKUP_SLOZKA . '/jservices-' . $casovaZnacka . '.zip';
if (!is_writable(BACKUP_SLOZKA)) {
zaloha_selhala('Zálohovací složka není zapisovatelná: ' . BACKUP_SLOZKA . ' (vlastník: ' . posix_getpwuid(fileowner(BACKUP_SLOZKA))['name'] . ', PHP běží jako: ' . get_current_user() . ')', $jeCli);
}
if (!mkdir($tmpSlozka, 0750, true)) {
zaloha_selhala('Nelze vytvořit dočasnou složku: ' . $tmpSlozka, $jeCli);
}
// 2. Dump databáze
log_msg('Zálohování databáze...', $jeCli);
$sqlSoubor = $tmpSlozka . '/databaze_' . $casovaZnacka . '.sql';
$mysqldump = '/bin/mysqldump';
// Hledáme mysqldump na různých místech
foreach (['/bin/mysqldump', '/usr/bin/mysqldump', '/usr/local/bin/mysqldump'] as $cesta) {
if (file_exists($cesta)) { $mysqldump = $cesta; break; }
}
$prikaz = sprintf(
'%s --host=%s --user=%s --password=%s --single-transaction --routines --triggers %s > %s 2>&1',
escapeshellarg($mysqldump),
escapeshellarg(DB_HOST),
escapeshellarg(DB_USER),
escapeshellarg(DB_PASS),
escapeshellarg(DB_NAME),
escapeshellarg($sqlSoubor)
);
exec($prikaz, $vystup, $navratKod);
if ($navratKod !== 0 || !file_exists($sqlSoubor) || filesize($sqlSoubor) < 100) {
// Fallback: dump přes PDO
log_msg('mysqldump selhal, zkouším PDO fallback...', $jeCli);
try {
$pdo = new PDO(
'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME . ';charset=utf8mb4',
DB_USER,
DB_PASS,
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
);
$sql = "-- J Services databáze dump\n";
$sql .= "-- Datum: " . date('Y-m-d H:i:s') . "\n\n";
$sql .= "SET NAMES utf8mb4;\nSET FOREIGN_KEY_CHECKS=0;\n\n";
// Získáme seznam tabulek
$tabulky = $pdo->query("SHOW TABLES")->fetchAll(PDO::FETCH_COLUMN);
foreach ($tabulky as $tabulka) {
// CREATE TABLE
$create = $pdo->query("SHOW CREATE TABLE `{$tabulka}`")->fetch(PDO::FETCH_NUM);
$sql .= "\n-- Tabulka: {$tabulka}\n";
$sql .= "DROP TABLE IF EXISTS `{$tabulka}`;\n";
$sql .= $create[1] . ";\n\n";
// Data
$radky = $pdo->query("SELECT * FROM `{$tabulka}`")->fetchAll(PDO::FETCH_ASSOC);
if (count($radky) > 0) {
$sql .= "INSERT INTO `{$tabulka}` VALUES\n";
$hodnoty = [];
foreach ($radky as $radek) {
$escapovane = array_map(function($v) use ($pdo) {
return $v === null ? 'NULL' : $pdo->quote((string) $v);
}, array_values($radek));
$hodnoty[] = '(' . implode(', ', $escapovane) . ')';
}
$sql .= implode(",\n", $hodnoty) . ";\n\n";
}
}
$sql .= "SET FOREIGN_KEY_CHECKS=1;\n";
file_put_contents($sqlSoubor, $sql);
log_msg('PDO dump dokončen.', $jeCli);
} catch (Exception $e) {
zaloha_selhala('Dump databáze selhal: ' . $e->getMessage(), $jeCli);
}
}
log_msg('Databáze: OK (' . round(filesize($sqlSoubor) / 1024, 1) . ' KB)', $jeCli);
// 3. Vytvoříme ZIP archiv
log_msg('Vytváření ZIP archivu...', $jeCli);
if (!class_exists('ZipArchive')) {
zaloha_selhala('PHP ZipArchive není dostupné', $jeCli);
}
$zip = new ZipArchive();
if ($zip->open($zipSoubor, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
zaloha_selhala('Nelze vytvořit ZIP soubor', $jeCli);
}
// Přidáme SQL dump
$zip->addFile($sqlSoubor, 'databaze/databaze_' . $casovaZnacka . '.sql');
// Přidáme soubory webu (vynecháme zálohovací složku a dočasné soubory)
$vynechat = [
realpath(BACKUP_SLOZKA),
WEB_SLOZKA . '/assets/moje', // osobní soubory z portálu (mohou být velké)
];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(WEB_SLOZKA, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
$pocetSouboru = 0;
foreach ($iterator as $soubor) {
$realCesta = realpath($soubor->getPathname());
// Přeskočíme vyloučené složky
$preskocit = false;
foreach ($vynechat as $v) {
if ($v && str_starts_with($realCesta, $v)) {
$preskocit = true;
break;
}
}
if ($preskocit) continue;
$relativniCesta = 'web/' . substr($soubor->getPathname(), strlen(WEB_SLOZKA) + 1);
if ($soubor->isDir()) {
$zip->addEmptyDir($relativniCesta);
} elseif ($soubor->isFile()) {
$zip->addFile($soubor->getPathname(), $relativniCesta);
$pocetSouboru++;
}
}
$zip->close();
// 4. Úklid dočasné složky
unlink($sqlSoubor);
rmdir($tmpSlozka);
$zipVelikost = round(filesize($zipSoubor) / 1024 / 1024, 2);
log_msg("ZIP vytvořen: backup_{$casovaZnacka}.zip ({$zipVelikost} MB, {$pocetSouboru} souborů)", $jeCli);
// 5. Rotace – ponecháme jen posledních MAX_ZALOH záloh
log_msg('Rotace záloh...', $jeCli);
$vsechnyZalohy = glob(BACKUP_SLOZKA . '/jservices-*.zip');
if ($vsechnyZalohy !== false) {
rsort($vsechnyZalohy); // nejnovější první
if (count($vsechnyZalohy) > MAX_ZALOH) {
$keSmazu = array_slice($vsechnyZalohy, MAX_ZALOH);
foreach ($keSmazu as $stara) {
unlink($stara);
log_msg('Smazána stará záloha: ' . basename($stara), $jeCli);
}
}
}
$celkemZaloh = count(glob(BACKUP_SLOZKA . '/backup_*.zip') ?: []);
log_msg("Celkem záloh: {$celkemZaloh}/" . MAX_ZALOH, $jeCli);
log_msg('=== Záloha dokončena ===', $jeCli);
// Vrátíme cestu k ZIP souboru (pro HTTP volání z administrace)
return $zipSoubor;