You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

791 lines
30 KiB

<?php
/**
* brings Smarty functionality into Tiki
*
* this script may only be included, it will die if called directly.
*
* @package TikiWiki
* @subpackage lib\init
* @copyright (c) Copyright by authors of the Tiki Wiki CMS Groupware Project. All Rights Reserved. See copyright.txt for details and a complete list of authors.
* @licence Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
*/
// $Id$
// die if called directly.
if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) {
header('location: index.php');
exit;
}
require_once __DIR__ . '/../setup/third_party.php';
/**
* extends Smarty_Security
* @package TikiWiki\lib\init
*/
class Tiki_Security_Policy extends Smarty_Security
{
/**
* needs a proper description
* @var array $secure_dir
*/
public $trusted_uri = [];
public $secure_dir = [];
/**
* needs a proper description
* @param Smarty $smarty
*/
public function __construct($smarty)
{
if (class_exists("TikiLib")) {
$tikilib = TikiLib::lib('tiki');
// modlib defines zone_is_empty which must exist before smarty initializes to fix bug with smarty autoloader after version 3.1.21
TikiLib::lib('mod');
}
parent::__construct($smarty);
//With phpunit and command line these don't exist yet for some reason
if (isset($tikilib) && method_exists($tikilib, "get_preference")) {
global $url_host;
$this->trusted_uri[] = '#' . preg_quote("http://$url_host", '$#') . '#';
$this->trusted_uri[] = '#' . preg_quote("https://$url_host", '$#') . '#';
$functions = array_filter($tikilib->get_preference('smarty_security_functions', [], true));
$modifiers = array_filter($tikilib->get_preference('smarty_security_modifiers', [], true));
$dirs = array_filter($tikilib->get_preference('smarty_security_dirs', [], true));
$cdns = preg_split('/\s+/', $tikilib->get_preference('tiki_cdn', ''));
$cdns_ssl = preg_split('/\s+/', $tikilib->get_preference('tiki_cdn_ssl', ''));
$cdn_uri = array_filter(array_merge($cdns, $cdns_ssl));
foreach ($cdn_uri as $uri) {
$this->trusted_uri[] = '#' . preg_quote($uri) . '$#';
}
} else {
$functions = [];
$modifiers = [];
$dirs = [];
}
// Add defaults
$this->php_modifiers = array_merge([
'addslashes',
'array_filter',
'array_reverse',
'count',
'escape',
'explode',
'htmlentities',
'implode',
'is_array',
'json_decode',
'json_encode',
'md5',
'nl2br',
'preg_split',
'strip_tags',
'stristr',
'strpos',
'substr',
'tra',
'trim',
'ucfirst',
'ucwords',
'urlencode',
'var_dump',
'strstr',
], $modifiers);
$this->php_functions = array_merge(['isset',
'array', // not needed? use {$value = []}
'array_rand',
'array_key_exists',
'basename',
'count',
'empty',
'ereg', // deprecated and removed in php7+ use preg functions instead
'in_array',
'is_array',
'is_numeric',
'json_encode',
'min',
'max',
'nl2br',
'preg_match',
'preg_match_all',
'preg_replace',
'sizeof',
'strlen',
'stristr',
'strpos',
'strstr',
'str_replace',
'strtolower',
'time',
'tra',
'trim',
'zone_is_empty',
], $functions);
$this->secure_dir = array_merge($this->secure_dir, $dirs);
}
}
/**
* extends Smarty.
*
* Centralizing overrides here will avoid problems when upgrading to newer versions of the Smarty library.
* @package TikiWiki\lib\init
*/
class Smarty_Tiki extends Smarty
{
/**
* needs a proper description
* @var array|null
*/
public $url_overriding_prefix_stack = null;
/**
* needs a proper description
* @var null
*/
public $url_overriding_prefix = null;
/**
* needs a proper description
* @var null|string
*/
public $main_template_dir = null;
/**
* needs a proper description
*/
public function __construct()
{
parent::__construct();
global $prefs;
$this->initializePaths();
$this->setConfigDir(null);
if (! isset($prefs['smarty_compilation'])) {
$prefs['smarty_compilation'] = '';
}
$this->compile_check = ( $prefs['smarty_compilation'] != 'never' );
$this->force_compile = ( $prefs['smarty_compilation'] == 'always' );
$this->assign('app_name', 'Tiki');
if (! isset($prefs['smarty_security']) || $prefs['smarty_security'] == 'y') {
$this->enableSecurity('Tiki_Security_Policy');
} else {
$this->disableSecurity();
}
$this->use_sub_dirs = false;
$this->url_overriding_prefix_stack = [];
if (! empty($prefs['smarty_notice_reporting']) and $prefs['smarty_notice_reporting'] === 'y') {
$this->error_reporting = E_ALL;
} else {
$this->error_reporting = E_ALL ^ E_NOTICE;
}
if (! empty($prefs['smarty_cache_perms'])) {
$this->_file_perms = (int) $prefs['smarty_cache_perms'];
}
$this->loadFilter('pre', 'tr');
$this->loadFilter('pre', 'jq');
include_once(__DIR__ . '/../smarty_tiki/resource.tplwiki.php');
$this->registerResource('tplwiki', new Smarty_Resource_Tplwiki());
include_once(__DIR__ . '/../smarty_tiki/resource.wiki.php');
$this->registerResource('tplwiki', new Smarty_Resource_Wiki());
global $prefs;
// Assign the prefs array in smarty, by reference
$this->assignByRef('prefs', $prefs);
if (! empty($prefs['log_tpl']) && $prefs['log_tpl'] === 'y') {
$this->loadFilter('pre', 'log_tpl');
}
if (! empty($prefs['feature_sefurl_filter']) && $prefs['feature_sefurl_filter'] === 'y') {
require_once('tiki-sefurl.php');
$this->registerFilter('output', 'filter_out_sefurl');
}
// restore tiki's own escape function
$this->loadPlugin('smarty_modifier_escape');
$this->registerPlugin('modifier', 'escape', 'smarty_modifier_escape');
}
/**
* Fetch templates from plugins (smarty plugins, wiki plugins, modules, ...) that may need to :
* - temporarily override some smarty vars,
* - prefix their self_link / button / query URL arguments
*
* @param $_smarty_tpl_file
* @param null $override_vars
*
* @return string
*/
public function plugin_fetch($_smarty_tpl_file, &$override_vars = null)
{
$smarty_orig_values = [];
if (is_array($override_vars)) {
foreach ($override_vars as $k => $v) {
$smarty_orig_values[ $k ] = $this->getTemplateVars($k);
$this->assignByRef($k, $override_vars[ $k ]);
}
}
$return = $this->fetch($_smarty_tpl_file);
// Restore original values of smarty variables
if (count($smarty_orig_values) > 0) {
foreach ($smarty_orig_values as $k => $v) {
$this->assignByRef($k, $smarty_orig_values[ $k ]);
}
}
unset($smarty_orig_values);
return $return;
}
/**
* needs a proper description
* @param null $_smarty_tpl_file
* @param null $_smarty_cache_id
* @param null $_smarty_compile_id
* @param null $parent
* @param bool $_smarty_display
* @param bool $merge_tpl_vars
* @param bool $no_output_filter
* @return string
*/
public function fetch($_smarty_tpl_file = null, $_smarty_cache_id = null, $_smarty_compile_id = null, $parent = null, $_smarty_display = false, $merge_tpl_vars = true, $no_output_filter = false)
{
if (strpos($_smarty_tpl_file, 'extends:') === 0) {
// temporarily disable extends_recursion which restores smarty < 3.1.28 behaviour
// see note at vendor_bundled/vendor/smarty/smarty/libs/Smarty.class.php:296 for more
$this->extends_recursion = false;
}
$this->refreshLanguage();
$this->assign_layout_sections($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent);
$_smarty_tpl_file = $this->get_filename($_smarty_tpl_file);
if ($_smarty_display) {
$html = parent::display($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent);
} else {
$html = parent::fetch($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent);
}
if (! $this->extends_recursion) {
$this->extends_recursion = true;
}
return $html;
}
/**
* Clears the value of an assigned variable
* @param $var mixed
* @return Smarty_Internal_Data
*/
public function clear_assign($var)
{
return parent::clearAssign($var);
}
/**
* This is used to assign() values to the templates by reference instead of making a copy.
* @param $var string
* @param $value mixed
* @return Smarty_Internal_Data
*/
public function assign_by_ref($var, &$value)
{
return parent::assignByRef($var, $value);
}
/**
* fetch in a specific language without theme consideration
* @param $lg
* @param $_smarty_tpl_file
* @param null $_smarty_cache_id
* @param null $_smarty_compile_id
* @param bool $_smarty_display
* @return mixed
*/
public function fetchLang($lg, $_smarty_tpl_file, $_smarty_cache_id = null, $_smarty_compile_id = null)
{
global $prefs;
$_smarty_tpl_file = $this->get_filename($_smarty_tpl_file);
$lgSave = $prefs['language'];
$prefs['language'] = $lg;
$this->refreshLanguage();
$res = parent::fetch($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id);
$prefs['language'] = $lgSave; // Restore the language of the user triggering the notification
$this->refreshLanguage();
return preg_replace("/^[ \t]*/", '', $res);
}
/**
* needs a proper description
* @param null $resource_name
* @param null $cache_id
* @param null $compile_id
* @param null $parent
* @param string $content_type
* @return Purified|void
*/
public function display($resource_name = null, $cache_id = null, $compile_id = null, $parent = null, $content_type = 'text/html; charset=utf-8')
{
global $prefs;
if (! empty($prefs['feature_htmlpurifier_output']) and $prefs['feature_htmlpurifier_output'] == 'y') {
static $loaded = false;
static $purifier = null;
if (! $loaded) {
require_once('lib/htmlpurifier_tiki/HTMLPurifier.tiki.php');
$config = getHTMLPurifierTikiConfig();
$purifier = new HTMLPurifier($config);
$loaded = true;
}
}
/**
* Add security headers. By default there headers are not sent.
* To change go to admin > security > site access
*/
if (! headers_sent()) {
if (! isset($prefs['http_header_frame_options'])) {
$frame = false;
} else {
$frame = $prefs['http_header_frame_options'];
}
if (! isset($prefs['http_header_xss_protection'])) {
$xss = false; // prevent smarty E_NOTICE
} else {
$xss = $prefs['http_header_xss_protection'];
}
if (! isset($prefs['http_header_content_type_options'])) {
$content_type_options = false; // prevent smarty E_NOTICE
} else {
$content_type_options = $prefs['http_header_content_type_options'];
}
if (! isset($prefs['http_header_content_security_policy'])) {
$content_security_policy = false; // prevent smarty E_NOTICE
} else {
$content_security_policy = $prefs['http_header_content_security_policy'];
}
if (! isset($prefs['http_header_strict_transport_security'])) {
$strict_transport_security = false; // prevent smarty E_NOTICE
} else {
$strict_transport_security = $prefs['http_header_strict_transport_security'];
}
if (! isset($prefs['http_header_public_key_pins'])) {
$public_key_pins = false; // prevent smarty E_NOTICE
} else {
$public_key_pins = $prefs['http_header_public_key_pins'];
}
if ($frame == 'y') {
$header_value = $prefs['http_header_frame_options_value'];
header('X-Frame-Options: ' . $header_value);
}
if ($xss == 'y') {
$header_value = $prefs['http_header_xss_protection_value'];
header('X-XSS-Protection: ' . $header_value);
}
if ($content_type_options == 'y') {
header('X-Content-Type-Options: nosniff');
}
if ($content_security_policy == 'y') {
$header_value = $prefs['http_header_content_security_policy_value'];
header('Content-Security-Policy: ' . $header_value);
}
if ($strict_transport_security == 'y') {
$header_value = $prefs['http_header_strict_transport_security_value'];
header('Strict-Transport-Security: ' . $header_value);
}
if ($public_key_pins == 'y') {
$header_value = $prefs['http_header_public_key_pins_value'];
header('Public-Key-Pins: ' . $header_value);
}
}
/**
* By default, display is used with text/html content in UTF-8 encoding
* If you want to output other data from smarty,
* - either use fetch() / fetchLang()
* - or set $content_type to '' (empty string) or another content type.
*/
if ($content_type != '' && ! headers_sent()) {
header('Content-Type: ' . $content_type);
}
if (function_exists('current_object') && $obj = current_object()) {
$attributes = TikiLib::lib('attribute')->get_attributes($obj['type'], $obj['object']);
if (isset($attributes['tiki.object.layout'])) {
$prefs['site_layout'] = $attributes['tiki.object.layout'];
}
}
$this->refreshLanguage();
TikiLib::events()->trigger('tiki.process.render', []);
$this->assign_layout_sections($resource_name, $cache_id, $compile_id, $parent);
if (! empty($prefs['feature_htmlpurifier_output']) and $prefs['feature_htmlpurifier_output'] == 'y') {
return $purifier->purify(parent::display($resource_name, $cache_id, $compile_id));
} else {
return parent::display($resource_name, $cache_id, $compile_id);
}
}
/**
* Since Smarty 3.1.23, display no longer calls fetch function, so we need to have this Tiki layout section assignment
* and modules loading called in both places
*/
private function assign_layout_sections($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent)
{
global $prefs;
if (($tpl = $this->getTemplateVars('mid')) && ( $_smarty_tpl_file == 'tiki.tpl' || $_smarty_tpl_file == 'tiki-print.tpl' || $_smarty_tpl_file == 'tiki_full.tpl' )) {
// Set the last mid template to be used by AJAX to simulate a 'BACK' action
if (isset($_SESSION['last_mid_template'])) {
$this->assign('last_mid_template', $_SESSION['last_mid_template']);
$this->assign('last_mid_php', $_SESSION['last_mid_php']);
}
$_SESSION['last_mid_template'] = $tpl;
$_SESSION['last_mid_php'] = $_SERVER['REQUEST_URI'];
// set the first part of the browser title for admin pages
if (null === $this->getTemplateVars('headtitle')) {
$script_name = basename($_SERVER['SCRIPT_NAME']);
if ($script_name === 'route.php' && ! empty($inclusion)) {
$script_name = $inclusion;
}
if ($script_name != 'tiki-admin.php' && strpos($script_name, 'tiki-admin') === 0) {
$str = substr($script_name, 10, strpos($script_name, '.php') - 10);
$str = ucwords(trim(str_replace('_', ' ', $str)));
$this->assign('headtitle', 'Admin ' . $str);
} elseif (strpos($script_name, 'tiki-list') === 0) {
$str = substr($script_name, 9, strpos($script_name, '.php') - 9);
$str = ucwords(trim(str_replace('_', ' ', $str)));
$this->assign('headtitle', 'List ' . $str);
} elseif (strpos($script_name, 'tiki-view') === 0) {
$str = substr($script_name, 9, strpos($script_name, '.php') - 9);
$str = ucwords(trim(str_replace('_', ' ', $str)));
$this->assign('headtitle', 'View ' . $str);
} elseif ($prefs['urlIndex'] && strpos($script_name, $prefs['urlIndex']) === 0) {
$this->assign('headtitle', tra($prefs['urlIndexBrowserTitle'])); // Viewing Custom Homepage
} else { // still not set? guess...
$str = str_replace(['tiki-', '.php', '_'], ['', '', ' '], $script_name);
$str = ucwords($str);
$this->assign('headtitle', tra($str)); // for files where no title has been set or can be reliably calculated - translators: please add comments here as you find them
}
}
if ($_smarty_tpl_file == 'tiki-print.tpl') {
$this->assign('print_page', 'y');
}
$data = $this->fetch($tpl, $_smarty_cache_id, $_smarty_compile_id, $parent);//must get the mid because the modules can overwrite smarty variables
$this->assign('mid_data', $data);
} elseif ($_smarty_tpl_file == 'confirm.tpl' || $_smarty_tpl_file == 'error.tpl' || $_smarty_tpl_file == 'error_ticket.tpl' || $_smarty_tpl_file == 'error_simple.tpl') {
if (! empty(ob_get_status())) {
ob_end_clean(); // Empty existing Output Buffer that may have been created in smarty before the call of this confirm / error* template
}
if ($prefs['feature_obzip'] == 'y') {
ob_start('ob_gzhandler');
}
}
if (! defined('TIKI_IN_INSTALLER') && ! defined('TIKI_IN_TEST')) {
require_once 'tiki-modules.php';
}
}
/**
* Returns the file path associated to the template name
* Check if the path is a template inside one of the template dirs and not an arbitrary file
* @param $template
* @return string
*/
public function get_filename($template)
{
if (substr($template, 0, 5) === 'file:') {
$template = substr($template, 5);
}
// could be extends: or something else?
if (preg_match('/^[a-z]+\:/', $template)) {
return $template;
}
//get the list of template directories
$dirs = array_merge(
$this->getTemplateDir(),
['temp/cache'],
$this->security_policy ? array_map('realpath', $this->security_policy->secure_dir) : []
);
// sanity check
if (file_exists($template)) {
$valid_path = false;
foreach ($dirs as $dir) {
$dirPath = realpath($dir);
if ($dirPath === false) {
continue;
}
if (strpos(realpath($template), $dirPath) === 0) {
$valid_path = true;
break;
}
}
if (! $valid_path) {
Feedback::error(tr("Invalid template name: %0", $template));
return "";
}
return $template;
}
//go through directories in search of the template
foreach ($dirs as $dir) {
if (file_exists($dir . $template)) {
return $dir . $template;
}
}
return "";
}
/**
* needs a proper description
* @param $url_arguments_prefix
* @param $arguments_list
*/
public function set_request_overriders($url_arguments_prefix, $arguments_list)
{
$this->url_overriding_prefix_stack[] = [ $url_arguments_prefix . '-', $arguments_list ];
$this->url_overriding_prefix =& $this->url_overriding_prefix_stack[ count($this->url_overriding_prefix_stack) - 1 ];
}
/**
* needs a proper description
* @param $url_arguments_prefix
* @param $arguments_list
*/
public function remove_request_overriders($url_arguments_prefix, $arguments_list)
{
$last_override_prefix = empty($this->url_overriding_prefix_stack) ? false : array_pop($this->url_overriding_prefix_stack);
if (! is_array($last_override_prefix) || $url_arguments_prefix . '-' != $last_override_prefix[0]) {
trigger_error('URL Overriding prefix stack is in a bad state', E_USER_ERROR);
}
$this->url_overriding_prefix =& $this->url_overriding_prefix_stack[ count($this->url_overriding_prefix_stack) - 1 ];
;
}
public function refreshLanguage()
{
global $tikidomain, $prefs;
$lang = $prefs['language'];
if (empty($lang)) {
$lang = 'default';
}
if (! empty($prefs['site_layout'])) {
$layout = $prefs['site_layout'];
} else {
$layout = 'classic';
}
$this->setCompileId("$lang-$tikidomain-$layout");
$this->initializePaths();
}
/*
Add smarty template paths from where tpl files should be loaded. This function also gets called from lib/setup/theme.php to initialize theme specific paths
*/
public function initializePaths()
{
global $prefs, $tikidomainslash, $section;
if (! $this->main_template_dir) {
// First run only
$this->main_template_dir = TIKI_PATH . '/templates/';
$this->setCompileDir(TIKI_PATH . "/temp/templates_c");
$this->setPluginsDir(
[ // the directory order must be like this to overload a plugin
TIKI_PATH . '/' . TIKI_SMARTY_DIR,
SMARTY_DIR . 'plugins'
]
);
}
$this->setTemplateDir([]);
// when called from release.php TikiLib isn't initialised so we can ignore the themes and addons
if (class_exists('TikiLib')) {
// Theme templates
$themelib = TikiLib::lib('theme');
if (! empty($prefs['theme']) && ! in_array($prefs['theme'], ['custom_url'])) {
$theme_path = $themelib->get_theme_path($prefs['theme'], $prefs['theme_option'], '', 'templates'); // path to the theme options
$this->addTemplateDir(TIKI_PATH . "/$theme_path/");
//if theme_admin is empty, use main theme and site_layout instead of site_layout_admin
if ($section != "admin" || empty($prefs['theme_admin'])) {
$layout = TIKI_PATH . "/$theme_path/" . 'layouts/' . $prefs['site_layout'] . '/';
if (! is_readable($layout)) {
$layout = TIKI_PATH . "/$theme_path/" . 'layouts/basic/';
}
$this->addTemplateDir($layout);
} else {
$layout = TIKI_PATH . "/$theme_path/" . 'layouts/' . $prefs['site_layout_admin'] . '/';
if (! is_readable($layout)) {
$layout = TIKI_PATH . "/$theme_path/" . 'layouts/basic/';
}
$this->addTemplateDir($layout);
}
$this->addTemplateDir(TIKI_PATH . "/$theme_path/" . 'layouts/');
$main_theme_path = $themelib->get_theme_path($prefs['theme'], '', '', 'templates'); // path to the main theme
$this->addTemplateDir(TIKI_PATH . "/$main_theme_path/");
//if theme_admin is empty, use main theme and site_layout instead of site_layout_admin
if ($section != "admin" || empty($prefs['theme_admin'])) {
$layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/' . $prefs['site_layout'] . '/';
if (! is_readable($layout)) {
$layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/basic/';
}
$this->addTemplateDir($layout);
} else {
$layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/' . $prefs['site_layout_admin'] . '/';
if (! is_readable($layout)) {
$layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/basic/';
}
$this->addTemplateDir($layout);
}
}
// Tikidomain main template folder
if (! empty($tikidomainslash)) {
$this->addTemplateDir(TIKI_PATH . "/themes/{$tikidomainslash}templates/"); // This dir is for all the themes in the tikidomain
$this->addTemplatedir($this->main_template_dir . '/' . $tikidomainslash); // legacy tpls just in case, for example: /templates/mydomain.ltd/
}
$this->addTemplateDir(TIKI_PATH . "/themes/templates/"); //This dir stores templates for all the themes
//Addon templates
foreach (\Tiki\Package\ExtensionManager::getPaths() as $path) {
$this->addTemplateDir($path . '/templates/');
}
}
//Layout templates
if (! empty($prefs['site_layout']) && ($section != "admin" || empty($prefs['theme_admin']))) { //use the admin layout if in the admin section
$layout = $this->main_template_dir . '/layouts/' . $prefs['site_layout'] . '/';
if (! is_readable($layout)) {
$layout = $this->main_template_dir . '/layouts/basic/';
}
$this->addTemplateDir($layout);
} elseif (! empty($prefs['site_layout_admin'])) {
$layout = $this->main_template_dir . '/layouts/' . $prefs['site_layout_admin'] . '/';
if (! is_readable($layout)) {
$layout = $this->main_template_dir . '/layouts/basic/';
}
$this->addTemplateDir($layout);
}
$this->addTemplateDir($this->main_template_dir . '/layouts/');
$this->addTemplateDir($this->main_template_dir);
//Test templates
$this->addTemplateDir(TIKI_PATH . '/lib/test/core/Search/');
}
/**
* When calling directly smarty functions, from PHP, you need to provide a object of type Smarty_Internal_Template
* The method signature for smarty functions is: smarty_function_xxxx($params, Smarty_Internal_Template $template)
*
* @return Smarty_Internal_Template
*/
public function getEmptyInternalTemplate()
{
global $prefs;
$tpl = new Smarty_Internal_Template('empty', $this);
$tpl->assign('app_name', $this->getTemplateVars('app_name'));
$tpl->assignByRef('prefs', $prefs);
return $tpl;
}
/**
* Checks a wiki page permissions are ok to use as a template and returns the page info if all ok
*
* @param string $page
* @param string|null $tpl_source
*
* @return array|null
* @throws Exception
*/
final public function checkWikiPageTemplatePerms(string $page, ?string &$tpl_source): ?array
{
global $tikilib;
$perms = Perms::get([ 'type' => 'wiki page', 'object' => $page ]);
if (! $perms->use_as_template) {
$tpl_source = tra('Permission denied: the specified wiki page cannot be used as Smarty template resource') . '<br />';
// TODO: do not cache ! and return the message only once should be enough...
return null;
}
// check perms for non-admin editors but only show to admins
if ($perms->admin_wiki) {
$loaded = $perms->getResolver()->dump();
$nonAdminEditorGroups = [];
if (is_array($loaded['perms']['edit'])) {
foreach ($loaded['perms']['edit'] as $editorGroup) {
if ($editorGroup !== 'Admins' && is_array($loaded['perms']['admin_wiki']) && ! in_array($editorGroup, $loaded['perms']['admin_wiki'])) {
$nonAdminEditorGroups[] = $editorGroup;
}
}
}
if ($nonAdminEditorGroups) {
$groupString = implode(', ', $nonAdminEditorGroups);
TikiLib::lib('smarty')->loadPlugin('smarty_modifier_sefurl');
$pageLink = '<a href="' . smarty_modifier_sefurl($page) . '" class="alert-link">' . $page . '</a>';
if (count($nonAdminEditorGroups) > 1) {
$message = 'The %0 groups can edit this template page %1 but are not wiki administrators';
$groupString = substr_replace($groupString, tr(' and'), strrpos($groupString, ','), 1);
} else {
$message = 'The %0 group can edit this template page %1 but is not a wiki administrator';
}
Feedback::warning(tr($message, $groupString, $pageLink));
}
}
$info = $tikilib->get_page_info($page);
if (empty($info)) {
return null;
} else {
return (array) $info;
}
}
}