File "volt-core.php"
Full path: /var/www/vhosts/derekdigital.com/gawrjuhs.art/includes/volt-core.php
File
size: 69.84 B (69.84 KB bytes)
MIME-type: text/x-php
Charset: utf-8
Download Open Edit Advanced Editor &nnbsp; Back
<?php
namespace Volt;
//////////////////////////////////////////////////
// Bric Version 1.9.4
const VERSION = '1.9.7';
//////////////////////////////////////////////////
//////////////////////////////////////////////////
// template parameters
//////////////////////////////////////////////////
$localhost_preview = '0';
$baseURL = 'https://www.gawrjuhs.art/';
$users = [];
$users[] = [
'username' => sanitizeString('admin'),
'password_hash' => trim('$2y$10$YwgwUqnurPEHCssc5ba5xeFuEz12QkbZjm3iLoYKLtaD2sMuvv9zO '),
'groups' => array_map('Volt\\sanitizeString', explode(',', 'administrator,editor')),
];
$users[] = [
'username' => sanitizeString(''),
'password_hash' => trim(''),
'groups' => array_map('Volt\\sanitizeString', explode(',', '')),
];
$users[] = [
'username' => sanitizeString(''),
'password_hash' => trim(''),
'groups' => array_map('Volt\\sanitizeString', explode(',', '')),
];
$users[] = [
'username' => sanitizeString(''),
'password_hash' => trim(''),
'groups' => array_map('Volt\\sanitizeString', explode(',', '')),
];
$users[] = [
'username' => sanitizeString(''),
'password_hash' => trim(''),
'groups' => array_map('Volt\\sanitizeString', explode(',', '')),
];
$required_editor_groups = trim('');
$scale_image = '0';
$image_width = '2000';
$image_height = '2000';
$perform_backup = '1';
$is_preview = 'false';
//////////////////////////////////////////////////
// constants and variables
//////////////////////////////////////////////////
const BASE_FOLDER_CONTENT = '_cms';
const BASE_FOLDER_BACKUP = 'backup';
const BASE_FOLDER_TEXT = 'text';
const BASE_FOLDER_BLOG = 'blog';
const BASE_FOLDER_MEDIA = 'media';
const BASE_PATH = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . BASE_FOLDER_CONTENT . DIRECTORY_SEPARATOR;
const BASE_PATH_TEXT = BASE_PATH . BASE_FOLDER_TEXT . DIRECTORY_SEPARATOR;
const BASE_PATH_BLOG = BASE_PATH . BASE_FOLDER_BLOG . DIRECTORY_SEPARATOR;
const BASE_PATH_MEDIA = BASE_PATH . BASE_FOLDER_MEDIA . DIRECTORY_SEPARATOR;
const BASE_PATH_BACKUP = BASE_PATH . BASE_FOLDER_BACKUP . DIRECTORY_SEPARATOR;
const FILE_EXT_TXT = 'txt';
const MAX_LOGIN_ATTEMPTS = 10;
const SESSION_LOGIN = 'login';
const SESSION_LOGIN_ATTEMPTS = 'login_attempts';
const SESSION_LOGIN_CSRF_TOKEN = 'X-CSRF-Token';
const SESSION_LOGIN_USERNAME = 'login_username';
const SESSION_LOGIN_GROUPS = 'login_groups';
const SESSION_LOGIN_AUTHORIZATION_EDITOR = 'authorization_editor';
const HTTP_X_CSRF_TOKEN = 'HTTP_X_CSRF_TOKEN';
const HTTP_ORIGIN = 'HTTP_ORIGIN';
const HTACCESS = 'Deny from all';
const VOLT_CONTENT = 'volt-content-';
const VOLT_BLOG_ITEM = 'volt-blog-item-';
const IMAGE_REGEX = '%<img.*?src=[\"\'](.*?)[\"\'].*?>%i';
const LOGIN_REGEX = '%<a class="volt-protect-login-page" href="(.*?)"></a>%i';
const FORBIDDEN_REGEX = '%<a class="volt-protect-forbidden-page" href="(.*?)"></a>%i';
DEFINE('ENABLED_ZIP', extension_loaded('zip'));
DEFINE('ENABLED_GD', extension_loaded('gd'));
if ($perform_backup === '1' && ENABLED_ZIP) {
DEFINE('ENABLED_BACKUP', true);
} else {
DEFINE('ENABLED_BACKUP', false);
}
DEFINE('NOW', (new \DateTime())->format('Y-m-d\TH:i'));
DEFINE('NOW_MILLIS', getDateMillis(NOW));
$page = 1;
$post = "";
$author = "";
$category = "";
$date = "";
$tag;
$filter;
$search = "";
$search_array = [];
$query = "";
$display_detail = false;
$display_filter = false;
$last_page = 1;
$author_archive = array();
$category_archive = array();
$date_year_archive = array();
$date_month_archive = array();
$tag_archive = array();
$feed = "";
$page_path = dirname($_SERVER['PHP_SELF']);
if (substr($page_path, -1) !== '/') {
$page_path = $page_path . '/';
}
$fully_qualified_page_path = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $page_path;
$fully_qualified_domain = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'];
//////////////////////////////////////////////////
// start session, create folders
//////////////////////////////////////////////////
initializeContent();
if ($localhost_preview === '1' &&
$baseURL !== 'http://setTheBaseURLInProjectSettings.com/' &&
(
(array_key_exists('api', $_GET) && array_key_exists('localhost_preview', $_GET)) || array_key_exists('debug', $_GET))
) {
$localhost_preview = true;
setHeader('Access-Control-Allow-Origin', '*');
} else {
$localhost_preview = false;
}
if ($scale_image === '1' && ENABLED_GD && is_numeric($image_width) && is_numeric($image_height)) {
$scale_image = true;
$image_width = $image_width + 0;
$image_height = $image_height + 0;
} else {
$scale_image = false;
}
//////////////////////////////////////////////////
// check for HTTP method GET
//////////////////////////////////////////////////
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
if (array_key_exists('api', $_GET)) {
// is user logged in
if ($_GET['api'] == 'login') {
startSession();
if (array_key_exists(HTTP_X_CSRF_TOKEN, $_SERVER) && $_SERVER[HTTP_X_CSRF_TOKEN] === 'fetch') {
setHeader(SESSION_LOGIN_CSRF_TOKEN, $_SESSION[SESSION_LOGIN_CSRF_TOKEN]);
}
echo getJsonLoginInfo();
exit();
}
// get content by filename
if ($_GET['api'] == 'content' && array_key_exists('name', $_GET)) {
$file = BASE_PATH_TEXT . sanitizeString($_GET['name']) . '.' . FILE_EXT_TXT;
if (file_exists($file)) {
$content = file_get_contents($file);
if ($localhost_preview) {
$content = str_replace('src="/' . BASE_FOLDER_CONTENT, 'src="' . $baseURL . BASE_FOLDER_CONTENT, $content);
}
echo $content;
}
exit();
}
// get blog item
if ($_GET['api'] == 'blog' && array_key_exists('blog-id', $_GET) && array_key_exists('id', $_GET)) {
setHeader('Content-Type', 'application/json');
$blog_id = $_GET['blog-id'];
$id = $_GET['id'];
$db = new \PragmaPHP\FileDB\FileDB(BASE_PATH_BLOG . $blog_id);
$data = $db->read($id);
if (!empty($data) && count($data) === 1) {
echo json_encode($data[0]);
}
exit();
}
// get blog
if ($_GET['api'] == 'blog' && array_key_exists('blog-id', $_GET)) {
if (strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false) {
setHeader('Content-Type', 'application/json');
$blog_id = $_GET['blog-id'];
$db = new \PragmaPHP\FileDB\FileDB(BASE_PATH_BLOG . $blog_id);
$data = $db->readAll();
echo json_encode(['blog' => $data]);
exit();
} else {
$content = getBlogContent(
$_GET['blog-id'],
$_GET['blog-items'],
$_GET['blog-layout'],
$_GET['blog-date-pattern'],
$_GET['blog-hide-future-items'],
$_GET['blog-author-text'],
$_GET['blog-category-text'],
$_GET['blog-tag-text'],
$_GET['blog-separator-text'],
$_GET['blog-readmore-text'],
$_GET['blog-back-text'],
$_GET['blog-prev-post-text'],
$_GET['blog-next-post-text'],
$_GET['blog-prev-page-text'],
$_GET['blog-next-page-text'],
1, // replace_metadata
0, // htaccess_rewrite
'', // rss_publisher
'', // rss_title
'', // rss_description
'en-us', // rss_language
'', // rss_image
$_GET['blog-heading-list'],
$_GET['blog-heading-detail'],
true, // scroll_detail_top
'', // disqus_shorthand
$_GET['blog-metadata-display'],
$_GET['blog-share-display']
);
if ($localhost_preview) {
$content = str_replace('src="/' . BASE_FOLDER_CONTENT, 'src="' . $baseURL . BASE_FOLDER_CONTENT, $content);
}
echo $content;
}
}
// get content list
if ($_GET['api'] == 'content') {
setHeader('Content-Type', 'application/json');
if (isLoggedIn()) {
$files = array();
$filesTemp = glob(BASE_PATH_TEXT . '*');
foreach ($filesTemp as $file) {
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
if ($ext == FILE_EXT_TXT) {
$files[] = [
'url' => '/' . BASE_FOLDER_CONTENT . '/' . BASE_FOLDER_TEXT . '/' . basename($file),
'filesize' => filesize($file),
'name' => pathinfo($file)['filename'],
];
}
}
echo json_encode(['content' => $files]);
exit();
} else {
echo json_encode(['content' => []]);
exit();
}
}
// get image list
if ($_GET['api'] == 'image') {
setHeader('Content-Type', 'application/json');
if (isLoggedIn()) {
$files = array();
$filesTemp = array_filter(glob(BASE_PATH_MEDIA . '*'), 'is_file');
usort($filesTemp, function ($a, $b) {
return filemtime($b) <=> filemtime($a);
});
foreach ($filesTemp as $file) {
$files[] = getImageInfo($file);
}
echo json_encode(['image' => $files]);
exit();
} else {
echo json_encode(['image' => []]);
exit();
}
}
}
// debug parameters
if (array_key_exists('debug', $_GET)) {
setHeader('Content-Type', 'application/json');
$user_exist = false;
foreach ($users as $key => $user) {
if (!empty($user) && !empty($user['username']) && !empty($user['password_hash'])) {
$user_exist = true;
}
}
echo json_encode([
'php_version' => phpversion(),
'php_post_max_size' => ini_get('post_max_size'),
'php_enabled_zip' => ENABLED_ZIP,
'php_enabled_gd' => ENABLED_GD,
'php_document_root' => $_SERVER['DOCUMENT_ROOT'],
'php_script_filename' => $_SERVER['SCRIPT_FILENAME'],
'php_context_document_root' => $_SERVER['CONTEXT_DOCUMENT_ROOT'],
'version' => VERSION,
'localhost_preview' => $localhost_preview,
'baseURL' => $baseURL,
'file_permission' => substr(sprintf('%o', fileperms(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR)), -4),
'scale_image' => $scale_image,
'image_width' => $image_width,
'image_height' => $image_height,
'enabled_backup' => ENABLED_BACKUP,
'user_exist' => $user_exist,
'cms_folder_exist' => file_exists(BASE_PATH),
'time' => NOW,
]);
exit();
}
}
//////////////////////////////////////////////////
// check for HTTP method POST
//////////////////////////////////////////////////
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (array_key_exists('api', $_REQUEST)) {
// log in
if ($_REQUEST['api'] == 'login') {
startSession();
if (array_key_exists('username', $_REQUEST) &&
array_key_exists('password', $_REQUEST) &&
array_key_exists(HTTP_X_CSRF_TOKEN, $_SERVER) &&
!empty($_REQUEST['username']) &&
!empty($_REQUEST['password']) &&
!empty($_SERVER[HTTP_X_CSRF_TOKEN])) {
if ($_SESSION[SESSION_LOGIN_ATTEMPTS] < MAX_LOGIN_ATTEMPTS && hash_equals($_SESSION[SESSION_LOGIN_CSRF_TOKEN], $_SERVER[HTTP_X_CSRF_TOKEN])) {
$username = sanitizeString($_REQUEST['username']);
$password = $_REQUEST['password'];
foreach ($users as $key => $user) {
if (!empty($user) && !empty($user['username']) && !empty($user['password_hash'])) {
if ($username == $user['username'] && password_verify($password, $user['password_hash'])) {
backupContent();
$_SESSION[SESSION_LOGIN] = true;
$_SESSION[SESSION_LOGIN_USERNAME] = $user['username'];
$_SESSION[SESSION_LOGIN_GROUPS] = $user['groups'];
$_SESSION[SESSION_LOGIN_ATTEMPTS] = 0;
$_SESSION[SESSION_LOGIN_AUTHORIZATION_EDITOR] = isMemberOfGroup($required_editor_groups);
echo getJsonLoginInfo();
exit();
}
}
}
}
}
// no match, raise login attempts
$_SESSION[SESSION_LOGIN_ATTEMPTS]++;
http_response_code(401);
echo getJsonLoginInfo();
exit();
}
// log out
if ($_REQUEST['api'] == 'logout') {
startSession();
$_SESSION[SESSION_LOGIN] = false;
$_SESSION[SESSION_LOGIN_USERNAME] = '';
$_SESSION[SESSION_LOGIN_GROUPS] = [];
$_SESSION[SESSION_LOGIN_ATTEMPTS] = 0;
$_SESSION[SESSION_LOGIN_AUTHORIZATION_EDITOR] = false;
echo getJsonLoginInfo();
exit();
}
// set content by filename
if ($_REQUEST['api'] == 'content') {
enforceEditor();
foreach ($_REQUEST as $key => $value) {
if (strpos($key, VOLT_CONTENT) === 0 && strpos($key, VOLT_CONTENT . VOLT_BLOG_ITEM) === false) {
$key = substr($key, 13);
$file = BASE_PATH_TEXT . sanitizeString($key) . '.' . FILE_EXT_TXT;
file_put_contents($file, $value);
}
}
exit();
}
// set blog item
if ($_REQUEST['api'] == 'blog') {
enforceEditor();
setHeader('Content-Type', 'application/json');
$blog_item = [];
foreach ($_REQUEST as $key => $value) {
if (strpos($key, VOLT_BLOG_ITEM) === 0) {
$key = substr($key, 15);
$blog_item[$key] = $value;
}
}
$blog_id = $blog_item['blog-id'];
unset($blog_item['blog-id']);
$id = '';
if (isset($blog_item['id'])) {
$id = $blog_item['id'];
unset($blog_item['id']);
}
if (!empty($blog_id)) {
$db = new \PragmaPHP\FileDB\FileDB(BASE_PATH_BLOG . $blog_id);
if (empty($id)) {
$id = $db->create($blog_item);
} else {
$id = $db->update($id, $blog_item);
}
echo json_encode(['_id' => $id]);
}
exit();
}
// upload image
if ($_REQUEST['api'] == 'image') {
enforceEditor();
if (!empty($_FILES)) {
$image = current($_FILES);
if (!empty($image) && $image['error'] == UPLOAD_ERR_OK) {
$name = sanitizeString(pathinfo($image['name'], PATHINFO_FILENAME));
$ext = strtolower(pathinfo($image['name'], PATHINFO_EXTENSION));
$file = BASE_PATH_MEDIA . $name . '.' . $ext;
if (file_exists($file)) {
$file = BASE_PATH_MEDIA . $name . '_' . base_convert(time(), 10, 36) . '.' . $ext;
}
if (move_uploaded_file($image['tmp_name'], $file)) {
$file = scaleImage($file, $scale_image, $image_width, $image_height);
chmod($file, 0644);
echo json_encode(getImageInfo($file));
exit();
}
}
}
http_response_code(401);
exit();
}
}
}
//////////////////////////////////////////////////
// check for HTTP method DELETE
//////////////////////////////////////////////////
if ($_SERVER['REQUEST_METHOD'] == 'DELETE') {
if (array_key_exists('api', $_REQUEST)) {
// delete image
if ($_REQUEST['api'] == 'image' && array_key_exists('name', $_REQUEST)) {
enforceEditor();
$name = sanitizeString(pathinfo($_REQUEST['name'], PATHINFO_FILENAME));
$ext = strtolower(pathinfo($_REQUEST['name'], PATHINFO_EXTENSION));
$file = BASE_PATH_MEDIA . $name . '.' . $ext;
if (file_exists($file)) {
echo BASE_PATH_MEDIA . $name;
unlink($file);
}
exit();
}
// delete blog item
if ($_REQUEST['api'] == 'blog' && array_key_exists('blog-id', $_REQUEST) && array_key_exists('id', $_REQUEST)) {
enforceEditor();
$blog_id = $_REQUEST['blog-id'];
$id = $_REQUEST['id'];
if (!empty($blog_id) && !empty($id)) {
$db = new \PragmaPHP\FileDB\FileDB(BASE_PATH_BLOG . $blog_id);
$db->delete($id);
}
exit();
}
}
}
//////////////////////////////////////////////////
// functions
//////////////////////////////////////////////////
function setHeader($key, $value)
{
header($key . ': ' . $value);
}
function sanitizeString($value)
{
$value = trim($value);
$value = strtolower($value);
$value = preg_replace('/\s+/', '-', $value);
$value = preg_replace('/[^a-z0-9_\-]+/', '', $value);
return $value;
}
function initializeContent()
{
if (!file_exists(BASE_PATH)) {
mkdir(BASE_PATH);
chmod(BASE_PATH, 0755);
}
if (!file_exists(BASE_PATH_TEXT)) {
mkdir(BASE_PATH_TEXT);
chmod(BASE_PATH_TEXT, 0755);
}
if (!file_exists(BASE_PATH_TEXT . '.htaccess')) {
file_put_contents(BASE_PATH_TEXT . '.htaccess', HTACCESS);
}
if (!file_exists(BASE_PATH_BLOG)) {
mkdir(BASE_PATH_BLOG);
chmod(BASE_PATH_BLOG, 0755);
}
if (!file_exists(BASE_PATH_BLOG . '.htaccess')) {
file_put_contents(BASE_PATH_BLOG . '.htaccess', HTACCESS);
}
if (!file_exists(BASE_PATH_MEDIA)) {
mkdir(BASE_PATH_MEDIA);
chmod(BASE_PATH_MEDIA, 0755);
}
if (!file_exists(BASE_PATH_BACKUP)) {
mkdir(BASE_PATH_BACKUP);
chmod(BASE_PATH_BACKUP, 0755);
}
if (!file_exists(BASE_PATH_BACKUP . '.htaccess')) {
file_put_contents(BASE_PATH_BACKUP . '.htaccess', HTACCESS);
}
}
function backupContent()
{
if (ENABLED_BACKUP) {
zipFiles(BASE_PATH_BACKUP . 'backup_' . date('Y-m-d') . '_text.zip', BASE_PATH_TEXT);
$blog_dirs = array_filter(glob(BASE_PATH_BLOG . '*'), 'is_dir');
foreach ($blog_dirs as $folder) {
zipFiles(BASE_PATH_BACKUP . 'backup_' . date('Y-m-d') . '_blog_' . basename($folder) . '.zip', $folder . DIRECTORY_SEPARATOR);
}
}
}
function zipFiles($zipFile, $folder)
{
if (!file_exists($zipFile)) {
$files = glob($folder . '*');
if (count($files) > 0) {
$zip = new \ZipArchive();
$zip->open($zipFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
foreach ($files as $file) {
$zip->addFile($file, basename($file));
}
$zip->close();
}
}
}
function getJsonLoginInfo()
{
setHeader('Content-Type', 'application/json');
return json_encode([
'login' => $_SESSION[SESSION_LOGIN],
'username' => $_SESSION[SESSION_LOGIN_USERNAME],
'editor' => $_SESSION[SESSION_LOGIN_AUTHORIZATION_EDITOR],
]);
}
function startSession()
{
if (session_status() === PHP_SESSION_NONE) {
$session_settings = [
'httponly' => true,
'samesite' => 'Strict',
'secure' => isset($_SERVER['HTTPS']) ? true : false
];
session_set_cookie_params($session_settings);
$s = session_start();
if ($s) {
if (!array_key_exists(SESSION_LOGIN, $_SESSION)) {
$_SESSION[SESSION_LOGIN] = false;
}
if (!array_key_exists(SESSION_LOGIN_USERNAME, $_SESSION)) {
$_SESSION[SESSION_LOGIN_USERNAME] = '';
}
if (!array_key_exists(SESSION_LOGIN_GROUPS, $_SESSION)) {
$_SESSION[SESSION_LOGIN_GROUPS] = [];
}
if (!array_key_exists(SESSION_LOGIN_ATTEMPTS, $_SESSION)) {
$_SESSION[SESSION_LOGIN_ATTEMPTS] = 0;
}
if (!array_key_exists(SESSION_LOGIN_AUTHORIZATION_EDITOR, $_SESSION)) {
$_SESSION[SESSION_LOGIN_AUTHORIZATION_EDITOR] = false;
}
if (!array_key_exists(SESSION_LOGIN_CSRF_TOKEN, $_SESSION)) {
if (function_exists('random_bytes')) {
$_SESSION[SESSION_LOGIN_CSRF_TOKEN] = bin2hex(random_bytes(32));
} else {
$_SESSION[SESSION_LOGIN_CSRF_TOKEN] = bin2hex(rand());
}
}
}
}
}
function isLoggedIn()
{
startSession();
return (!empty($_SESSION) && array_key_exists(SESSION_LOGIN, $_SESSION) && $_SESSION[SESSION_LOGIN] === true);
}
function enforceLogin()
{
if (!isLoggedIn()) {
http_response_code(401);
echo getJsonLoginInfo();
exit();
}
}
function enforceEditor()
{
global $required_editor_groups;
enforceLogin();
if (!isMemberOfGroup($required_editor_groups)) {
http_response_code(401);
echo getJsonLoginInfo();
exit();
}
}
function isMemberOfGroup($required_groups)
{
$required_groups = array_map('Volt\\sanitizeString', explode(',', $required_groups));
if (!empty($required_groups[0]) && empty(array_intersect($required_groups, $_SESSION[SESSION_LOGIN_GROUPS]))) {
return false;
} else {
return true;
}
}
function protectPage($login_redirect, $forbidden_redirect, $required_groups)
{
if (!isLoggedIn()) {
if ($login_redirect) {
header('Location: ' . getLoginPage(ob_get_clean()) . '?ref=' . $_SERVER['REQUEST_URI']);
exit();
} else {
if ($forbidden_redirect) {
header('Location: ' . getForbiddenPage(ob_get_clean()) . '?ref=' . $_SERVER['REQUEST_URI']);
exit();
} else {
ob_end_clean();
http_response_code(401);
echo "<h1>Forbidden</h1>";
exit;
}
}
} else {
if (!isMemberOfGroup($required_groups)) {
if ($forbidden_redirect) {
header('Location: ' . getForbiddenPage(ob_get_clean()) . '?ref=' . $_SERVER['REQUEST_URI']);
exit();
} else {
ob_end_clean();
http_response_code(401);
echo "<h1>Forbidden</h1>";
exit;
}
}
}
}
function getImageInfo($file)
{
$size_temp = getimagesize($file);
if (is_array($size_temp)) {
$size = [$size_temp[0], $size_temp[1]];
} else {
$size = [1,1];
}
return [
'url' => '/' . BASE_FOLDER_CONTENT . '/' . BASE_FOLDER_MEDIA . '/' . basename($file),
'size' => $size,
'name' => pathinfo($file)['filename'],
'filesize' => filesize($file),
];
}
function scaleImage($file, $scale_image, $image_width, $image_height)
{
if ($scale_image) {
$image_info = getimagesize($file);
if ($image_info[0] > $image_width || $image_info[1] > $image_height) {
$image = false;
$ratio_width = $image_width / $image_info[0];
$ratio_height = $image_height / $image_info[1];
$ratio = min($ratio_width, $ratio_height);
$new_width = (int) $image_info[0] * $ratio;
switch ($image_info[2]) {
// IMAGETYPE_JPEG / IMG_JPG
case 2:
if (imagetypes() & 2) {
$image = imagecreatefromjpeg($file);
$image = imagescale($image, $new_width);
imagejpeg($image, $file);
}
break;
default:
break;
}
}
}
return $file;
}
function parseBlogURL()
{
global $page, $post, $author, $category, $date, $tag, $search, $search_array, $sort_by, $feed, $query, $display_detail, $display_filter, $filter;
if ($_SERVER['REQUEST_METHOD'] == 'GET') {
$urlQuery = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
if (!$urlQuery) {
$urlQuery = '';
}
parse_str($urlQuery, $parsedUrl);
if (isset($parsedUrl['page'])) {
$page = $parsedUrl['page'];
}
if (isset($parsedUrl['post'])) {
$post = $parsedUrl['post'];
} else if (isset($_REQUEST['post'])) {
$post = $_REQUEST['post'];
}
if (isset($parsedUrl['author'])) {
$author = $parsedUrl['author'];
} else if (isset($_REQUEST['author'])) {
$author = $_REQUEST['author'];
}
if (isset($parsedUrl['category'])) {
$category = $parsedUrl['category'];
} else if (isset($_REQUEST['category'])) {
$category = $_REQUEST['category'];
}
if (isset($parsedUrl['date'])) {
$date = $parsedUrl['date'];
} else if (isset($_REQUEST['date'])) {
$date = $_REQUEST['date'];
}
if (isset($parsedUrl['tag'])) {
$tag = $parsedUrl['tag'];
} else if (isset($_REQUEST['tag'])) {
$tag = $_REQUEST['tag'];
}
if (isset($parsedUrl['search'])) {
$search = $parsedUrl['search'];
$search_array = buildSearchArray($search);
} else if (isset($_REQUEST['search'])) {
$search = $_REQUEST['search'];
$search_array = buildSearchArray($search);
}
if (isset($parsedUrl['sort_by'])) {
$sort_by = $parsedUrl['sort_by'];
} else if (isset($_REQUEST['sort_by'])) {
$sort_by = $_REQUEST['sort_by'];
}
if (isset($parsedUrl['feed'])) {
$feed = $parsedUrl['feed'];
} else if (isset($_REQUEST['feed'])) {
$feed = $_REQUEST['feed'];
}
} else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_REQUEST['search'])) {
$search = $_REQUEST['search'];
$search_array = buildSearchArray($search);
}
if (isset($_REQUEST['sort_by'])) {
$sort_by = $_REQUEST['sort_by'];
}
}
if (!is_numeric($page)) {
$page = 1;
}
if ($post != "") {
$display_detail = true;
}
if ($category != "" || $date != "" || $author != "" || $search != "") {
$display_filter = true;
}
if (!empty($author)) {
$query = $query . "&author=" . $author;
$filter = $author;
}
if (!empty($category)) {
$query = $query . "&category=" . $category;
$filter = $category;
}
if (!empty($date)) {
$query = $query . "&date=" . $date;
$filter = $date;
}
if (!empty($tag)) {
$query = $query . "&tag=" . $tag;
$filter = $tag;
}
if (!empty($search)) {
$query = $query . "&search=" . $search;
$filter = $search;
}
}
function slugify($slug)
{
$slug = preg_replace('~[^\pL\d]+~u', '-', $slug);
$slug = trim($slug, '-');
$slug = preg_replace('~-+~', '-', $slug);
$slug = strtolower($slug);
if (empty($slug)) {
return 'n-a';
}
return $slug;
}
function buildFilterArray(&$values, &$filter_archive)
{
$array = array();
$s = "";
if (!empty($values)) {
foreach ($values as $value) {
if ($value != "") {
$s = slugify($value);
array_push($array, $s);
$filter_archive[$s] = $value;
}
}
}
return $array;
}
function buildCategoryArray(&$values)
{
global $category_archive;
return buildFilterArray($values, $category_archive);
}
function buildDateArray($date_str)
{
global $date_year_archive, $date_month_archive;
if (is_int($date_str)) {
$date_str = date("Y-m-d", $date_str);
}
if (!empty($date_str)) {
$s = substr($date_str, 0, 4);
$date_year_archive[$s] = $s;
$s = substr($date_str, 0, 7);
$date_month_archive[$s] = $s;
}
}
function buildAuthorArray(&$values)
{
global $author_archive;
return buildFilterArray($values, $author_archive);
}
function buildSearchArray($search)
{
if (!empty($search)) {
$search_array = explode(' ', $search);
$search_array = array_filter($search_array, function ($value) {
return !is_null($value) && $value !== '';
}
);
return $search_array;
}
}
function full_text_search($haystack)
{
global $search_array;
$match = true;
foreach ($search_array as $search) {
if (stripos($haystack, $search) === false) {
$match = false;
}
}
return $match;
}
function buildFilterLinks($array, $values, $label, $separator_text, $htaccess_rewrite, $filter_name)
{
$result = '';
if (!empty($array)) {
$result = $label;
for ($i = 0, $count = count($array); $i < $count; $i++) {
if ($htaccess_rewrite) {
if ($i === 0) {
$result = $result . ' <a href="./' . $filter_name . '/' . $array[0] . '">' . htmlspecialchars($values[$i], ENT_QUOTES) . '</a>';
} else {
$result = $result . $separator_text . '<a href="./' . $filter_name . '/' . $array[$i] . '">' . htmlspecialchars($values[$i], ENT_QUOTES) . '</a>';
}
} else {
if ($i === 0) {
$result = $result . ' <a href="?' . $filter_name . '=' . $array[0] . '">' . htmlspecialchars($values[$i], ENT_QUOTES) . '</a>';
} else {
$result = $result . $separator_text . '<a href="?' . $filter_name . '=' . $array[$i] . '">' . htmlspecialchars($values[$i], ENT_QUOTES) . '</a>';
}
}
}
}
return $result;
}
function fixQuery($tempQuery)
{
if (!empty($tempQuery)) {
if (strpos($tempQuery, '&') === 0) {
$tempQuery = '?' . substr($tempQuery, 1);
}
}
return $tempQuery;
}
function getPostLink($slug, $htaccess_rewrite)
{
global $query;
if ($htaccess_rewrite) {
return './' . $slug . fixQuery($query);
} else {
return './?post=' . $slug . $query;
}
}
function getPostPermalink($slug, $htaccess_rewrite)
{
$dirname = dirname($_SERVER['PHP_SELF']);
if (!empty($dirname) && substr($dirname, -1) !== '/') {
$dirname = $dirname . '/';
}
if ($htaccess_rewrite) {
return 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $dirname . $slug;
} else {
return 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . $dirname . "?post=" . $slug;
}
}
function isPostInQuery($category_array, $date_str, $author_array, $text_array = null, $hide_future_items = 0)
{
global $category, $date, $author, $search;
if (is_int($date_str)) {
$date_str = date("Y-m-d", $date_str);
}
if (!empty($category) && !in_array($category, $category_array)) {
return false;
}
if (!empty($date) && (strpos($date_str, $date) !== 0)) {
return false;
}
if (!empty($author) && !in_array($author, $author_array)) {
return false;
}
if (!empty($search) && !empty($text_array) && empty(array_filter($text_array, "Volt\\full_text_search"))) {
return false;
}
if ($hide_future_items && $date_str > NOW) {
return false;
}
return true;
}
function replaceMetadataRssLink($page_buffer, $title)
{
global $page_path;
$page_buffer = str_replace('<he' . 'ad>', '<he' . 'ad>' . "\n" . '<link rel="alternate" type="application/rss+xml" title="' . $title . '" href="' . $page_path . '?feed=rss">', $page_buffer);
return $page_buffer;
}
function replaceMetadataTitle($page_buffer, $title)
{
global $page_path;
$page_buffer = preg_replace('/(<title)(.*?)(<\/title>)/i', '$1' . '$2' . ' - ' . htmlspecialchars($title, ENT_QUOTES) . '$3', $page_buffer);
return $page_buffer;
}
function replaceMetadataDocumentBase($page_buffer)
{
global $page_path;
$page_buffer = str_replace('<he' . 'ad>', '<he' . 'ad>' . "\n" . '<base href="' . $page_path . '">', $page_buffer);
return $page_buffer;
}
function replaceMetadataTag($buffer, $key, $value)
{
$index = strpos($buffer['header'], $key);
if ($index !== false) {
$buffer['header'] = preg_replace('/(' . $key . ')(.*?)(">)/i', '$1' . '"' . $value . '$3', $buffer['header']);
} else {
$buffer['new_content'] = $buffer['new_content'] . $key . '"' . $value . '">' . "\n";
}
return $buffer;
}
function replaceMetadata($page_buffer, $detail_item, $rss_data)
{
// global $metadata_fb_username, $metadata_twitter_username;
// print_r($detail_item);
$page_buffer = preg_replace('/(<title)(.*?)(<\/title>)/i', '$1' . '>' . $detail_item['title'] . '$3', $page_buffer);
$index_header_start = strpos($page_buffer, '<he' . 'ad>');
$index_header_end = strpos($page_buffer, '</he' . 'ad>');
$header = substr($page_buffer, $index_header_start, $index_header_end - $index_header_start);
$buffer = [
'header' => $header,
'new_content' => '',
];
$buffer['new_content'] = $buffer['new_content'] . '<link rel="canonical" href="' . $detail_item['permalink'] . '" />' . "\n";
$buffer = replaceMetadataTag($buffer, '<meta property="og:type" content=', 'article');
$index = strpos($buffer['header'], '<meta name="twitter:card" content="summary">');
if (!$index) {
$buffer['new_content'] = $buffer['new_content'] . '<meta name="twitter:card" content="summary">' . "\n";
}
$buffer = replaceMetadataTag($buffer, '<meta property="og:title" content=', $detail_item['title']);
$buffer = replaceMetadataTag($buffer, '<meta name="twitter:title" content=', $detail_item['title']);
$buffer = replaceMetadataTag($buffer, '<meta property="og:site_name" content=', $detail_item['title']);
// if ($metadata_fb_username) {
// $buffer = replaceMetadataTag($buffer, '<meta property="fb:admins" content=', $metadata_fb_username);
// }
// if ($metadata_twitter_username) {
// $buffer = replaceMetadataTag($buffer, '<meta name="twitter:site" content=', '@' . $metadata_twitter_username);
// }
$buffer = replaceMetadataTag($buffer, '<meta property="og:url" content=', $detail_item['permalink']);
$buffer = replaceMetadataTag($buffer, '<meta name="twitter:url" content=', $detail_item['permalink']);
$buffer = replaceMetadataTag($buffer, '<meta name="description" content=', $detail_item['description']);
$buffer = replaceMetadataTag($buffer, '<meta property="og:description" content=', $detail_item['description']);
$buffer = replaceMetadataTag($buffer, '<meta name="twitter:description" content=', $detail_item['description']);
if ($detail_item['preview_image']) {
$buffer = replaceMetadataTag($buffer, '<meta property="og:image" content=', $detail_item['preview_image']);
$buffer = replaceMetadataTag($buffer, '<meta name="twitter:image" content=', $detail_item['preview_image']);
}
$buffer['new_content'] = $buffer['new_content'] . '<meta property="fb:app_id" content="966242223397117">' . "\n";
$structured_data = [
"@context" => "https://schema.org",
"@type" => "NewsArticle",
"mainEntityOfPage" => [
"@type" => "WebPage",
"@id" => $detail_item['permalink'],
],
"headline" => $detail_item['title'],
"image" => [
$detail_item['preview_image'],
],
"datePublished" => $detail_item['date'],
"dateModified" => $detail_item['date'],
"author" => [
"@type" => "Person",
"name" => $detail_item['author'],
],
"publisher" => [
"@type" => "Organization",
"name" => $rss_data['rss_publisher'],
"logo" => [
"@type" => "ImageObject",
"url" => $rss_data['rss_image'],
],
],
"description" => $detail_item['description'],
];
$json_structured_data = '<script type="application/ld+json">' . "\n";
$json_structured_data = $json_structured_data . json_encode($structured_data);
$json_structured_data = $json_structured_data . "\n" . '</script>';
$buffer['new_content'] = $buffer['new_content'] . $json_structured_data;
$header = $buffer['header'] . $buffer['new_content'] . "\n";
return $page_buffer = substr($page_buffer, 0, $index_header_start) . $header . substr($page_buffer, $index_header_end);
}
function getImageSrc($html)
{
$match = array();
preg_match(IMAGE_REGEX, $html, $match);
if (!empty($match[1])) {
return $match[1];
}
return '';
}
function getLoginPage($html)
{
$match = array();
preg_match(LOGIN_REGEX, $html, $match);
if (!empty($match[1])) {
return $match[1];
}
return '';
}
function getForbiddenPage($html)
{
$match = array();
preg_match(FORBIDDEN_REGEX, $html, $match);
if (!empty($match[1])) {
return $match[1];
}
return '';
}
function getFullyQualifiedImageURL($src)
{
global $fully_qualified_domain;
if (!empty($src) && stripos($src, 'http') !== 0) {
$src = $fully_qualified_domain . $src;
// $src = str_replace('/./', '/', $src);
$src = str_replace('//_cms', '/_cms', $src);
}
return $src;
}
function getDateMillis($date)
{
if (is_int($date)) {
$date_millis = $date;
} else {
if (strlen($date) > 19) {
$date_millis = strtotime(substr($date, 0, 19));
} else {
$date_millis = strtotime($date);
}
}
return $date_millis;
}
function generateSitemap($rss_items)
{
header('Content-type: application/xml');
$html = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
// $html = $html . "<urlset xmlns:xsi=\"https://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"https://www.sitemaps.org/schemas/sitemap/0.9/ https://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\" xmlns=\"https://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd\" xmlns:image=\"https://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd\" xmlns:video=\"https://www.google.com/schemas/sitemap-video/1.1/sitemap-video.xsd\">\n";
$html = $html . "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd http://www.google.com/schemas/sitemap-image/1.1 http://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd http://www.google.com/schemas/sitemap-video/1.1 http://www.google.com/schemas/sitemap-video/1.1/sitemap-video.xsd http://www.google.com/schemas/sitemap-news/0.9 http://www.google.com/schemas/sitemap-news/0.9/sitemap-news.xsd\" xmlns:image=\"http://www.google.com/schemas/sitemap-image/1.1\" xmlns:video=\"http://www.google.com/schemas/sitemap-video/1.1\" xmlns:news=\"http://www.google.com/schemas/sitemap-news/0.9\">\n";
foreach ($rss_items as $key => $detail_item) {
$html = $html . "<url><loc>" . $detail_item['permalink'] . "</loc>";
$html = $html . "<lastmod>" . date("Y-m-d", getDateMillis($detail_item['date'])) . "</lastmod>";
$html = $html . "<changefreq>monthly</changefreq><priority>0.5</priority>";
if ($detail_item['preview_image']) {
$html = $html . "<image:image><image:loc>" . $detail_item['preview_image'] . "</image:loc></image:image>";
}
$html = $html . "</url>\n";
}
$html = $html . "</urlset>";
return $html;
}
function generateRssFeed($rss_items, $rss_data, $date_pattern)
{
header('Content-type: application/rss+xml');
$html = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
$html = $html . "<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\">\n";
$html = $html . "<channel>\n";
$html = $html . "<title>" . $rss_data['rss_title'] . "</title>\n";
$html = $html . "<link>" . $rss_data['rss_url'] . "</link>\n";
$feed = "/?feed=rss";
if (substr($rss_data['rss_url'], -1) == '/') {
$feed = "?feed=rss";
}
$html = $html . "<atom:link href=\"" . $rss_data['rss_url'] . $feed . "\" rel=\"self\" type=\"application/rss+xml\"/>\n";
$html = $html . "<description>" . $rss_data['rss_description'] . "</description>\n";
$html = $html . "<language>" . $rss_data['rss_language'] . "</language>\n";
$html = $html . "<copyright>" . $rss_data['rss_copyright'] . "</copyright>\n";
$html = $html . "<lastBuildDate>" . date('r', NOW_MILLIS) . "</lastBuildDate>\n";
$html = $html . "<pubDate>" . date('r', NOW_MILLIS) . "</pubDate>\n";
if ($rss_data['rss_image']) {
$html = $html . "<image>\n";
$html = $html . "<url>" . $rss_data['rss_image'] . "</url>\n";
$html = $html . "<title>" . $rss_data['rss_title'] . "</title>\n";
$html = $html . "<link>" . $rss_data['rss_url'] . "</link>\n";
$html = $html . "</image>\n";
}
foreach ($rss_items as $key => $detail_item) {
$html = $html . "<item>\n";
$html = $html . "<title>" . $detail_item['title'] . "</title>\n";
$html = $html . "<link>" . $detail_item['permalink'] . "</link>\n";
$html = $html . "<description><![CDATA[" . $detail_item['description'] . "]]></description>\n";
$html = $html . "<pubDate>" . date('r', getDateMillis($detail_item['date'])) . "</pubDate>\n";
$html = $html . "<pubDateFormat>" . (new \DateTime($detail_item['date']))->format($date_pattern) . "</pubDateFormat>\n";
$html = $html . "<guid isPermaLink=\"true\">" . $detail_item['permalink'] . "</guid>\n";
if (!empty($detail_item['author'])) {
$html = $html . "<dc:creator>" . $detail_item['author'] . "</dc:creator>\n";
} else {
$html = $html . "<dc:creator>" . $rss_data['rss_publisher'] . "</dc:creator>\n";
}
if ($detail_item['preview_image']) {
$html = $html . "<content:encoded><![CDATA[<img src=\"" . $detail_item['preview_image'] . "\"/>]]></content:encoded>\n";
}
$html = $html . "</item>\n";
}
$html = $html . "</channel>\n";
$html = $html . "</rss>";
return $html;
}
function getBlogContent(
$blog_id = 1,
$items_per_page = 10,
$layout = '1 Column',
$date_pattern = 'd.m.Y H:i',
$hide_future_items = 0,
$author_text = 'Authors: ',
$category_text = 'Categories: ',
$tag_text = 'Tags: ',
$separator_text = ', ',
$readmore_text = 'Read More',
$back_text = 'Back',
$prev_post_text = 'Previous Post',
$next_post_text = 'Next Post',
$prev_page_text = 'Previous Page',
$next_page_text = 'Next Page',
$replace_metadata = 1,
$htaccess_rewrite = 0,
$rss_publisher = '',
$rss_title = '',
$rss_description = '',
$rss_language = 'en-us',
$rss_image = '',
$heading_list = 'h2',
$heading_detail = 'h1',
$scroll_detail_top = true,
$disqus_shorthand = '',
$metadata_display = 'Below Title',
$share_display = 'Above Body') {
global $display_detail, $display_filter, $filter, $post, $page, $search, $sort_by, $feed, $query, $last_page;
parseBlogURL();
if (isset($feed) && (($feed == "rss") || ($feed == "sitemap"))) {
$is_logged_in = false;
} else {
$is_logged_in = isLoggedIn();
}
if ($is_logged_in) {
$hide_future_items = 0;
}
$page_buffer = ob_get_clean();
$page_buffer = replaceMetadataRssLink($page_buffer, $rss_title);
if ($display_filter && !$display_detail) {
$page_buffer = replaceMetadataTitle($page_buffer, $filter);
}
if ($htaccess_rewrite) {
$page_buffer = replaceMetadataDocumentBase($page_buffer);
}
ob_start();
echo $page_buffer;
$rss_data = [
'rss_title' => htmlspecialchars($rss_title, ENT_QUOTES),
'rss_description' => htmlspecialchars($rss_description, ENT_QUOTES),
'rss_language' => $rss_language,
'rss_copyright' => htmlspecialchars($rss_publisher, ENT_QUOTES),
'rss_url' => 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']),
'rss_image' => $rss_image,
'rss_publisher' => htmlspecialchars($rss_publisher, ENT_QUOTES),
];
$prev_slug = "";
$next_slug = "";
$prev_title = "";
$next_title = "";
$store_prev_slug = true;
$store_next_slug = false;
$css_wrapper = '';
$css_item = '';
switch ($layout) {
case '1 Column':
break;
case 'Bootstrap 2 Columns':
$css_wrapper = 'row';
$css_item = 'col-12 col-md-6';
break;
case 'Bootstrap 3 Columns':
$css_wrapper = 'row';
$css_item = 'col-12 col-md-6 col-lg-4';
break;
case 'Bootstrap 4 Columns':
$css_wrapper = 'row';
$css_item = 'col-12 col-md-6 col-lg-4 col-xl-3';
break;
case 'Bootstrap 6 Columns':
$css_wrapper = 'row';
$css_item = 'col-12 col-md-6 col-lg-3 col-xl-2';
break;
case 'Masonry 2 Columns':
$css_wrapper = 'volt-blog-layout-masonry-2';
break;
case 'Masonry 3 Columns':
$css_wrapper = 'volt-blog-layout-masonry-3';
break;
case 'Masonry 4 Columns':
$css_wrapper = 'volt-blog-layout-masonry-4';
break;
default:
break;
}
$items_start = ($page - 1) * $items_per_page + 1;
$items_end = ($page) * $items_per_page;
$item = 0;
$current_item = 0;
$rss_items = [];
$db = new \PragmaPHP\FileDB\FileDB(BASE_PATH_BLOG . $blog_id);
$files = $db->readAll();
if (empty($sort_by)) {
$sort_by = "date_desc";
}
switch ($sort_by) {
case 'date_asc':
usort($files, function ($postFile1, $postFile2) {
return ($postFile1['date'] <=> $postFile2['date']);
});
break;
case 'date_desc':
usort($files, function ($postFile1, $postFile2) {
return ($postFile2['date'] <=> $postFile1['date']);
});
break;
case 'title_asc':
usort($files, function ($postFile1, $postFile2) {
return ($postFile1['title'] <=> $postFile2['title']);
});
break;
case 'title_desc':
usort($files, function ($postFile1, $postFile2) {
return ($postFile2['title'] <=> $postFile1['title']);
});
break;
default:
usort($files, function ($postFile1, $postFile2) {
return ($postFile2['date'] <=> $postFile1['date']);
});
break;
}
$html = '';
foreach ($files as $postFile) {
if ($is_logged_in || !isset($postFile['draft']) || (isset($postFile['draft']) && $postFile['draft'] === 'false')) {
$item_id = $postFile['_id'];
$postFile['title'] = htmlspecialchars($postFile['title'], ENT_QUOTES);
$title = $postFile['title'];
if (isset($postFile['description'])) {
$postFile['description'] = htmlspecialchars($postFile['description'], ENT_QUOTES);
$description = $postFile['description'];
}
if (empty($description)) {
$description = $title;
}
$category_raw = [];
if (isset($postFile['categories'])) {
$category_raw = array_map('trim', explode(',', $postFile['categories']));
}
$author_raw = [];
if (isset($postFile['authors'])) {
$author_raw = array_map('trim', explode(',', $postFile['authors']));
if (!empty($author_raw)) {
$postFile['author'] = htmlspecialchars($author_raw[0]);
} else {
$postFile['author'] = $rss_data['rss_publisher'];
}
}
$date_raw = $postFile['date'];
$author_array = buildAuthorArray($author_raw);
$category_array = buildCategoryArray($category_raw);
$date_array = buildDateArray($date_raw);
$text_array = [$title, $description];
if ($search != "") {
if (isset($postFile['summary'])) {
$text_array[] = strip_tags($postFile['summary']);
}
if (isset($postFile['main'])) {
$text_array[] = strip_tags($postFile['main']);
}
}
if (isPostInQuery($category_array, $date_raw, $author_array, $text_array, $hide_future_items)) {
$last_page = floor($item / $items_per_page) + 1;
$item++;
if ($store_prev_slug && isset($slug)) {
$prev_slug = $slug;
}
if (isset($postFile['slug'])) {
$slug = htmlspecialchars($postFile['slug'], ENT_QUOTES);
} else {
$slug = '';
}
if (empty($slug)) {
$slug = slugify($title);
} else {
$slug = slugify($slug);
}
$postFile['slug'] = $slug;
if ($store_next_slug) {
$next_slug = $slug;
$store_next_slug = false;
}
$link = getPostLink($slug, $htaccess_rewrite);
$postFile['permalink'] = getPostPermalink($slug, $htaccess_rewrite);
$permalink = $postFile['permalink'];
if (isset($postFile['header'])) {
$header = $postFile['header'];
} else {
$header = '';
}
$postFile['preview_image'] = getFullyQualifiedImageURL(getImageSrc($header));
if (!empty($feed)) {
$rss_items[] = $postFile;
continue;
}
// display post content
if ((!$display_detail && $items_start <= $item && $item <= $items_end) || ($display_detail && $post == $slug)) {
if ($display_detail) {
$store_prev_slug = false;
$store_next_slug = true;
$current_item = $item;
}
$date_format = (new \DateTime($date_raw))->format($date_pattern);
$author_links = buildFilterLinks($author_array, $author_raw, $author_text, $separator_text, $htaccess_rewrite, 'author');
$category_links = buildFilterLinks($category_array, $category_raw, $category_text, $separator_text, $htaccess_rewrite, 'category');
if (!empty($postFile['_readonly'])) {
$readonly = '1';
} else {
$readonly = '';
}
if (isset($postFile['summary'])) {
$summary = $postFile['summary'];
} else {
$summary = '';
}
if (isset($postFile['main'])) {
$main = $postFile['main'];
} else {
$main = '';
}
if (isset($postFile['gallery'])) {
$gallery = $postFile['gallery'];
} else {
$gallery = '';
}
if (isset($postFile['gallery-layout']) && !$is_logged_in) {
$galleryLayout = $postFile['gallery-layout'];
} else {
$galleryLayout = 'flexbox';
}
if ((isset($postFile['gallery-lightbox-captions']) && $postFile['gallery-lightbox-captions'] === 'true')) {
$galleryLightboxCaptions = 1;
} else {
$galleryLightboxCaptions = 0;
}
if (isset($postFile['gallery-carousel-interval'])) {
$galleryCarouselInterval = $postFile['gallery-carousel-interval'];
} else {
$galleryCarouselInterval = 5;
}
if ($display_detail) {
$backLink = '';
if ($last_page == 1) {
$backLink = './' . fixQuery($query);
} else {
$backLink = './?page=' . $last_page . $query;
}
$detail_item = $postFile;
// display detail
$html = $html . <<<EOT
<article class="volt-blog-item volt-blog-item-detail" data-item-id="$item_id" data-item-permalink="$permalink" data-item-title="$title" data-item-readonly="$readonly">
<section>
<div class="volt-blog-item-header volt-blog-item-header-detail">$header</div>
</section>
<section>
EOT;
if ($metadata_display == 'Above Title') {
$html = $html . <<<EOT
<div class="volt-blog-item-metadata volt-blog-item-metadata-detail">
<p>
<time datetime="$date_raw"><span class="volt-blog-item-date volt-blog-item-date-detail">$date_format</span></time>
<span class="volt-blog-item-category volt-blog-item-category-detail">$category_links</span>
<span class="volt-blog-item-author volt-blog-item-author-detail">$author_links</span>
</p>
</div>
EOT;
}
$html = $html . <<<EOT
<$heading_detail class="volt-blog-item-title volt-blog-item-title-detail mt-2">$title</$heading_detail>
EOT;
if ($metadata_display == 'Below Title') {
$html = $html . <<<EOT
<div class="volt-blog-item-metadata volt-blog-item-metadata-detail">
<p>
<time datetime="$date_raw"><span class="volt-blog-item-date volt-blog-item-date-detail">$date_format</span></time>
<span class="volt-blog-item-category volt-blog-item-category-detail">$category_links</span>
<span class="volt-blog-item-author volt-blog-item-author-detail">$author_links</span>
</p>
</div>
EOT;
}
if ($share_display == 'Above Body') {
$html = $html . <<<EOT
<div class="volt-blog-item-share volt-blog-item-share-detail"></div>
EOT;
}
$html = $html . <<<EOT
<div class="volt-blog-item-body volt-blog-item-body-detail">$main
EOT;
if (!empty($gallery)) {
$html = $html . <<<EOT
<div class="volt-gallery" data-gallery-layout="$galleryLayout" data-gallery-lightbox-captions="$galleryLightboxCaptions" data-gallery-carousel-interval="$galleryCarouselInterval">$gallery</div>
EOT;
}
$html = $html . <<<EOT
</div>
EOT;
if ($share_display == 'Below Body') {
$html = $html . <<<EOT
<div class="volt-blog-item-share volt-blog-item-share-detail"></div>
EOT;
}
$html = $html . <<<EOT
<div class="volt-blog-item-back mt-3"><a class="btn volt-blog-btn volt-blog-btn-back" href="$backLink">$back_text</a></div>
</section>
</article>
EOT;
} else {
// display list
$html = $html . <<<EOT
<div class="volt-blog-item-list-wrapper mb-5 $css_item">
<article class="volt-blog-item volt-blog-item-list" data-item-id="$item_id" data-item-permalink="$permalink" data-item-title="$title" data-item-readonly="$readonly">
<section>
<div class="volt-blog-item-header volt-blog-item-header-list"><a href="$link" class="volt-blog-item-header-link">$header</a></div>
</section>
<section>
EOT;
if ($metadata_display == 'Above Title') {
$html = $html . <<<EOT
<div class="volt-blog-item-metadata volt-blog-item-metadata-list">
<p>
<time datetime="$date_raw"><span class="volt-blog-item-date volt-blog-item-date-list">$date_format</span></time>
<span class="volt-blog-item-category volt-blog-item-category-list">$category_links</span>
<span class="volt-blog-item-author volt-blog-item-author-list">$author_links</span>
</p>
</div>
EOT;
}
$html = $html . <<<EOT
<$heading_list class="volt-blog-item-title volt-blog-item-title-list mt-2"><a href="$link" class="volt-blog-item-title-link">$title</a></$heading_list>
EOT;
if ($metadata_display == 'Below Title') {
$html = $html . <<<EOT
<div class="volt-blog-item-metadata volt-blog-item-metadata-list">
<p>
<time datetime="$date_raw"><span class="volt-blog-item-date volt-blog-item-date-list">$date_format</span></time>
<span class="volt-blog-item-category volt-blog-item-category-list">$category_links</span>
<span class="volt-blog-item-author volt-blog-item-author-list">$author_links</span>
</p>
</div>
EOT;
}
$html = $html . <<<EOT
<div class="volt-blog-item-body volt-blog-item-body-list">$summary</div>
<div class="volt-blog-item-readmore mt-3"><a class="btn volt-blog-btn volt-blog-btn-readmore" href="$link">$readmore_text</a></div>
</section>
</article>
</div>
EOT;
}
}
}
}
}
if (isset($feed) && ($feed == "rss")) {
ob_get_clean();
ob_start();
echo generateRssFeed($rss_items, $rss_data, $date_pattern);
exit();
}
if (isset($feed) && ($feed == "sitemap")) {
ob_get_clean();
ob_start();
echo generateSitemap($rss_items);
exit();
}
if ($display_detail) {
// display detail
if (isset($detail_item)) {
if ($replace_metadata) {
$page_buffer = replaceMetadata(ob_get_clean(), $detail_item, $rss_data);
ob_start();
echo $page_buffer;
}
$html = $html . '<div class="volt-blog-nav-post text-center mt-5 row">';
$html = $html . '<div class="volt-blog-nav-post-prev text-right col">';
if (!empty($prev_slug)) {
$html = $html . '<a class="btn volt-blog-btn volt-blog-btn-post-prev" href="' . getPostLink($prev_slug, $htaccess_rewrite) . '">' . $prev_post_text . '</a>';
}
$html = $html . '</div>';
$html = $html . '<div class="volt-blog-nav-post-counter btn d-none d-md-block disabled text-center col">' . $current_item . ' / ' . $item . '</div>';
$html = $html . '<div class="volt-blog-nav-post-next text-left col">';
if (!empty($next_slug)) {
$html = $html . '<a class="btn volt-blog-btn volt-blog-btn-post-next" href="' . getPostLink($next_slug, $htaccess_rewrite) . '">' . $next_post_text . '</a>';
}
$html = $html . '</div>';
$html = $html . '</div>';
$html = $html . '<style>.volt-blog-hide-in-detail {display: none !important;}</style>';
if (!$is_logged_in && $scroll_detail_top) {
$html = $html . "<script>document.addEventListener('DOMContentLoaded',function(event){var target = $('.volt-blog-item-detail').offset().top;if ($('.sticky-nav').length) {target -= $('.sticky-nav').outerHeight();}$('html,body').animate({scrollTop: target}, 0);});</script>";
}
if (!$is_logged_in && !empty($disqus_shorthand)) {
$html = $html . '<div id="disqus_thread"></div><script>var disqus_config = function () {this.page.url = "' . $detail_item['permalink'] . '";this.page.identifier = "' . $detail_item['slug'] . '";this.page.title = "' . $detail_item['title'] . '";};(function() {var d = document, s = d.createElement("script");s.src = "//' . $disqus_shorthand . '.disqus.com/embed.js";s.setAttribute("data-timestamp", +new Date());(d.head || d.body).appendChild(s);})();</script>';
}
} else {
http_response_code(404);
}
} else {
// display list
$html = '<div class="volt-blog-list ' . $css_wrapper . '">' . $html . '</div>';
if ($last_page > 1) {
$html = $html . '<div class="volt-blog-nav-page text-center mt-5 row">';
$html = $html . '<div class="volt-blog-nav-page-prev text-right col">';
if (1 < $page) {
if ($page == 2) {
$html = $html . '<a class="btn volt-blog-btn volt-blog-btn-page-prev" href="./' . fixQuery($query) . '">' . $prev_page_text . '</a>';
} else {
$html = $html . '<a class="btn volt-blog-btn volt-blog-btn-page-prev" href="./?page=' . ($page - 1) . $query . '">' . $prev_page_text . '</a>';
}
}
$html = $html . '</div>';
$html = $html . '<div class="volt-blog-nav-page-counter btn d-none d-md-block disabled text-center col">' . $page . ' / ' . $last_page . '</div>';
$html = $html . '<div class="volt-blog-nav-page-next text-left col">';
if ($page < $last_page) {
$html = $html . '<a class="btn volt-blog-btn volt-blog-btn-page-next" href="./?page=' . ($page + 1) . $query . '">' . $next_page_text . '</a>';
}
$html = $html . '</div>';
$html = $html . '</div>';
$html = $html . '<style>.volt-blog-hide-in-list {display: none !important;}</style>';
}
}
return $html;
}
//////////////////////////////////////////////////
// libraries
//////////////////////////////////////////////////
namespace PragmaPHP\Uid;
/**
* PHP Unique ID generator based on ULID (Universally Unique Lexicographically Sortable Identifier)
*/
class Uid {
/**
* @param int Time in milliseconds (optional). E.g. round(microtime(true) * 1000)
* @return string Unique ID
*/
public static function generate($millis = 0): string {
if ($millis === 0) {
$millis = round(microtime(true) * 1000);
}
$uid = self::encode($millis);
if (strlen($uid) < 10) {
$uid = '0' . $uid;
}
$uid = $uid . self::random_str() . self::random_str() . self::random_str() . self::random_str();
if (strlen($uid) != 26) {
throw new \Exception('Error in Uid generation.');
}
return $uid;
}
/**
* @return string Random 4 characters
*/
public static function random_str() {
// For cryptographically secure value, use random_int instead of rand
return self::encode(rand(100000, 999999));
}
/**
* @return string Base 32 encoded string
*/
public static function encode($str) {
$str = strtoupper(base_convert($str, 10, 32));
return strtr(
$str,
"ABCDEFGHIJKLMNOPQRSTUV",
"ABCDEFGHJKMNPQRSTVWXYZ");
}
public static function decode($str) {
$str = strtoupper($str);
return base_convert(
strtr($str,
"ABCDEFGHJKMNPQRSTVWXYZILO",
"ABCDEFGHIJKLMNOPQRSTUV110"),
32, 10);
}
}
namespace PragmaPHP\FileDB;
use \PragmaPHP\Uid\Uid;
/**
* Flat file DB based on JSON files
*/
class FileDB
{
const ATTRIBUTE_ID = '_id';
const ATTRIBUTE_CREATED = '_created';
const ATTRIBUTE_MODIFIED = '_modified';
const ATTRIBUTE_READONLY = '_readonly';
const FILE_EXT_JSON = '.json';
private $directory;
/**
* @param string Directory
*/
public function __construct(string $directory)
{
// check if directory is existing
if (!is_dir($directory)) {
if (!mkdir($directory, 0777, true)) {
throw new \Exception("Directory " . $directory . " cannot be created");
}
} else if (!is_writable($directory)) {
throw new \Exception("Directory " . $directory . " is not writeable");
}
$this->directory = $directory;
}
/**
* @param array Data
*/
public function create(array $data): string
{
$time = microtime(true);
$created = date(DATE_ATOM, round($time));
$id = Uid::generate(round($time * 1000));
$data = self::removePrivateFields($data);
$data[self::ATTRIBUTE_ID] = $id;
$data[self::ATTRIBUTE_CREATED] = $created;
$this->writeFile($id, $data);
return $id;
}
/**
* @param string Unique ID
* @param array Data
*/
public function read(?string $id = null, ?array $search_data = null): array
{
$result = [];
if (!empty($id)) {
$files = [$this->directory . DIRECTORY_SEPARATOR . $id . self::FILE_EXT_JSON];
return $this->readFiles($files);
} else if (!empty($search_data)) {
// TODO performance, multi search array, wildcard search
$files = $this->readAll();
foreach ($files as $file) {
foreach ($search_data as $search_key => $search_value) {
$search_value = trim($search_value);
$search_key = trim($search_key);
if (array_key_exists($search_key, $file)) {
foreach ($file as $key => $value) {
if ($key == $search_key) {
if (self::startsWith($search_value, '*') && self::endsWith($search_value, '*') && strlen($search_value) > 3) {
if (stripos($value, substr($search_value, 1, -1)) !== false) {
$result[] = $file;
}
} else {
if (strcasecmp($value, $search_value) === 0) {
$result[] = $file;
}
}
}
}
}
}
}
}
return $result;
}
/**
* @param string Unique ID
* @param array Data
*/
public function readAll(): array
{
$files = glob($this->directory . DIRECTORY_SEPARATOR . '*' . self::FILE_EXT_JSON);
return $this->readFiles($files);
}
/**
* @param string Unique ID
* @param array Data
*/
public function update(string $id, array $data): string
{
$file = $this->directory . DIRECTORY_SEPARATOR . $id . self::FILE_EXT_JSON;
if (is_file($file)) {
$file_data = $this->readFile($file);
if (!self::isReadonly($file_data)) {
$data = self::removePrivateFields($data);
$data = array_merge($file_data, $data);
$data[self::ATTRIBUTE_MODIFIED] = date(DATE_ATOM, round(microtime(true)));
$this->writeFile($id, $data);
}
}
return $id;
}
/**
* @param string Unique ID
*/
public function delete(string $id)
{
$files = [$this->directory . DIRECTORY_SEPARATOR . $id . self::FILE_EXT_JSON];
$this->deleteFiles($files);
}
/**
* @param string Unique ID
*/
public function deleteAll()
{
$files = glob($this->directory . DIRECTORY_SEPARATOR . '*' . self::FILE_EXT_JSON);
$this->deleteFiles($files);
}
/**
* @param string Unique ID
* @param array Data
*/
public function setReadonly(string $id, bool $readonly): string
{
$file = $this->directory . DIRECTORY_SEPARATOR . $id . self::FILE_EXT_JSON;
if (is_file($file)) {
$data = $this->readFile($file);
$data[self::ATTRIBUTE_READONLY] = $readonly;
$data[self::ATTRIBUTE_MODIFIED] = date(DATE_ATOM, round(microtime(true)));
$this->writeFile($id, $data);
}
return $id;
}
private function writeFile(string $id, array $data)
{
$file = $this->directory . DIRECTORY_SEPARATOR . $id . self::FILE_EXT_JSON;
ksort($data);
// todo trim array
array_walk_recursive($data, function (&$v) {$v = trim($v);});
file_put_contents($file, json_encode($data, JSON_PRETTY_PRINT));
}
private function readFiles(array $files): array
{
$result = [];
foreach ($files as $file) {
if (is_file($file)) {
$result[] = $this->readFile($file);
}
}
return $result;
}
private function readFile($file): array
{
return json_decode(file_get_contents($file), true);
}
private function deleteFiles(array $files)
{
foreach ($files as $file) {
if (is_file($file)) {
$original_data = $this->readFile($file);
if (!self::isReadonly($original_data)) {
unlink($file);
}
}
}
}
private static function startsWith($haystack, $needle)
{
return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
private static function endsWith($haystack, $needle)
{
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}
private static function isReadonly($data)
{
if (array_key_exists('_readonly', $data) && $data['_readonly']) {
return true;
}
return false;
}
private static function removePrivateFields(array $data): array
{
foreach ($data as $key => $value) {
if (strpos($key, '_') === 0) {
unset($data[$key]);
}
}
return $data;
}
}