artabro/wire/core/admin.php
2024-08-27 11:35:37 +02:00

241 lines
7.6 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php namespace ProcessWire;
/**
* Controller for ProcessWire Admin
*
* This file is designed for inclusion by /site/templates/admin.php template and all the variables
* it references are from your template namespace.
*
* Copyright 2022 by Ryan Cramer
*
* @var Config $config
* @var User $user
* @var Modules $modules
* @var Pages $pages
* @var Page $page
* @var ProcessWire $wire
* @var WireInput $input
* @var Sanitizer $sanitizer
* @var Session $session
* @var Notices $notices
* @var AdminTheme $adminTheme
*
*
*/
if(!defined("PROCESSWIRE")) die("This file may not be accessed directly.");
header("X-Frame-Options: SAMEORIGIN");
/**
* Ensures a modal GET variable is retained through redirects, when appropriate
*
* @param HookEvent $event
*
*/
function _hookSessionRedirectModal(HookEvent $event) {
$url = $event->arguments(0);
if(strpos($url, 'modal=1') === false && strpos($url, '://') === false) {
$url .= (strpos($url, '?') === false ? '?' : '&') . 'modal=1';
$event->arguments(0, $url);
}
}
/**
* Check if the current HTTP host is recognized and generate error if not
*
* @param Config $config
*
*/
function _checkForHttpHostError(Config $config) {
$valid = false;
$httpHost = strtolower($config->httpHost);
if(isset($_SERVER['HTTP_HOST']) && $httpHost === strtolower($_SERVER['HTTP_HOST'])) {
$valid = true;
} else if(isset($_SERVER['SERVER_NAME']) && $httpHost === strtolower($_SERVER['SERVER_NAME'])) {
$valid = true;
} else if(in_array($httpHost, $config->httpHosts)) {
$valid = true;
}
if(!$valid) $config->error(
__('Unrecognized HTTP host:') . "'" .
htmlentities($_SERVER['HTTP_HOST'], ENT_QUOTES, 'UTF-8') . "' - " .
__('Please update your $config->httpHosts setting in /site/config.php') . " - " .
"<a target='_blank' href='https://processwire.com/api/variables/config/#httphosts'>" . __('read more') . "</a>",
Notice::allowMarkup
);
}
/**
* Check if two factor authentication is being required and display warning with link to configure
*
* @param Session $session
*
*/
function _checkForTwoFactorAuth(Session $session) {
$tfaUrl = $session->getFor('_user', 'requireTfa'); // contains URL to configure TFA
if(!$tfaUrl || strpos($tfaUrl, $session->wire('page')->url()) === 0) return;
$sanitizer = $session->wire('sanitizer');
$session->wire('user')->warning(
'<strong>' . $sanitizer->entities1(__('Action required')) . '</strong> ' .
wireIconMarkup('angle-right') . ' ' .
"<a href='$tfaUrl'>" . $sanitizer->entities1(__('Enable two-factor authentication')) . " </a>",
Notice::allowMarkup
);
}
/**
* Check if POST request exceeds PHPs max_input_vars
*
* @param WireInput $input
*
*/
function _checkForMaxInputVars(WireInput $input) {
$max = (int) ini_get('max_input_vars');
if($max && count($_POST) >= $max) {
$input->error(sprintf(__('You have reached PHPs “max_input_vars” setting of %d — please increase it.'), $max));
}
}
// fallback theme if one not already present
if(empty($adminTheme)) {
$adminTheme = $modules->get($config->defaultAdminTheme ? $config->defaultAdminTheme : 'AdminThemeUikit');
if(empty($adminTheme)) $adminTheme = $modules->get('AdminThemeUikit');
if($adminTheme) $wire->wire('adminTheme', $adminTheme);
}
// notify superuser if there is an http host error
if($user->isSuperuser()) _checkForHttpHostError($config);
// ensure core jQuery modules are loaded before others
$modules->get("JqueryCore");
$modules->get("JqueryUI");
// tell ProcessWire that any pages loaded from this point forward should have their outputFormatting turned off
$pages->setOutputFormatting(false);
// setup breadcrumbs to current page, and the Process may modify, add to or replace them as needed
$breadcrumbs = $wire->wire('breadcrumbs', new Breadcrumbs());
foreach($page->parents() as $p) {
if($p->id > 1) $breadcrumbs->add(new Breadcrumb($p->url, $p->get("title|name")));
}
$controller = null;
$content = '';
$ajax = $config->ajax;
$modal = $input->get('modal') ? true : false;
$demo = $config->demo;
// enable modules to output their own ajax responses if they choose to
if($ajax) ob_start();
if($page->process && $page->process != 'ProcessPageView') {
try {
if($demo && $page->process != 'ProcessLogin') {
if(count($_POST)) $wire->error("Features that use POST variables are disabled in this demo");
foreach($_POST as $k => $v) unset($_POST[$k]);
foreach($_FILES as $k => $v) unset($_FILES[$k]);
$input->post->removeAll();
} else if($input->requestMethod('POST') && $user->isLoggedin() && $user->hasPermission('page-edit')) {
_checkForMaxInputVars($input);
}
$controller = new ProcessController();
$wire->wire($controller);
$controller->setProcessName($page->process);
$initFile = $config->paths->adminTemplates . 'init.php';
if(is_file($initFile)) {
if(strpos($initFile, $config->paths->site) === 0) {
// admin themes in /site/modules/ may be compiled
$initFile = $wire->files->compile($initFile);
}
/** @noinspection PhpIncludeInspection */
include_once($initFile);
}
if($modal) $session->addHookBefore('redirect', null, '_hookSessionRedirectModal');
$content = $controller->execute();
$process = $controller->wire('process');
if(!$ajax && !$modal && !$demo && $user->isLoggedin()) _checkForTwoFactorAuth($session);
if($process) {} // ignore
} catch(Wire404Exception $e) {
$wire->setStatusFailed($e, "404 from $page->process", $page);
$wire->error($e->getMessage());
} catch(WirePermissionException $e) {
$wire->setStatusFailed($e, "Permission error from $page->process", $page);
if($controller && $controller->isAjax()) {
$content = $controller->jsonMessage($e->getMessage(), true);
} else if($user->isGuest()) {
/** @var Process $process */
$process = $modules->get("ProcessLogin");
$content = $process->execute();
} else {
$wire->error($e->getMessage());
}
} catch(\Exception $e) {
$wire->setStatusFailed($e, "Error from $page->process", $page);
$msg = $e->getMessage();
if($config->debug) {
$msg = $sanitizer->entities($msg);
$msg .= "<pre>\n" .
__('DEBUG MODE BACKTRACE') . " " .
"(\$config->debug == true):\n" .
$sanitizer->entities($e->getTraceAsString()) .
"</pre>";
$wire->error("$page->process: $msg", Notice::allowMarkup);
} else {
$wire->error($msg);
}
if($controller && $controller->isAjax()) {
$content = $controller->jsonMessage($e->getMessage(), true);
$wire->trackException($e, false);
} else {
$wire->trackException($e, true);
}
}
} else {
$content = '<p>' . __('This page has no process assigned.') . '</p>';
}
if($ajax) {
// enable modules to output their own ajax responses if they choose to
if(!$content) $content = ob_get_contents();
ob_end_clean();
}
// config properties that should be mirrored to ProcessWire.config.property in JS
$config->js(array('httpHost', 'httpHosts', 'https'), true);
if($controller && $controller->isAjax()) {
if(empty($content) && count($notices)) {
$notice = $notices->last(); /** @var Notice $notice */
$content = $controller->jsonMessage($notice->text, false, $notice->flags & Notice::allowMarkup);
}
echo $content;
} else {
if(!strlen($content)) $content = '<p>' . __('The process returned no content.') . '</p>';
if($adminTheme) {
$adminThemeFile = $adminTheme->path() . 'default.php';
} else {
$adminThemeFile = $config->paths->adminTemplates . 'default.php';
}
if(strpos($adminThemeFile, $config->paths->site) === 0) {
// @todo determine if compilation needed
$adminThemeFile = $wire->files->compile($adminThemeFile);
}
/** @noinspection PhpIncludeInspection */
require($adminThemeFile);
$session->removeNotices();
if($content) {} // ignore
}