| Server IP : 188.114.96.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /polana/admin/ |
Upload File : |
<?php
declare(strict_types=1);
require_once dirname(__DIR__) . '/includes/functions.php';
require_admin_role();
const V174_BACKUP_HEADER = "<?php http_response_code(404); exit; __halt_compiler(); ?>\n";
function v174_core_path(): string { return dirname(__DIR__) . '/includes/functions.php'; }
function v174_backup_dir(): string { return dirname(__DIR__) . '/storage/.polana_v174_backups'; }
function v174_manifest_path(): string { return v174_backup_dir() . '/manifest.php'; }
function v174_read_protected(string $file): ?string {
$data = @file_get_contents($file);
if (!is_string($data) || !str_starts_with($data, V174_BACKUP_HEADER)) return null;
return substr($data, strlen(V174_BACKUP_HEADER));
}
function v174_write_protected(string $file, string $payload): void {
if (@file_put_contents($file, V174_BACKUP_HEADER . $payload, LOCK_EX) === false) {
throw new RuntimeException('Nie można zapisać bezpiecznej kopii: ' . basename($file));
}
@chmod($file, 0600);
}
function v174_replace_atomically(string $path, string $new): void {
$temp = dirname($path) . '/.v174_' . bin2hex(random_bytes(8)) . '.tmp';
if (@file_put_contents($temp, $new, LOCK_EX) === false) throw new RuntimeException('Nie można utworzyć pliku tymczasowego.');
@chmod($temp, fileperms($path) & 0777);
if (!@rename($temp, $path)) {
@unlink($temp);
throw new RuntimeException('Nie można atomowo podmienić functions.php.');
}
}
function v174_patch_core(string $src): string {
$hasHead = str_contains($src, 'POLANA_TRACKING_HEAD_V174');
$hasFoot = str_contains($src, 'POLANA_TRACKING_FOOTER_V174');
if ($hasHead || $hasFoot) {
if ($hasHead && $hasFoot) return $src;
throw new RuntimeException('Znaleziono niepełną integrację V17.4. Nie nadpisuję pliku — potrzebna diagnostyka.');
}
// Existing manually inserted analytics would double-count page views.
if (preg_match('~googletagmanager\.com/(?:gtag/js|gtm\.js)|connect\.facebook\.net/[^\s]+/fbevents\.js~i', $src)) {
throw new RuntimeException('W functions.php jest już ręcznie dodany kod Google/Meta. Usuń duplikat lub skontaktuj się przed instalacją.');
}
$headStart = strpos($src, 'function render_public_head(');
$headEnd = strpos($src, 'function render_public_header(', $headStart === false ? 0 : $headStart);
$footStart = strpos($src, 'function render_public_footer(');
$footEnd = strpos($src, 'function render_admin_header(', $footStart === false ? 0 : $footStart);
if ($headStart === false || $headEnd === false || $footStart === false || $footEnd === false || $headEnd <= $headStart || $footEnd <= $footStart) {
throw new RuntimeException('Nie znaleziono bezpiecznych granic render_public_head/render_public_footer. Plik niezmieniony.');
}
$head = substr($src, $headStart, $headEnd - $headStart);
$footer = substr($src, $footStart, $footEnd - $footStart);
if (substr_count($head, '</head>') !== 1 || substr_count($footer, '</body>') !== 1) {
throw new RuntimeException('Nieznany układ szablonu HTML. Plik niezmieniony.');
}
$headHook = " <?php /* POLANA_TRACKING_HEAD_V174 */ require_once __DIR__ . '/polana_tracking.php'; polana_tracking_head(); ?>\n";
$footerHook = " <?php /* POLANA_TRACKING_FOOTER_V174 */ if (function_exists('polana_tracking_footer')) polana_tracking_footer(); ?>\n";
$head = str_replace('</head>', $headHook . '</head>', $head);
$footer = str_replace('</body>', $footerHook . '</body>', $footer);
$patched = substr($src, 0, $footStart) . $footer . substr($src, $footEnd);
// Earlier footer replacement may change string offsets: locate head again.
$hStart = strpos($patched, 'function render_public_head(');
$hEnd = strpos($patched, 'function render_public_header(', $hStart);
$patched = substr($patched, 0, $hStart) . $head . substr($patched, $hEnd);
// Visible navigation link, but never break installation if nav is customized.
if (!str_contains($patched, 'href="/admin/polana-analityka.php"')) {
$needle = '<a href="/admin/seo.php">SEO / zaślepka</a>';
if (str_contains($patched, $needle)) {
$link = '<?php if ($role === \'admin\'): ?><a href="/admin/polana-analityka.php">Analityka i piksele</a><?php endif; ?>' . "\n ";
$patched = str_replace($needle, $link . $needle, $patched);
}
}
return $patched;
}
function v174_preflight(): array {
$src = @file_get_contents(v174_core_path());
if (!is_string($src) || $src === '') throw new RuntimeException('Nie można odczytać includes/functions.php.');
foreach (['includes/polana_tracking.php','assets/js/polana-tracking.js','assets/css/polana-tracking.css','admin/polana-analityka.php'] as $rel) {
if (!is_file(dirname(__DIR__) . '/' . $rel)) throw new RuntimeException('Brakuje pliku z paczki: ' . $rel);
}
// Check common public entrypoints as well, not only the shared template.
foreach (['index.php', 'rezerwacja.php', 'menu.php', 'kontakt.php', 'polityka-prywatnosci.php'] as $entry) {
$file = dirname(__DIR__) . '/' . $entry;
if (!is_file($file)) continue;
$entryCode = @file_get_contents($file);
if (is_string($entryCode) && preg_match('~googletagmanager\.com/(?:gtag/js|gtm\.js)|connect\.facebook\.net/[^\s]+/fbevents\.js~i', $entryCode)) {
throw new RuntimeException('W ' . $entry . ' znaleziono już ręcznie dodany Google Tag/GTM/Meta Pixel. Najpierw usuń duplikat.');
}
}
$patched = v174_patch_core($src);
return [$src, $patched];
}
function v174_install(): string {
[$src, $patched] = v174_preflight();
if ($src === $patched) return 'Integracja V17.4 jest już zainstalowana. Nie wykonano zmian.';
$backupDir = v174_backup_dir();
if (!is_dir($backupDir) && !@mkdir($backupDir, 0700, true) && !is_dir($backupDir)) throw new RuntimeException('Nie można utworzyć katalogu kopii zapasowej.');
@chmod($backupDir, 0700);
@file_put_contents($backupDir . '/.htaccess', "Require all denied\nDeny from all\n", LOCK_EX);
@file_put_contents($backupDir . '/index.php', "<?php http_response_code(404); exit;\n", LOCK_EX);
if (is_file(v174_manifest_path())) throw new RuntimeException('Istnieje poprzedni manifest instalacji. Najpierw sprawdź rollback, nie nadpisuję kopii.');
$backupName = 'functions_' . gmdate('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.php';
v174_write_protected($backupDir . '/' . $backupName, $src);
$manifest = [
'version'=>'17.4', 'backup'=>$backupName, 'original_sha256'=>hash('sha256',$src),
'patched_sha256'=>hash('sha256',$patched), 'created_at'=>gmdate('c')
];
$changed = false;
$manifestWritten = false;
$pdo = db();
try {
v174_replace_atomically(v174_core_path(), $patched);
$changed = true;
$pdo->beginTransaction();
$stmt = $pdo->prepare('INSERT IGNORE INTO settings (setting_key, setting_value) VALUES (?, ?)');
$stmt->execute(['polana_tracking_mode', 'direct']);
$stmt->execute(['polana_ga4_id', 'G-H5C811DZHV']);
$stmt->execute(['polana_gtm_id', '']);
$stmt->execute(['polana_meta_pixel_id', '']);
v174_write_protected(v174_manifest_path(), json_encode($manifest, JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR));
$manifestWritten = true;
$pdo->commit();
} catch (Throwable $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
if ($changed) {
try { v174_replace_atomically(v174_core_path(), $src); }
catch (Throwable $restore) { throw new RuntimeException('UWAGA: zapis nieudany i automatyczny rollback pliku nie powiódł się: ' . $restore->getMessage()); }
}
if ($manifestWritten) @unlink(v174_manifest_path());
throw $e;
}
admin_log('polana_v174_install', 'Włączono analitykę z bannerem zgód; backup ' . $backupName);
return 'V17.4 zainstalowana. GA4 jest ustawione na G-H5C811DZHV i uruchomi się dopiero po zgodzie na analitykę.';
}
function v174_rollback(): string {
$raw = v174_read_protected(v174_manifest_path());
if ($raw === null) throw new RuntimeException('Brak poprawnego manifestu. Nie można wykonać rollbacku automatycznie.');
$manifest = json_decode($raw, true, 512, JSON_THROW_ON_ERROR);
$backupName = (string)($manifest['backup'] ?? '');
if (!preg_match('/^functions_[0-9]{8}_[0-9]{6}_[a-f0-9]{8}\.php$/', $backupName)) throw new RuntimeException('Nieprawidłowa nazwa kopii.');
$original = v174_read_protected(v174_backup_dir() . '/' . $backupName);
if ($original === null || !hash_equals((string)$manifest['original_sha256'], hash('sha256', $original))) throw new RuntimeException('Kopia jest uszkodzona — rollback przerwany.');
$current = @file_get_contents(v174_core_path());
if (!is_string($current) || !hash_equals((string)$manifest['patched_sha256'], hash('sha256', $current))) {
throw new RuntimeException('functions.php zmienił się po instalacji. Nie nadpisuję nowszych zmian.');
}
v174_replace_atomically(v174_core_path(), $original);
@rename(v174_manifest_path(), v174_backup_dir() . '/manifest_rolledback_' . gmdate('Ymd_His') . '.php');
admin_log('polana_v174_rollback', 'Przywrócono functions.php sprzed V17.4.');
return 'Rollback zakończony. Przywrócono poprzedni functions.php. Ustawienia w bazie pozostają zachowane.';
}
$message = '';
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
try {
$action = (string)($_POST['action'] ?? '');
if ($action === 'install') $message = v174_install();
elseif ($action === 'rollback') {
if (($_POST['confirm_rollback'] ?? '') !== 'yes') throw new RuntimeException('Potwierdź rollback.');
$message = v174_rollback();
} else throw new RuntimeException('Nieznana akcja.');
} catch (Throwable $e) {
$error = $e->getMessage();
}
}
$preflight = '';
$installed = false;
$ready = false;
try {
[$original, $patched] = v174_preflight();
$installed = $original === $patched;
$ready = true;
$preflight = $installed ? 'Zainstalowano' : 'Gotowe do instalacji';
} catch (Throwable $e) {
$preflight = $e->getMessage();
}
render_admin_header('Instalator analityki V17.4');
?>
<div class="admin-title-row"><div><h1>POLANA V17.4 — instalator analityki</h1><p>Google Analytics 4, GTM, Meta Pixel i zgody cookie. Niezależne od modułów rezerwacji i poczty.</p></div></div>
<div class="form-card" style="max-width:960px;padding:24px">
<?php if ($message): ?><div class="flash flash-success"><?= e($message) ?></div><?php endif; ?>
<?php if ($error): ?><div class="flash flash-error"><?= e($error) ?></div><?php endif; ?>
<p><strong>Stan:</strong> <?= e($preflight) ?></p>
<p>Instalator robi backup <code>includes/functions.php</code>, dopina dwa małe hooki do szablonu i dodaje skrót do panelu. Nie zmienia rezerwacji, newslettera, SMTP, SEO ani przekierowań domeny.</p>
<form method="post" style="margin:22px 0">
<?= csrf_field() ?><input type="hidden" name="action" value="install">
<button type="submit" <?= !$ready || $installed ? 'disabled' : '' ?>>Zainstaluj V17.4 z backupem</button>
</form>
<p><a href="/admin/polana-analityka.php">Otwórz panel „Analityka i piksele” →</a></p>
<hr style="margin:28px 0">
<h2>Bezpieczny rollback</h2>
<p>Przywróci oryginalny <code>functions.php</code> tylko wtedy, gdy od instalacji nie był modyfikowany. Nie kasuje ustawień ani danych analitycznych.</p>
<form method="post">
<?= csrf_field() ?><input type="hidden" name="action" value="rollback">
<label style="display:block;margin-bottom:10px"><input type="checkbox" name="confirm_rollback" value="yes"> Potwierdzam cofnięcie integracji V17.4</label>
<button type="submit">Cofnij V17.4</button>
</form>
</div>
<?php render_admin_footer(); ?>