| 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);
/** POLANA V18.17 — generator bezpiecznej poprawki kolorow zdarzen Google Calendar.
* Nie zapisuje kodu ani bazy samoczynnie. Tylko administrator.
*/
require_once dirname(__DIR__) . '/includes/functions.php';
require_admin_role();
header('Cache-Control: private, no-store, max-age=0');
header('X-Robots-Tag: noindex, nofollow');
header('Referrer-Policy: no-referrer');
function v1817_e($s): string { return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); }
function v1817_color_code(): string {
return <<<'GCAL_COLORS'
/** POLANA_GCAL_COLOR_V1817: indywidualne, stabilne kolory wydarzen. */
function pg173_event_color_id(array $reservation): string {
// Google Calendar event.colorId: 1..11. Kolejnosc mieszana, nie losowana ponownie.
$palette = ['9','2','10','5','11','7','6','4','3','1','8'];
$id = (int)($reservation['id'] ?? 0);
$date = (string)($reservation['reservation_date'] ?? '');
$time = (string)($reservation['reservation_time'] ?? '00:00:00');
$start = static function(string $value): int {
$parts = explode(':', $value);
return ((int)($parts[0] ?? 0) * 3600) + ((int)($parts[1] ?? 0) * 60) + (int)($parts[2] ?? 0);
};
$initial = static function(int $reservationId) use ($date, $palette): int {
return hexdec(substr(hash('sha256', 'polana-gcal-color-1:'.$date.':'.$reservationId), 0, 7)) % count($palette);
};
$fallback = $palette[$initial($id)];
if ($id <= 0 || !preg_match('/^\d{4}-\d{2}-\d{2}$/D', $date)) return $fallback;
try {
// Algorytm przydziela kolory wg rosnacego ID, by nowa rezerwacja nie
// wymuszala zmiany kolorow wczesniej utworzonych rezerwacji.
$q = db()->prepare("SELECT id, reservation_time FROM reservations WHERE reservation_date=? AND status='confirmed' AND id<=? ORDER BY id ASC LIMIT 1000");
$q->execute([$date, $id]);
$rows = $q->fetchAll(PDO::FETCH_ASSOC);
if (!is_array($rows)) return $fallback;
$duration = pg173_duration() * 60;
$assigned = [];
$found = false;
foreach ($rows as $row) {
$otherId = (int)($row['id'] ?? 0);
$otherStart = $start((string)($row['reservation_time'] ?? '00:00:00'));
$otherEnd = $otherStart + $duration;
$used = [];
foreach ($assigned as $previous) {
if ($previous['start'] < $otherEnd && $previous['end'] > $otherStart) {
$used[$previous['color']] = true;
}
}
$base = $initial($otherId);
$chosen = $palette[$base];
for ($step = 0; $step < count($palette); $step++) {
$candidate = $palette[($base + $step) % count($palette)];
if (!isset($used[$candidate])) { $chosen = $candidate; break; }
}
$assigned[] = ['start'=>$otherStart, 'end'=>$otherEnd, 'color'=>$chosen];
if ($otherId === $id) { $fallback = $chosen; $found = true; break; }
}
// Bez wymuszonej modyfikacji innych wydarzen i bez zmian schematu SQL.
return $found ? $fallback : $palette[$initial($id)];
} catch (Throwable $ignored) {
// Problem zapytania o kolory nie moze zatrzymac synchronizacji kalendarza.
return $fallback;
}
}
GCAL_COLORS;
}
function v1817_patch(string $original): array {
if (str_contains($original, 'POLANA_GCAL_COLOR_V1817')) return ['state'=>'installed', 'content'=>null, 'message'=>'Kolory V18.17 sa juz dodane do biblioteki.'];
$start = strpos($original, 'function pg173_event_payload(');
if ($start === false) return ['state'=>'unsupported','content'=>null,'message'=>'Brak rozpoznanej funkcji pg173_event_payload().'];
$end = strpos($original, 'function pg173_row(', $start);
if ($end === false) return ['state'=>'unsupported','content'=>null,'message'=>'Nieznany koniec funkcji payload — brak pg173_row().'];
$segment = substr($original, $start, $end - $start);
if (preg_match('/[\'\"]colorId[\'\"]\s*=>/', $segment)) return ['state'=>'unsupported','content'=>null,'message'=>'Wykryto inny mechanizm kolorow, poprawka nie nadpisze go.'];
$eol = str_contains($original, "\r\n") ? "\r\n" : "\n";
$re = '/^([ \t]*)[\'\"]id[\'\"]\s*=>\s*pg173_event_id\(\(int\)\s*\$r\[[\'\"]id[\'\"]\]\)\s*,[^\S\r\n]*(?:\r?\n)/m';
$count = 0;
$patchedSegment = preg_replace_callback($re, static function(array $m) use ($eol): string {
return $m[0].$m[1]."'colorId'=>pg173_event_color_id(\$r),".$eol;
}, $segment, 1, $count);
if ($count !== 1 || !is_string($patchedSegment)) return ['state'=>'unsupported','content'=>null,'message'=>'Zmodyfikowano strukture pola ID w wydarzeniu — nie nadpisuje biblioteki.'];
$helper = str_replace("\n", $eol, v1817_color_code());
$patched = substr($original, 0, $start) . $helper . $patchedSegment . substr($original, $end);
return ['state'=>'ready','content'=>$patched,'message'=>'Rozpoznano kod, mozna pobrac poprawiony plik.'];
}
$target = dirname(__DIR__) . '/includes/polana_gcal.php';
$original = is_file($target) && is_readable($target) ? file_get_contents($target) : false;
$result = is_string($original) ? v1817_patch($original) : ['state'=>'missing','content'=>null,'message'=>'Brak dostepu do includes/polana_gcal.php.'];
if (($_GET['download'] ?? '') === 'original' && is_string($original)) {
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="polana_gcal_ORIGINAL.php"');
header('Content-Length: '.strlen($original));
echo $original; exit;
}
if (($_GET['download'] ?? '') === 'patched' && $result['state'] === 'ready') {
$content = $result['content'];
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="polana_gcal.php"');
header('Content-Length: '.strlen($content));
echo $content; exit;
}
$outcomes = [];
$after = 0;
$hasNext = false;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
verify_csrf();
if (($_POST['action'] ?? '') === 'resync' && $result['state'] === 'installed') {
require_once $target;
if (!function_exists('pg173_connected') || !pg173_connected()) {
$outcomes[] = 'Google Calendar nie jest aktualnie polaczony. Nie wyslano zmian.';
} else {
$after = max(0, (int)($_POST['after_id'] ?? 0));
try {
$q = db()->prepare("SELECT r.id FROM reservations r INNER JOIN polana_calendar_events c ON c.reservation_id=r.id WHERE r.status='confirmed' AND r.reservation_date >= CURDATE() AND r.id>? ORDER BY r.id ASC LIMIT 11");
$q->execute([$after]);
$ids = array_map('intval', $q->fetchAll(PDO::FETCH_COLUMN));
$hasNext = count($ids) > 10;
$ids = array_slice($ids, 0, 10);
foreach ($ids as $id) {
$after = $id;
$sync = pg173_sync($id);
$outcomes[] = 'Rezerwacja #'.$id.': '.(string)($sync['result'] ?? 'nieznany');
}
if (!$ids) $outcomes[] = 'Brak kolejnych potwierdzonych rezerwacji do synchronizacji.';
} catch (Throwable $e) {
$outcomes[] = 'Synchronizacja zostala zatrzymana: '.mb_substr($e->getMessage(), 0, 180, 'UTF-8');
}
}
}
}
render_admin_header('Kolory Google Calendar V18.17');
echo '<main style="max-width:980px;margin:24px auto;padding:0 20px"><h1>POLANA V18.17 — kolorowe rezerwacje Google</h1>';
echo '<p>Ta strona nie zmienia konfiguracji OAuth. Nowa rezerwacja dostaje kolor z 11 kolorow Google. Kolory zarezerwowane przez nakladajace sie wydarzenia sa omijane, gdy mozliwe.</p>';
echo '<section class="card" style="padding:22px;margin:14px 0"><h2>Status biblioteki</h2><p><strong>'.v1817_e($result['state']).'</strong> — '.v1817_e($result['message']).'</p>';
if (is_string($original)) {
echo '<p>SHA-256 oryginalu: <code>'.v1817_e(hash('sha256',$original)).'</code></p>';
echo '<p><a href="?download=original">1. Pobierz ORYGINALNY plik PHP do rollbacku</a></p>';
}
if ($result['state'] === 'ready') {
echo '<p><a href="?download=patched">2. Pobierz POPRAWIONY polana_gcal.php</a></p>';
echo '<p><strong>3.</strong> Przez FileZilla wgraj poprawiony plik do <code>includes/polana_gcal.php</code>. Oryginal przechowuj lokalnie poza katalogiem WWW. Potem odswiez te strone.</p>';
}
echo '</section>';
if ($result['state'] === 'installed') {
echo '<section class="card" style="padding:22px;margin:14px 0"><h2>Odśwież kolory już istniejących wydarzeń</h2>';
echo '<p>Przycisk wywołuje istniejącą synchronizację, bez zmiany statusów rezerwacji. Jedna partia: do 10 potwierdzonych, przyszłych rezerwacji. Nie twórz nowego kalendarza.</p>';
if ($outcomes) {echo '<ul>';foreach ($outcomes as $o) echo '<li>'.v1817_e($o).'</li>';echo '</ul>';}
echo '<form method="post">'.csrf_field().'<input type="hidden" name="action" value="resync"><input type="hidden" name="after_id" value="'.(int)$after.'"><button type="submit">'.($hasNext?'Synchronizuj następną partię':'Zaktualizuj kolory wydarzeń').'</button></form>';
echo '</section>';
}
echo '<p><a href="/admin/polana-kalendarz.php">Wróć do Google Calendar</a></p></main>';
render_admin_footer();