Copyright (C) Rodolfo Berrios A. All rights reserved.
BY USING THIS SOFTWARE YOU DECLARE TO ACCEPT THE CHEVERETO EULA
http://chevereto.com/license
--------------------------------------------------------------------- */
use TijsVerkoyen\Akismet\Akismet;
$route = function ($handler) {
try {
if ($_POST and !$handler::checkAuthToken($_REQUEST['auth_token'])) {
$handler->template = 'request-denied';
return;
}
$doing = $handler->request[0];
$logged_user = CHV\Login::getUser();
if (!$logged_user) {
G\redirect(G\get_base_url('login'));
}
// Hack the user settings route
if ($doing == 'user' && $handler::getCond('content_manager')) {
$route = $handler->getRouteFn('settings');
$handler::setCond('dashboard_user', true);
return $route($handler);
}
if (!$logged_user['is_admin']) {
return $handler->issue404();
}
$route_prefix = 'dashboard';
$sub_routes = [
'stats' => _s('Stats'),
'images' => _s('Images'),
'albums' => _s('Albums'),
'users' => _s('Users'),
'settings' => _s('Settings'),
'bulk' => _s('Bulk importer'),
];
$default_route = 'stats';
if (!is_null($doing) and !array_key_exists($doing, $sub_routes)) {
return $handler->issue404();
}
if ($doing == '') {
$doing = $default_route;
}
// Populate the routes
foreach ($sub_routes as $route => $label) {
$aux = str_replace('_', '-', $route);
$handler::setCond($route_prefix . '_' . $aux, $doing == $aux);
if ($handler::getCond($route_prefix . '_' . $aux)) {
$handler::setVar($route_prefix, $aux);
}
$route_menu[$route] = array(
'label' => $label,
'url' => G\get_base_url($route_prefix . ($route == $default_route ? '' : '/' . $route)),
'current' => $handler::getCond($route_prefix . '_' . $aux)
);
}
$route_menu['upgrade'] = [
'label' => 'โญ Upgrade',
'id' => 'upgrade'
];
$handler::setVar($route_prefix . '_menu', $route_menu);
$handler::setVar('tabs', $route_menu);
// conds
$is_error = false;
$is_changed = false;
// vars
$input_errors = [];
$error_message = null;
if ($doing == '') {
$doing = 'stats';
}
// Old and new image size counter
$image_size_count_qry = 'SELECT (SUM(image_size) + SUM(image_thumb_size) + SUM(image_medium_size)) as count';
switch ($doing) {
case 'stats':
$totals = CHV\Stat::getTotals();
$totals_display = [];
foreach (['images', 'users', 'albums'] as $v) {
$totals_display[$v] = G\abbreviate_number($totals[$v]);
}
$format_disk_ussage = explode(' ', G\format_bytes($totals['disk_used']));
$totals_display['disk'] = ['used' => $format_disk_ussage[0], 'unit' => $format_disk_ussage[1]];
if (empty($totals_display['disk']['used'])) {
$totals_display['disk'] = [
'used' => 0,
'unit' => 'KB'
];
}
$db = CHV\DB::getInstance();
$chv_version = [
'files' => G\get_app_version(),
'db' => CHV\getSetting('chevereto_version_installed')
];
$system_values = [
'chv_version' => [
'label' => 'Chevereto (Free)',
'content' => (version_compare($chv_version['files'], $chv_version['db'], '<=') ? $chv_version['files'] : $chv_version['files'] . ' ('.$chv_version['db'].' DB) '._s('install update').'') . ' โ ' . _s("check for updates") . '',
],
'support' => [
'label' => 'Support',
'content' => _s('Need help? Go to %s and you will get help quickly.', ['%s' => '' . _s('Support') . ''])
],
'php_version' => [
'label' => _s('PHP version'),
'content' => PHP_VERSION . ' ๐ '. php_ini_loaded_file()
],
'server' => [
'label' => _s('Server'),
'content' => gethostname() . ' ' . PHP_OS . '/' . PHP_SAPI
],
'mysql_version' => [
'label' => _s('MySQL version'),
'content' => $db->getAttr(PDO::ATTR_SERVER_VERSION)
],
'mysql_server_info' => [
'label' => _s('MySQL server info'),
'content' => $db->getAttr(PDO::ATTR_SERVER_INFO)
],
'gdversion' => [
'label' => _s('GD Library'),
'content' => 'Version ' . gd_info()['GD Version'] . ' JPEG:' . gd_info()['JPEG Support'] . ' GIF:' . gd_info()['GIF Read Support'] . '/' . gd_info()['GIF Create Support'] . ' PNG:' . gd_info()['PNG Support'] . ' WBMP:' . gd_info()['WBMP Support'] . ' XBM:' . gd_info()['XBM Support']
],
'file_uploads' => [
'label' => _s('File uploads'),
'content' => ini_get('file_uploads') == 1 ? _s('Enabled') : _s('Disabled')
],
'max_upload_size' => [
'label' => _s('Max. upload file size'),
'content' => G\format_bytes(G\get_ini_bytes(ini_get('upload_max_filesize')))
],
'max_post_size' => [
'label' => _s('Max. post size'),
'content' => ini_get('post_max_size') == 0 ? _s('Unlimited') : G\format_bytes(G\get_ini_bytes(ini_get('post_max_size')))
],
'max_execution_time' => [
'label' => _s('Max. execution time'),
'content' => strtr(_n('%d second', '%d seconds', ini_get('max_execution_time')), ['%d' => ini_get('max_execution_time')])
],
'memory_limit' => [
'label' => _s('Memory limit'),
'content' => G\format_bytes(G\get_ini_bytes(ini_get('memory_limit')))
],
'rebuild_stats' => [
'label' => _s('Stats'),
'content' => ''. _s('Rebuild stats') .''
],
'connecting_ip' => [
'label' => _s('Connecting IP'),
'content' => G\get_client_ip() . ' ' . _s('Not your IP?') . ''
],
'links' => [
'label' => _s('Links'),
],
];
$chevereto_urls = [
'Chevereto' => 'https://chevereto.com',
_s('Community') => 'https://chevereto.com/community/',
_s('Collaboration') => 'https://chevereto.com/community/collaboration/',
_s('Support') => 'https://chevereto.com/support',
_s('Documentation') => 'https://v3-docs.chevereto.com/',
_s('Changelog') => 'https://chevereto.com/changelog',
_s('Bug tracking') => 'https://chevereto.com/bug-tracking',
'GitHub' => 'https://github.com/chevereto',
];
$chevereto_links = [];
foreach ($chevereto_urls as $k => $v) {
$chevereto_links[] = '' . $k . '';
}
$system_values['links']['content'] = implode(' ยท ', $chevereto_links);
$handler::setVar('system_values', $system_values);
$handler::setVar('totals', $totals);
$handler::setVar('totals_display', $totals_display);
break;
case 'settings':
$max_request_level = $handler->request[1] == 'pages' ? (in_array($handler->request[2], ['edit', 'delete']) ? 6 : 5) : 4;
if ($handler->isRequestLevel($max_request_level)) {
return $handler->issue404();
}
$handler::setCond('show_submit', true);
$settings_sections = [
'website' => _s('Website'),
'content' => _s('Content'),
'pages' => _s('Pages'),
'listings' => _s('Listings'),
'image-upload' => _s('Image upload'),
'categories' => _s('Categories'),
'users' => _s('Users'),
'consent-screen' => _s('Consent screen'),
'flood-protection' => _s('Flood protection'),
'theme' => _s('Theme'),
'homepage' => _s('Homepage'),
'banners' => _s('Banners'),
'system' => _s('System'),
'routing' => _s('Routing'),
'languages' => _s('Languages'),
'external-storage' => _s('External storage'),
'email' => _s('Email'),
'social-networks' => _s('Social networks'),
'external-services' => _s('External services'),
'ip-bans' => _s('IP bans'),
'api' => 'API',
'additional-settings' => _s('Additional settings'),
'tools' => _s('Tools'),
];
foreach ($settings_sections as $k => $v) {
$current = $handler->request[1] ? ($handler->request[1] == $k) : ($k == 'website');
$settings_sections[$k] = [
'key' => $k,
'label' => $v,
'url' => G\get_base_url($route_prefix . '/settings/' . $k),
'current' => $current
];
if ($current) {
$handler::setVar('settings', $settings_sections[$k]);
if (in_array($k, ['categories', 'ip-bans'])) {
$handler::setCond('show_submit', false);
}
}
}
// Reject non-existing settings sections
if (!empty($handler->request[1]) && !array_key_exists($handler->request[1], $settings_sections)) {
return $handler->issue404();
}
$handler::setVar('settings_menu', $settings_sections);
//$handler::setVar('tabs', $settings_sections);
switch ($handler->request[1]) {
case 'homepage':
if ($_GET['action'] == 'delete-cover' && isset($_GET['cover'])) {
$cover_index = $_GET['cover'] - 1;
$homecovers = CHV\getSetting('homepage_cover_images');
$cover_target = $homecovers[$cover_index];
if (!G\is_integer($_GET['cover'], ['min' => 0]) || !isset($cover_target)) {
$is_error = true;
$error_message = _s('Request denied');
}
if (is_array($homecovers) && count($homecovers) == 1) {
$is_error = true;
$input_errors[sprintf('homepage_cover_image_%s', $cover_index)] = _s("Can't delete all homepage cover images");
}
if (!$is_error) {
// Try to delete the image (disk)
if (!G\starts_with('default/', $cover_target['basename'])) {
$cover_file = CHV_PATH_CONTENT_IMAGES_SYSTEM . $cover_target['basename'];
@unlink($cover_file);
}
unset($homecovers[$cover_index]);
$homecovers = array_values($homecovers);
$homecovers_db = [];
foreach ($homecovers as $v) {
$homecovers_db[] = $v['basename'];
}
CHV\Settings::update(['homepage_cover_image' => implode(',', $homecovers_db)]);
$_SESSION['is_changed'] = true;
G\redirect('dashboard/settings/homepage');
}
}
if ($_SESSION['is_changed']) {
$is_changed = true;
$changed_message = _s('Homepage cover image deleted');
unset($_SESSION['is_changed']);
}
break;
case 'tools':
$handler::setCond('show_submit', false);
break;
case 'pages':
// Check the sub-request
if ($handler->request[2]) {
switch ($handler->request[2]) {
case 'add':
$settings_pages['title'] = _s('Add page');
$settings_pages['doing'] = 'add';
break;
case 'edit':
case 'delete':
if (!filter_var($handler->request[3], FILTER_VALIDATE_INT)) {
return $handler->issue404();
}
$page = CHV\Page::getSingle($handler->request[3], 'id');
if ($page) {
// Workaround for default pages
if (G\starts_with('default/', $page['file_path'])) {
$page['file_path'] = null;
}
} else {
return $handler->issue404();
}
$handler::setvar('page', $page);
if ($handler->request[2] == 'edit') {
$settings_pages['title'] = _s('Edit page ID %s', $page['id']);
$settings_pages['doing'] = 'edit';
if ($_SESSION['dashboard_page_added']) {
if ($_SESSION['dashboard_page_added']['id'] == $page['id']) {
$is_changed = true;
$changed_message = _s('The page has been added successfully.');
}
unset($_SESSION['dashboard_page_added']);
}
}
if ($handler->request[2] == 'delete') {
if (!$handler::checkAuthToken($_REQUEST['auth_token'])) {
$handler->template = 'request-denied';
return;
}
CHV\Page::delete($page);
$_SESSION['dashboard_page_deleted'] = [
'id' => $page['id']
];
G\redirect('dashboard/settings/pages');
}
break;
default:
return $handler->issue404();
break;
}
} else {
$pages = CHV\Page::getAll([], ['field' => 'sort_display', 'order' => 'asc']);
$handler::setVar('pages', $pages ?: []);
$settings_pages['doing'] = 'listing';
if ($_SESSION['dashboard_page_deleted']) {
$is_changed = true;
$changed_message = _s('The page has been deleted.');
unset($_SESSION['dashboard_page_deleted']);
}
$handler::setCond('show_submit', false);
}
$handler::setvar('settings_pages', $settings_pages);
break;
}
if ($_POST) {
if (!headers_sent()) {
header('X-XSS-Protection: 0');
}
/*** Do some cleaning... ***/
// Remove bad formatting and duplicates
if ($_POST['theme_home_uids']) {
$_POST['theme_home_uids'] = implode(',', array_keys(array_flip(explode(',', trim(preg_replace(['/\s+/', '/,+/'], ['', ','], $_POST['theme_home_uids']), ',')))));
}
// Personal mode stuff
if ($_POST['website_mode'] == 'personal') {
$_POST['website_mode_personal_routing'] = G\get_regex_match(CHV\getSetting('routing_regex'), '#', $_POST['website_mode_personal_routing'], 1);
if (!G\check_value($_POST['website_mode_personal_routing'])) {
$_POST['website_mode_personal_routing'] = '/';
}
}
if (isset($_POST['homepage_cta_fn_extra'])) {
$_POST['homepage_cta_fn_extra'] = trim($_POST['homepage_cta_fn_extra']);
}
// Columns number
foreach (['phone', 'phablet', 'laptop', 'desktop'] as $k) {
if ($_POST['listing_columns_' . $k]) {
$key = 'listing_columns_' . $k;
$val = $_POST[$key];
$_POST[$key] = (filter_var($val, FILTER_VALIDATE_INT) and $val > 0) ? $val : CHV\get_chv_default_setting($key);
}
}
// HEX color
if ($_POST['theme_main_color']) {
$_POST['theme_main_color'] = '#' . ltrim($_POST['theme_main_color'], '#');
}
// Pages related cleaning
if ($handler->request[1] == 'pages') {
$page_file_path_clean = trim(G\sanitize_relative_path($_POST['page_file_path']), '/');
$_POST['page_file_path'] = str_replace('default/', null, $page_file_path_clean);
$_POST['page_file_path_absolute'] = CHV\Page::getPath($_POST['page_file_path']);
// Invalid page sort display
if (!filter_var($_POST['page_sort_display'], FILTER_VALIDATE_INT)) {
$_POST['page_sort_display'] = null;
}
// Do some fixing..
if ($_POST['page_type'] == 'internal') {
if (!$_POST['page_is_active']) {
$_POST['page_is_link_visible'] = false;
}
} else {
$_POST['page_is_link_visible'] = $_POST['page_is_active'];
}
$handler::updateVar('safe_post', [
'page_is_active' => $_POST['page_is_active'],
'page_is_link_visible' => $_POST['page_is_link_visible'],
'page_file_path_absolute' => $_POST['page_file_path_absolute'],
]);
}
// Validations
$validations = [
'website_name' =>
[
'validate' => $_POST['website_name'] ? true : false,
'error_msg' => _s('Invalid website name')
],
'default_language' =>
[
'validate' => CHV\get_available_languages()[$_POST['default_language']] ? true : false,
'error_msg' => _s('Invalid language')
],
'default_timezone' =>
[
'validate' => in_array($_POST['default_timezone'], timezone_identifiers_list()),
'error_msg' => _s('Invalid timezone')
],
'listing_items_per_page' =>
[
'validate' => G\is_integer($_POST['listing_items_per_page'], ['min' => 1]),
'error_msg' => _s('Invalid value: %s', $_POST['listing_items_per_page'])
],
'upload_threads' =>
[
'validate' => G\is_integer($_POST['upload_threads'], ['min' => 1, 'max' => 5]),
'error_msg' => _s('Invalid value: %s', $_POST['upload_threads'])
],
'upload_storage_mode' =>
[
'validate' => in_array($_POST['upload_storage_mode'], ['datefolder', 'direct']),
'error_msg' => _s('Invalid upload storage mode')
],
'upload_filenaming' =>
[
'validate' => in_array($_POST['upload_filenaming'], ['original', 'random', 'mixed', 'id']),
'error_msg' => _s('Invalid upload filenaming')
],
'upload_thumb_width' =>
[
'validate' => G\is_integer($_POST['upload_thumb_width'], ['min' => 16]),
'error_msg' => _s('Invalid thumb width')
],
'upload_thumb_height' =>
[
'validate' => G\is_integer($_POST['upload_thumb_height'], ['min' => 16]),
'error_msg' => _s('Invalid thumb height')
],
'upload_medium_size' =>
[
'validate' => G\is_integer($_POST['upload_medium_size'], ['min' => 16]),
'error_msg' => _s('Invalid medium size')
],
'watermark_percentage' =>
[
'validate' => G\is_integer($_POST['watermark_percentage'], ['min' => 1, 'max' => 100]),
'error_msg' => _s('Invalid watermark percentage')
],
'watermark_opacity' =>
[
'validate' => G\is_integer($_POST['watermark_opacity'], ['min' => 0, 'max' => 100]),
'error_msg' => _s('Invalid watermark opacity')
],
'theme' =>
[
'validate' => file_exists(G_APP_PATH_THEMES . $_POST['theme']),
'error_msg' => _s('Invalid theme')
],
'theme_logo_height' =>
[
'validate' => !empty($_POST['theme_logo_height']) ? (G\is_integer($_POST['theme_logo_height'], ['min' => 0])) : true,
'error_msg' => _s('Invalid value')
],
'theme_tone' =>
[
'validate' => in_array($_POST['theme_tone'], ['light', 'dark']),
'error_msg' => _s('Invalid theme tone')
],
'theme_main_color' =>
[
'validate' => G\check_value($_POST['theme_main_color']) ? G\is_valid_hex_color($_POST['theme_main_color']) : true,
'error_msg' => _s('Invalid theme main color')
],
'theme_top_bar_button_color' =>
[
'validate' => in_array($_POST['theme_top_bar_button_color'], CHV\getSetting('available_button_colors')),
'error_msg' => _s('Invalid theme top bar button color')
],
'theme_image_listing_sizing' =>
[
'validate' => in_array($_POST['theme_image_listing_sizing'], ['fluid', 'fixed']),
'error_msg' => _s('Invalid theme image listing size')
],
'theme_home_uids' =>
[
'validate' => !empty($_POST['theme_home_uids']) ? preg_match('/^[0-9]+(\,[0-9]+)*$/', $_POST['theme_home_uids']) : true,
'error_msg' => _s('Invalid user id')
],
'email_mode' =>
[
'validate' => in_array($_POST['email_mode'], ['smtp', 'mail']),
'error_msg' => _s('Invalid email mode')
],
'email_smtp_server_port' =>
[
'validate' => in_array($_POST['email_smtp_server_port'], [25, 80, 465, 587]),
'error_msg' => _s('Invalid SMTP port')
],
'email_smtp_server_security' =>
[
'validate' => in_array($_POST['email_smtp_server_security'], ['tls', 'ssl', 'unsecured']),
'error_msg' => _s('Invalid SMTP security')
],
'website_mode' =>
[
'validate' => in_array($_POST['website_mode'], ['community', 'personal']),
'error_msg' => _s('Invalid website mode')
],
'website_mode_personal_uid' =>
[
'validate' => $_POST['website_mode'] == 'personal' ? (G\is_integer($_POST['website_mode_personal_uid'], ['min' => 0])) : true,
'error_msg' => _s('Invalid personal mode user ID')
],
'website_mode_personal_routing' =>
[
'validate' => $_POST['website_mode'] == 'personal' ? !G\is_route_available($_POST['website_mode_personal_routing']) : true,
'error_msg' => _s('Invalid or reserved route')
],
'website_privacy_mode' =>
[
'validate' => in_array($_POST['website_privacy_mode'], ['public', 'private']),
'error_msg' => _s('Invalid website privacy mode')
],
'website_content_privacy_mode' =>
[
'validate' => in_array($_POST['website_content_privacy_mode'], ['default', 'private', 'private_but_link']),
'error_msg' => _s('Invalid website content privacy mode')
],
'homepage_style' =>
[
'validate' => in_array($_POST['homepage_style'], ['landing', 'split', 'route_explore']),
'error_msg' => _s('Invalid homepage style')
],
'homepage_cta_color' =>
[
'validate' => in_array($_POST['homepage_cta_color'], CHV\getSetting('available_button_colors')),
'error_msg' => _s('Invalid homepage call to action button color')
],
'homepage_cta_fn' =>
[
'validate' => $_POST['homepage_style'] == 'route_explore' ? true : in_array($_POST['homepage_cta_fn'], ['cta-upload', 'cta-link']),
'error_msg' => _s('Invalid homepage call to action functionality')
],
// PAGES
'page_title' =>
[
'validate' => !empty($_POST['page_title']),
'error_msg' => _s('Invalid title')
],
'page_is_active' =>
[
'validate' => in_array($_POST['page_is_active'], ['1', '0']),
'error_msg' => _s('Invalid status')
],
'page_type' =>
[
'validate' => in_array($_POST['page_type'], ['internal', 'link']),
'error_msg' => _s('Invalid type')
],
'page_is_link_visible' =>
[
'validate' => $_POST['page_type'] == 'internal' ? in_array($_POST['page_is_link_visible'], ['1', '0']) : true,
'error_msg' => _s('Invalid visibility')
],
'page_internal' =>
[
'validate' => ($_POST['page_type'] == 'internal' && $_POST['page_internal']) ? in_array($_POST['page_internal'], ['tos', 'privacy', 'contact']) : true,
'error_msg' => _s('Invalid internal type')
],
'page_attr_target' =>
[
'validate' => in_array($_POST['page_attr_target'], ['_self', '_blank']),
'error_msg' => _s('Invalid target attribute')
],
'page_attr_rel' =>
[
'validate' => !empty($_POST['page_attr_rel']) ? preg_match('/^[\w\s\-]+$/', $_POST['page_attr_rel']) : true,
'error_msg' => _s('Invalid rel attribute')
],
'page_icon' =>
[
'validate' => !empty($_POST['page_icon']) ? preg_match('/^[\w\s\-]+$/', $_POST['page_icon']) : true,
'error_msg' => _s('Invalid icon')
],
'page_url_key' =>
[
'validate' => $_POST['page_type'] == 'internal' ? preg_match('/^[\w\-\_\/]+$/', $_POST['page_url_key']) : true,
'error_msg' => _s('Invalid URL key')
],
'page_file_path' =>
[
'validate' => $_POST['page_type'] == 'internal' ? preg_match('/^[\w\-\_\/]+\.php$/', $_POST['page_file_path']) : true,
'error_msg' => _s('Invalid file path')
],
'page_link_url' =>
[
'validate' => $_POST['page_type'] == 'link' ? filter_var($_POST['page_link_url'], FILTER_VALIDATE_URL) : true,
'error_msg' => _s('Invalid link URL')
],
'user_minimum_age' =>
[
'validate' => $_POST['user_minimum_age'] !== '' ? G\is_integer($_POST['user_minimum_age'], ['min' => 0]) : true,
'error_msg' => _s('Invalid user minimum age')
],
'route_image' =>
[
'validate' => preg_match('/^[\w\d\-\_]+$/', $_POST['route_image']),
'error_msg' => _s('Only alphanumeric, hyphen and underscore characters are allowed')
],
'route_album' =>
[
'validate' => preg_match('/^[\w\d\-\_]+$/', $_POST['route_album']),
'error_msg' => _s('Only alphanumeric, hyphen and underscore characters are allowed')
],
'image_load_max_filesize_mb' =>
[
'validate' => $_POST['image_load_max_filesize_mb'] !== '' ? G\is_integer($_POST['image_load_max_filesize_mb'], ['min' => 0]) : true,
'error_msg' => _s('Invalid value: %s', $_POST['image_load_max_filesize_mb'])
],
'upload_max_image_width' =>
[
'validate' => G\is_integer($_POST['upload_max_image_width'], ['min' => 0]),
'error_msg' => _s('Invalid value: %s', $_POST['upload_max_image_width'])
],
'upload_max_image_height' =>
[
'validate' => G\is_integer($_POST['upload_max_image_height'], ['min' => 0]),
'error_msg' => _s('Invalid value: %s', $_POST['upload_max_image_height'])
],
'auto_delete_guest_uploads' =>
[
'validate' => $_POST['auto_delete_guest_uploads'] !== null && array_key_exists($_POST['auto_delete_guest_uploads'], CHV\Image::getAvailableExpirations()),
'error_msg' => _s('Invalid value: %s', $_POST['auto_delete_guest_uploads'])
],
'sdk_pup_url' =>
[
'validate' => $_POST['sdk_pup_url'] ? filter_var($_POST['sdk_pup_url'], FILTER_VALIDATE_URL) : true,
'error_msg' => _s('Invalid URL')
],
];
// Detect funny stuff
if (isset($_POST['route_image'], $_POST['route_album']) && $_POST['route_image'] == $_POST['route_album']) {
$validations['route_image'] = [
'validate' => false,
'error_msg' => _s("Routes can't be the same")
];
$validations['route_album'] = $validations['route_image'];
}
// Validate image path
if ($_POST['upload_image_path']) {
$safe_upload_image_path = rtrim(G\sanitize_relative_path($_POST['upload_image_path']), '/');
$image_path = G_ROOT_PATH . $_POST['upload_image_path'];
if (!file_exists($image_path)) {
$validations['upload_image_path'] = [
'validate' => false,
'error_msg' => _s('Invalid upload image path')
];
}
}
// Validate CTA url
if ($_POST['homepage_style'] !== 'route_explore' and $_POST['homepage_cta_fn'] == 'cta-link' and !G\is_url($_POST['homepage_cta_fn_extra'])) {
if (!empty($_POST['homepage_cta_fn_extra'])) {
// Sanitize the fn_extra
$_POST['homepage_cta_fn_extra'] = rtrim(G\sanitize_relative_path($_POST['homepage_cta_fn_extra']), '/');
$_POST['homepage_cta_fn_extra'] = G\get_regex_match(CHV\getSetting('routing_regex_path'), '#', $_POST['homepage_cta_fn_extra'], 1);
} else {
$validations['homepage_cta_fn_extra'] = [
'validate' => false,
'error_msg' => _s('Invalid call to action URL')
];
}
}
// Validate max size
foreach (['upload_max_filesize_mb', 'upload_max_filesize_mb_guest', 'user_image_avatar_max_filesize_mb', 'user_image_background_max_filesize_mb'] as $k) {
unset($error_max_filesize);
if (isset($_POST[$k])) {
if (!is_numeric($_POST[$k]) or $_POST[$k] == 0) {
$error_max_filesize = _s('Invalid value');
} else {
if (G\get_bytes($_POST[$k] . 'MB') > CHV\Settings::get('true_upload_max_filesize')) {
$error_max_filesize = _s('Max. allowed %s', G\format_bytes(CHV\Settings::get('true_upload_max_filesize')));
}
}
$validations[$k] = ['validate' => isset($error_max_filesize) ? false : true, 'error_msg' => $error_max_filesize];
}
}
// Validate virtual routes
$validate_routes = [];
foreach (['image', 'album'] as $k) {
$route = 'route_' . $k;
if (file_exists(G_ROOT_PATH . $_POST[$route])) {
$validations[$route] = [
'validate' => false,
'error_msg' => _s("Can't map %m to an existing folder (%f)", ['%m' => '/' . $k, '%f' => '/' . $_POST[$route]])
];
continue;
}
if (isset($_POST[$route]) && $_POST[$route] !== $k && $validations[$route]['validate']) {
if (G\is_route_available($_POST[$route])) {
$validations[$route] = [
'validate' => false,
'error_msg' => _s("Can't map %m to an existing route (%r)", ['%m' => '/' . $k, '%r' => '/' . $_POST[$route]])
];
} else {
// Check username collision
$user_exists = CHV\User::getSingle($_POST[$route], 'username', false);
if ($user_exists) {
$validations[$route] = [
'validate' => false,
'error_msg' => _s("Can't map %m to %r (username collision)", ['%m' => '/' . $k, '%r' => '/' . $_POST[$route]])
];
}
}
}
}
// 1. No pueden mappear una ruta ya existente, excepto self (no puden mapear /dashboard, pero si /image)
// 2. No pueden mapear a un username
// Handle disabled image formats
if ($_POST['image_format_enable'] && is_array($_POST['image_format_enable'])) {
// Validate each entry
$image_format_enable = [];
foreach ($_POST['image_format_enable'] as $v) {
if (in_array($v, CHV\Upload::getAvailableImageFormats())) {
$image_format_enable[] = $v;
}
}
$_POST['upload_enabled_image_formats'] = implode(',', $image_format_enable);
}
// Handle disabled languages
if ($_POST['languages_enable'] && is_array($_POST['languages_enable'])) {
// Push default language
if (!in_array($_POST['default_language'], $_POST['languages_enable'])) {
$_POST['languages_enable'][] = $_POST['default_language'];
}
$enabled_languages = [];
$disabled_languages = CHV\get_available_languages();
$_POST['languages_disable'] = [];
foreach ($_POST['languages_enable'] as $k) {
if (!array_key_exists($k, CHV\get_available_languages())) {
continue;
}
$enabled_languages[$k] = CHV\get_available_languages()[$k];
unset($disabled_languages[$k]);
}
CHV\l10n::setStatic('disabled_languages', $disabled_languages);
CHV\l10n::setStatic('enabled_languages', $enabled_languages);
unset($_POST['languages_enable']);
foreach ($disabled_languages as $k => $v) {
$_POST['languages_disable'][] = $k;
}
$_POST['languages_disable'] = implode(',', $_POST['languages_disable']);
}
// Handle personal mode change
if ($_POST['website_mode'] == 'personal' and $_POST['website_mode_personal_routing']) {
if ($logged_user['id'] == $_POST['website_mode_personal_uid']) {
$new_user_url = G\get_base_url($_POST['website_mode_personal_routing'] !== '/' ? $_POST['website_mode_personal_routing'] : null);
CHV\Login::setUser('url', G\get_base_url($_POST['website_mode_personal_routing'] !== '/' ? $_POST['website_mode_personal_routing'] : null));
CHV\Login::setUser('url_albums', CHV\User::getUrlAlbums(CHV\Login::getUser()['url']));
} elseif (!CHV\User::getSingle($_POST['website_mode_personal_uid'])) { // Is a valid user id anyway?
$validations['website_mode_personal_uid'] = [
'validate' => false,
'error_msg' => _s('Invalid personal mode user ID')
];
}
}
// Validate image upload
$content_image_props = [];
foreach (CHV\getSetting('homepage_cover_images') as $k => $v) {
$content_image_props[] = sprintf('homepage_cover_image_%s', $k);
}
$content_image_props = array_merge($content_image_props, ['logo_vector', 'logo_image', 'logo_vector_homepage', 'logo_image_homepage', 'favicon_image', 'watermark_image', 'consent_screen_cover_image', 'homepage_cover_image_add']);
foreach ($content_image_props as $k) {
if ($_FILES[$k]['tmp_name']) {
try {
CHV\upload_to_content_images($_FILES[$k], $k);
} catch (Exception $e) {
$validations[$k] = [
'validate' => false,
'error_msg' => $e->getMessage()
];
}
}
}
// Validate SMTP credentials
if ($_POST['email_mode'] == 'smtp') {
$email_smtp_validate = [
'email_smtp_server' => _s('Invalid SMTP server'),
'email_smtp_server_username' => _s('Invalid SMTP username'),
//'email_smtp_server_password' => _s('Invalid SMTP password')
];
foreach ($email_smtp_validate as $k => $v) {
$validations[$k] = ['validate' => $_POST[$k] ? true : false, 'error_msg' => $v];
}
$email_validate = ['email_smtp_server', 'email_smtp_server_port', 'email_smtp_server_username', /*'email_smtp_server_password',*/ 'email_smtp_server_security'];
$email_error = false;
foreach ($email_validate as $k) {
if (!$validations[$k]['validate']) {
$email_error = true;
}
}
if (!$email_error) {
try {
$mail = new Mailer(true);
$mail->SMTPAuth = true;
$mail->SMTPSecure = $_POST['email_smtp_server_security'];
$mail->SMTPAutoTLS = in_array($_POST['email_smtp_server_security'], ['ssl', 'tls']);
$mail->Username = $_POST['email_smtp_server_username'];
$mail->Password = $_POST['email_smtp_server_password'];
$mail->Host = $_POST['email_smtp_server'];
$mail->Port = $_POST['email_smtp_server_port'];
if (CHV\getSetting('error_reporting') or G\get_app_setting('debug_level') !== 0) {
$mail->SMTPDebug = 2;
$GLOBALS['SMTPDebug'] = '';
$mail->Debugoutput = function ($str) {
$GLOBALS['SMTPDebug'] .= "$str\n";
};
if (strlen($GLOBALS['SMTPDebug']) > 0) {
$GLOBALS['SMTPDebug'] = "SMTP Debug>>\n" . $GLOBALS['SMTPDebug'];
}
}
$valid_mail_credentials = $mail->SmtpConnect();
} catch (Exception $e) {
$GLOBALS['SMTPDebug'] = "SMTP Exception>>\n" . ($mail->ErrorInfo ?: $e->getMessage());
}
if (!$valid_mail_credentials) {
foreach ($email_smtp_validate as $k => $v) {
$validations[$k]['validate'] = false;
}
}
}
}
// Validate social networks
$social_validate = [
'facebook' => ['facebook_app_id', 'facebook_app_secret'],
'twitter' => ['twitter_api_key', 'twitter_api_secret'],
'google' => ['google_client_id', 'google_client_secret'],
];
foreach ($social_validate as $k => $v) {
if ($_POST[$k] == 1) {
foreach ($v as $vv) {
$validations[$vv] = ['validate' => $_POST[$vv] ? true : false];
}
}
}
// Validate Akismet
if ($_POST['akismet'] == 1) {
$akismet = new Akismet($_POST['akismet_api_key'], G\get_base_url());
$validations['akismet_api_key'] = [
'validate' => $akismet->verifyKey(),
'error_msg' => _s('Invalid key')
];
}
// Validate CDN
if ($_POST['cdn'] == 1) {
$cdn_url = trim($_POST['cdn_url'], '/') . '/';
if (!G\is_url($cdn_url)) {
$cdn_url = 'http://' . $cdn_url;
}
if (!G\is_url($cdn_url) and !G\is_valid_url($cdn_url)) {
$validations['cdn_url'] = [
'validate' => false,
'error_msg' => _s('Invalid URL')
];
} else {
$_POST['cdn_url'] = $cdn_url;
$handler::updateVar('safe_post', ['cdn_url' => $cdn_url]);
}
}
// Validate recaptcha
if ($_POST['recaptcha'] == 1) {
foreach (['recaptcha_public_key', 'recaptcha_private_key'] as $v) {
$validations[$v] = ['validate' => $_POST[$v] ? true : false];
}
}
// Run the thing
foreach ($_POST + $_FILES as $k => $v) {
if (isset($validations[$k]) and !$validations[$k]['validate']) {
$input_errors[$k] = $validations[$k]['error_msg'] ?: _s('Invalid value');
}
}
// Test target page path and URL key
if ($handler->request[1] == 'pages' and in_array($handler->request[2], ['edit', 'add']) and $_POST['page_type'] == 'internal') {
if ($page) {
$try_page_db = ($page['url_key'] !== $_POST['url_key']) or ($page['file_path'] !== $_POST['page_file_path']);
} else {
$try_page_db = true;
}
if ($try_page_db) {
$db = CHV\DB::getInstance();
$db->query('SELECT * FROM ' . CHV\DB::getTable('pages') . ' WHERE page_url_key = :page_url_key OR page_file_path = :page_file_path');
$db->bind(':page_url_key', $_POST['page_url_key']);
$db->bind(':page_file_path', $_POST['page_file_path']);
$page_fetch_db = $db->fetchAll();
if ($page_fetch_db) {
foreach ($page_fetch_db as $k => $v) {
foreach ([
'page_url_key' => _s('This URL key is already being used by another page (ID %s)'),
'page_file_path' => _s('This file path is already being used by another page (ID %s)')
] as $kk => $vv) {
if ($page and $page['id'] == $v['page_id']) {
continue; // Skip on same thing
}
if (G\timing_safe_compare($v[$kk], $_POST[$kk])) {
$input_errors[$kk] = sprintf($vv, $v['page_id']);
}
}
}
}
}
}
// Input data looks fine
if (is_array($input_errors) && count($input_errors) == 0) {
if ($handler->request[1] == 'pages') {
// Try to edit / add a page
if (in_array($handler->request[2], ['edit', 'add']) and $_POST['page_type'] == 'internal') {
// Try to write page source code
$page_write_contents = (array_key_exists('page_code', $_POST)) ? (!empty($_POST['page_code']) ? html_entity_decode($_POST['page_code']) : null) : null;
try {
CHV\Page::writePage(['file_path' => $_POST['page_file_path'], 'contents' => $page_write_contents]);
// Delete old file if we are editing, file_path isn't null (default) and file path changed
if ($handler->request[2] == 'edit' and !is_null($page['file_path']) and !G\timing_safe_compare($page['file_path'], $_POST['page_file_path'])) {
unlink(CHV\Page::getPath($page['file_path']));
}
} catch (Exception $e) {
$input_errors['page_code'] = _s("Can't save page contents: %s.", $e->getMessage());
}
}
// Nullify needed for 5.6
// Go home 5.6, you are drunk.
if (isset($_POST['page_internal']) && $_POST['page_internal'] == '') {
$_POST['page_internal'] = null;
}
$page_fields = CHV\Page::getFields();
$page_values = [];
foreach ($page_fields as $v) {
$_post = $_POST['page_' . $v];
if ($handler->request[2] == 'edit') {
if (G\timing_safe_compare($page[$v], $_post)) {
continue;
} // Skip not updated values
}
$page_values[$v] = $_post;
}
if ($page_values) {
if ($handler->request[2] == 'add') {
$page_inserted = CHV\Page::insert($page_values);
$_SESSION['dashboard_page_added'] = ['id' => $page_inserted];
G\redirect(G\get_base_url('dashboard/settings/pages/edit/' . $page_inserted));
} else {
CHV\Page::update($page['id'], $page_values);
$is_changed = true;
$pages_sort_changed = false;
foreach (['sort_display', 'is_active', 'is_link_visible'] as $k) {
if ($page[$k] !== $page_values[$k]) {
$pages_sort_changed = true;
break;
}
}
// Update 'page' var
$page = array_merge($handler::getVar('page'), $page_values);
CHV\Page::fill($page);
$handler::updateVar('page', $page);
// Update pages_link_visible (menu)
$pages_link_visible = $handler::getVar('pages_link_visible');
$pages_link_visible[$page['id']] = $page; // Either update or append
if (!$page['is_active'] or !$page['is_link_visible']) {
unset($pages_link_visible[$page['id']]);
} elseif ($pages_sort_changed) { // Need to update the sort display?
uasort($pages_link_visible, function ($a, $b) {
return $a['sort_display'] - $b['sort_display'];
});
}
$handler::setVar('pages_link_visible', $pages_link_visible);
}
}
} else { // Settings
$update_settings = [];
foreach (CHV\getSettings() as $k => $v) {
if (isset($_POST[$k]) && $_POST[$k] != (is_bool(CHV\getSetting($k)) ? (CHV\getSetting($k) ? 1 : 0) : CHV\getSetting($k))) {
$update_settings[$k] = $_POST[$k];
}
}
if (!empty($update_settings)) {
$update = CHV\Settings::update($update_settings);
if ($update) {
$is_changed = true;
$reset_notices = false;
$settings_to_vars = [
'website_doctitle' => 'doctitle',
'website_description' => 'meta_description',
];
foreach ($update_settings as $k => $v) {
if ($k == 'maintenance') {
$reset_notices = true;
}
if (array_key_exists($k, $settings_to_vars)) {
$handler::setVar($settings_to_vars[$k], CHV\getSetting($k));
}
}
if ($reset_notices) {
$system_notices = CHV\getSystemNotices();
$handler::setVar('system_notices', $system_notices);
}
}
}
}
} else {
$is_error = true;
}
}
break;
case 'images':
case 'albums':
case 'users':
$tabs = CHV\Listing::getTabs([
'listing' => $doing,
'tools' => true,
]);
$type = $doing;
$current = false;
foreach ($tabs as $k => $v) {
if ($v['current']) {
$current = $k;
}
$tabs[$k]['type'] = $type;
$tabs[$k]['url'] = G\get_base_url('dashboard/' . $type . '/?' . $tabs[$k]['params']);
}
if (!$current) {
$current = 0;
$tabs[0]['current'] = true;
}
// Use CHV magic params
$list_params = CHV\Listing::getParams();
$handler::setVar('list_params', $list_params);
parse_str($tabs[$current]['params'], $tab_params);
preg_match('/(.*)\_(asc|desc)/', !empty($_REQUEST['sort']) ? $_REQUEST['sort'] : $tab_params['sort'], $sort_matches);
$list_params['sort'] = array_slice($sort_matches, 1);
$list = new CHV\Listing;
$list->setType($type); // images | users | albums
$list->setReverse($list_params['reverse']);
$list->setSeek($list_params['seek']);
$list->setOffset($list_params['offset']);
$list->setLimit($list_params['limit']); // how many results?
$list->setItemsPerPage($list_params['items_per_page']); // must
$list->setSortType($list_params['sort'][0]); // date | size | views
$list->setSortOrder($list_params['sort'][1]); // asc | desc
$list->setRequester($logged_user);
$list->output_tpl = $type;
$list->exec();
break;
}
$pre_doctitle = [_s('Dashboard')];
if ($doing != 'stats') {
$pre_doctitle[] = $sub_routes[$doing];
if ($doing == 'settings') {
reset($settings_sections);
$firstKey = key($settings_sections);
$dashSettingsProp = $handler::getVar('settings');
if ($dashSettingsProp['key'] != $firstKey) {
$pre_doctitle[] = $dashSettingsProp['label'];
}
}
}
$handler::setVar('pre_doctitle', implode(' - ', $pre_doctitle));
$handler::setCond('error', $is_error);
$handler::setCond('changed', $is_changed);
$handler::setVar('error_message', $error_message);
$handler::setVar('input_errors', $input_errors);
$handler::setVar('changed_message', $changed_message);
if ($tabs) {
$handler::setVar('sub_tabs', $tabs);
}
if ($list) {
$handler::setVar('list', $list);
}
} catch (Exception $e) {
G\exception_to_error($e);
}
};