| 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/includes/ |
Upload File : |
<?php
declare(strict_types=1);
function ensure_blog_schema(): void
{
db()->exec(
"CREATE TABLE IF NOT EXISTS blog_posts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(255) NOT NULL,
slug VARCHAR(220) NOT NULL,
category VARCHAR(120) DEFAULT NULL,
excerpt TEXT DEFAULT NULL,
content MEDIUMTEXT NOT NULL,
featured_image VARCHAR(500) DEFAULT NULL,
status VARCHAR(20) NOT NULL DEFAULT 'draft',
publish_at DATETIME DEFAULT NULL,
seo_title VARCHAR(255) DEFAULT NULL,
seo_description VARCHAR(320) DEFAULT NULL,
created_by_user_id INT UNSIGNED DEFAULT NULL,
updated_by_user_id INT UNSIGNED DEFAULT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
UNIQUE KEY uq_blog_slug (slug),
INDEX idx_blog_public (status,publish_at),
INDEX idx_blog_publish (publish_at,id),
CONSTRAINT fk_blog_created_by FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL,
CONSTRAINT fk_blog_updated_by FOREIGN KEY (updated_by_user_id) REFERENCES users(id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_polish_ci"
);
}
function blog_promote_due_posts(): int
{
ensure_blog_schema();
$now = date('Y-m-d H:i:s');
$stmt = db()->prepare(
"UPDATE blog_posts
SET status='published', updated_at=NOW()
WHERE status='scheduled'
AND publish_at IS NOT NULL
AND publish_at<=?"
);
$stmt->execute([$now]);
return $stmt->rowCount();
}
function blog_slugify(string $value): string
{
$value = trim($value);
if ($value === '') return 'wpis';
$ascii = iconv('UTF-8','ASCII//TRANSLIT//IGNORE',$value);
if ($ascii !== false) $value = $ascii;
$value = strtolower($value);
$value = preg_replace('/[^a-z0-9]+/','-',$value) ?? 'wpis';
$value = trim($value,'-');
return $value !== '' ? mb_substr($value,0,210,'UTF-8') : 'wpis';
}
function blog_unique_slug(string $slug, int $excludeId = 0): string
{
ensure_blog_schema();
$base = blog_slugify($slug);
$candidate = $base;
$i = 2;
while (true) {
$stmt = db()->prepare('SELECT id FROM blog_posts WHERE slug=? AND id<>? LIMIT 1');
$stmt->execute([$candidate,$excludeId]);
if (!$stmt->fetch()) return $candidate;
$candidate = mb_substr($base,0,195,'UTF-8') . '-' . $i;
$i++;
}
}
function blog_excerpt_from_content(string $content, int $max = 180): string
{
$plain = trim(preg_replace('/\s+/u',' ',$content) ?? $content);
if (mb_strlen($plain,'UTF-8') <= $max) return $plain;
return rtrim(mb_substr($plain,0,$max-1,'UTF-8')) . '…';
}
function blog_public_posts(int $limit = 100): array
{
ensure_blog_schema();
blog_promote_due_posts();
$limit = max(1,min(500,$limit));
return db()->query(
"SELECT * FROM blog_posts
WHERE status='published'
AND publish_at IS NOT NULL
AND publish_at<=NOW()
ORDER BY publish_at DESC,id DESC
LIMIT $limit"
)->fetchAll();
}
function blog_public_post_by_slug(string $slug, bool $allowPreview = false): ?array
{
ensure_blog_schema();
blog_promote_due_posts();
if ($allowPreview) {
$stmt = db()->prepare('SELECT * FROM blog_posts WHERE slug=? LIMIT 1');
$stmt->execute([$slug]);
return $stmt->fetch() ?: null;
}
$stmt = db()->prepare(
"SELECT * FROM blog_posts
WHERE slug=?
AND status='published'
AND publish_at IS NOT NULL
AND publish_at<=NOW()
LIMIT 1"
);
$stmt->execute([$slug]);
return $stmt->fetch() ?: null;
}
function blog_post_by_id(int $id): ?array
{
ensure_blog_schema();
$stmt = db()->prepare('SELECT * FROM blog_posts WHERE id=? LIMIT 1');
$stmt->execute([$id]);
return $stmt->fetch() ?: null;
}
function blog_status_label(array $post): string
{
$status = (string)($post['status'] ?? 'draft');
if ($status === 'scheduled') return 'Zaplanowany';
if ($status === 'published') return 'Opublikowany';
return 'Szkic';
}
function blog_can_manage(): bool
{
$u = admin_user();
return $u && in_array((string)$u['role'],['admin','editor'],true);
}
function require_blog_manager(): array
{
require_login();
$u = admin_user();
if (!$u || !in_array((string)$u['role'],['admin','editor'],true)) {
http_response_code(403);
exit('Brak dostępu do bloga.');
}
return $u;
}
function blog_upload_featured_image(array $file): string
{
$error = (int)($file['error'] ?? UPLOAD_ERR_NO_FILE);
if ($error === UPLOAD_ERR_NO_FILE) return '';
if ($error !== UPLOAD_ERR_OK) throw new RuntimeException('Błąd wysyłania zdjęcia.');
$tmp = (string)($file['tmp_name'] ?? '');
$size = (int)($file['size'] ?? 0);
if (!is_uploaded_file($tmp)) throw new RuntimeException('Nieprawidłowy upload zdjęcia.');
if ($size > 12*1024*1024) throw new RuntimeException('Zdjęcie jest za duże. Maks. 12 MB.');
$mime = (new finfo(FILEINFO_MIME_TYPE))->file($tmp);
$map = [
'image/jpeg'=>'jpg',
'image/png'=>'png',
'image/webp'=>'webp',
'image/avif'=>'avif',
];
if (!isset($map[$mime])) throw new RuntimeException('Dozwolone zdjęcia: JPG, PNG, WEBP, AVIF.');
$dir = dirname(__DIR__) . '/assets/img/blog';
if (!is_dir($dir) && !mkdir($dir,0755,true) && !is_dir($dir)) {
throw new RuntimeException('Nie udało się utworzyć katalogu bloga.');
}
$name = date('Ymd-His') . '-' . bin2hex(random_bytes(5)) . '.' . $map[$mime];
if (!move_uploaded_file($tmp,$dir.'/'.$name)) throw new RuntimeException('Nie udało się zapisać zdjęcia.');
@chmod($dir.'/'.$name,0644);
return '/assets/img/blog/' . $name;
}
function blog_render_content(string $content): string
{
$lines = preg_split('/\R/u',trim($content)) ?: [];
$html = [];
$paragraph = [];
$list = [];
$flushParagraph = function() use (&$paragraph,&$html): void {
if (!$paragraph) return;
$html[] = '<p>' . nl2br(e(implode("\n",$paragraph))) . '</p>';
$paragraph = [];
};
$flushList = function() use (&$list,&$html): void {
if (!$list) return;
$items = array_map(fn($x)=>'<li>'.e($x).'</li>',$list);
$html[] = '<ul>' . implode('',$items) . '</ul>';
$list = [];
};
foreach ($lines as $line) {
$trim = trim($line);
if ($trim === '') {
$flushParagraph();
$flushList();
continue;
}
if (str_starts_with($trim,'## ')) {
$flushParagraph(); $flushList();
$html[] = '<h2>' . e(trim(substr($trim,3))) . '</h2>';
continue;
}
if (str_starts_with($trim,'### ')) {
$flushParagraph(); $flushList();
$html[] = '<h3>' . e(trim(substr($trim,4))) . '</h3>';
continue;
}
if (str_starts_with($trim,'- ')) {
$flushParagraph();
$list[] = trim(substr($trim,2));
continue;
}
$flushList();
$paragraph[] = $trim;
}
$flushParagraph();
$flushList();
return implode("\n",$html);
}
function blog_public_enabled(): bool
{
return setting('nav_blog_enabled','0') === '1';
}