1<?php 2/** 3 * brings Smarty functionality into Tiki 4 * 5 * this script may only be included, it will die if called directly. 6 * 7 * @package TikiWiki 8 * @subpackage lib\init 9 * @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. 10 * @licence Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 11 */ 12// $Id$ 13 14// die if called directly. 15if (strpos($_SERVER['SCRIPT_NAME'], basename(__FILE__)) !== false) { 16 header('location: index.php'); 17 exit; 18} 19 20require_once __DIR__ . '/../setup/third_party.php'; 21 22/** 23 * extends Smarty_Security 24 * @package TikiWiki\lib\init 25 */ 26class Tiki_Security_Policy extends Smarty_Security 27{ 28 /** 29 * needs a proper description 30 * @var array $secure_dir 31 */ 32 33 public $trusted_uri = []; 34 35 public $secure_dir = []; 36 37 /** 38 * needs a proper description 39 * @param Smarty $smarty 40 */ 41 public function __construct($smarty) 42 { 43 if (class_exists("TikiLib")) { 44 $tikilib = TikiLib::lib('tiki'); 45 // modlib defines zone_is_empty which must exist before smarty initializes to fix bug with smarty autoloader after version 3.1.21 46 TikiLib::lib('mod'); 47 } 48 49 parent::__construct($smarty); 50 51 52 //With phpunit and command line these don't exist yet for some reason 53 if (isset($tikilib) && method_exists($tikilib, "get_preference")) { 54 global $url_host; 55 $this->trusted_uri[] = '#' . preg_quote("http://$url_host", '$#') . '#'; 56 $this->trusted_uri[] = '#' . preg_quote("https://$url_host", '$#') . '#'; 57 58 $functions = array_filter($tikilib->get_preference('smarty_security_functions', [], true)); 59 $modifiers = array_filter($tikilib->get_preference('smarty_security_modifiers', [], true)); 60 $dirs = array_filter($tikilib->get_preference('smarty_security_dirs', [], true)); 61 62 $cdns = preg_split('/\s+/', $tikilib->get_preference('tiki_cdn', '')); 63 $cdns_ssl = preg_split('/\s+/', $tikilib->get_preference('tiki_cdn_ssl', '')); 64 $cdn_uri = array_filter(array_merge($cdns, $cdns_ssl)); 65 foreach ($cdn_uri as $uri) { 66 $this->trusted_uri[] = '#' . preg_quote($uri) . '$#'; 67 } 68 } else { 69 $functions = []; 70 $modifiers = []; 71 $dirs = []; 72 } 73 74 // Add defaults 75 $this->php_modifiers = array_merge([ 76 'addslashes', 77 'array_filter', 78 'array_reverse', 79 'count', 80 'escape', 81 'explode', 82 'htmlentities', 83 'implode', 84 'is_array', 85 'json_decode', 86 'json_encode', 87 'md5', 88 'nl2br', 89 'preg_split', 90 'strip_tags', 91 'stristr', 92 'strpos', 93 'substr', 94 'tra', 95 'trim', 96 'ucfirst', 97 'ucwords', 98 'urlencode', 99 'var_dump', 100 ], $modifiers); 101 102 $this->php_functions = array_merge(['isset', 103 'array', // not needed? use {$value = []} 104 'array_rand', 105 'array_key_exists', 106 'basename', 107 'count', 108 'empty', 109 'ereg', // deprecated and removed in php7+ use preg functions instead 110 'in_array', 111 'is_array', 112 'is_numeric', 113 'json_encode', 114 'min', 115 'max', 116 'nl2br', 117 'preg_match', 118 'preg_match_all', 119 'preg_replace', 120 'sizeof', 121 'strlen', 122 'stristr', 123 'strpos', 124 'strstr', 125 'str_replace', 126 'strtolower', 127 'time', 128 'tra', 129 'trim', 130 'zone_is_empty', 131 ], $functions); 132 133 $this->secure_dir = array_merge($this->secure_dir, $dirs); 134 } 135} 136 137/** 138 * extends Smarty. 139 * 140 * Centralizing overrides here will avoid problems when upgrading to newer versions of the Smarty library. 141 * @package TikiWiki\lib\init 142 */ 143class Smarty_Tiki extends Smarty 144{ 145 /** 146 * needs a proper description 147 * @var array|null 148 */ 149 public $url_overriding_prefix_stack = null; 150 /** 151 * needs a proper description 152 * @var null 153 */ 154 public $url_overriding_prefix = null; 155 /** 156 * needs a proper description 157 * @var null|string 158 */ 159 public $main_template_dir = null; 160 161 /** 162 * needs a proper description 163 */ 164 public function __construct() 165 { 166 parent::__construct(); 167 global $prefs; 168 169 $this->initializePaths(); 170 171 $this->setConfigDir(null); 172 if (! isset($prefs['smarty_compilation'])) { 173 $prefs['smarty_compilation'] = ''; 174 } 175 $this->compile_check = ( $prefs['smarty_compilation'] != 'never' ); 176 $this->force_compile = ( $prefs['smarty_compilation'] == 'always' ); 177 $this->assign('app_name', 'Tiki'); 178 179 if (! isset($prefs['smarty_security']) || $prefs['smarty_security'] == 'y') { 180 $this->enableSecurity('Tiki_Security_Policy'); 181 } else { 182 $this->disableSecurity(); 183 } 184 $this->use_sub_dirs = false; 185 $this->url_overriding_prefix_stack = []; 186 if (! empty($prefs['smarty_notice_reporting']) and $prefs['smarty_notice_reporting'] === 'y') { 187 $this->error_reporting = E_ALL; 188 } else { 189 $this->error_reporting = E_ALL ^ E_NOTICE; 190 } 191 if (! empty($prefs['smarty_cache_perms'])) { 192 $this->_file_perms = (int) $prefs['smarty_cache_perms']; 193 } 194 195 $this->loadFilter('pre', 'tr'); 196 $this->loadFilter('pre', 'jq'); 197 198 include_once(__DIR__ . '/../smarty_tiki/resource.tplwiki.php'); 199 $this->registerResource('tplwiki', ['smarty_resource_tplwiki_source', 'smarty_resource_tplwiki_timestamp', 'smarty_resource_tplwiki_secure', 'smarty_resource_tplwiki_trusted']); 200 201 include_once(__DIR__ . '/../smarty_tiki/resource.wiki.php'); 202 $this->registerResource('wiki', ['smarty_resource_wiki_source', 'smarty_resource_wiki_timestamp', 'smarty_resource_wiki_secure', 'smarty_resource_wiki_trusted']); 203 204 global $prefs; 205 // Assign the prefs array in smarty, by reference 206 $this->assignByRef('prefs', $prefs); 207 208 if (! empty($prefs['log_tpl']) && $prefs['log_tpl'] === 'y') { 209 $this->loadFilter('pre', 'log_tpl'); 210 } 211 if (! empty($prefs['feature_sefurl_filter']) && $prefs['feature_sefurl_filter'] === 'y') { 212 require_once('tiki-sefurl.php'); 213 $this->registerFilter('output', 'filter_out_sefurl'); 214 } 215 216 // restore tiki's own escape function 217 $this->loadPlugin('smarty_modifier_escape'); 218 $this->registerPlugin('modifier', 'escape', 'smarty_modifier_escape'); 219 } 220 221 /** 222 * Fetch templates from plugins (smarty plugins, wiki plugins, modules, ...) that may need to : 223 * - temporarily override some smarty vars, 224 * - prefix their self_link / button / query URL arguments 225 * 226 * @param $_smarty_tpl_file 227 * @param null $override_vars 228 * 229 * @return string 230 */ 231 public function plugin_fetch($_smarty_tpl_file, &$override_vars = null) 232 { 233 $smarty_orig_values = []; 234 if (is_array($override_vars)) { 235 foreach ($override_vars as $k => $v) { 236 $smarty_orig_values[ $k ] = $this->getTemplateVars($k); 237 $this->assignByRef($k, $override_vars[ $k ]); 238 } 239 } 240 241 $return = $this->fetch($_smarty_tpl_file); 242 243 // Restore original values of smarty variables 244 if (count($smarty_orig_values) > 0) { 245 foreach ($smarty_orig_values as $k => $v) { 246 $this->assignByRef($k, $smarty_orig_values[ $k ]); 247 } 248 } 249 250 unset($smarty_orig_values); 251 return $return; 252 } 253 254 /** 255 * needs a proper description 256 * @param null $_smarty_tpl_file 257 * @param null $_smarty_cache_id 258 * @param null $_smarty_compile_id 259 * @param null $parent 260 * @param bool $_smarty_display 261 * @param bool $merge_tpl_vars 262 * @param bool $no_output_filter 263 * @return string 264 */ 265 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) 266 { 267 if (strpos($_smarty_tpl_file, 'extends:') === 0) { 268 // temporarily disable extends_recursion which restores smarty < 3.1.28 behaviour 269 // see note at vendor_bundled/vendor/smarty/smarty/libs/Smarty.class.php:296 for more 270 271 $this->extends_recursion = false; 272 } 273 $this->muteExpectedErrors(); 274 $this->refreshLanguage(); 275 276 $this->assign_layout_sections($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent); 277 278 $_smarty_tpl_file = $this->get_filename($_smarty_tpl_file); 279 280 if ($_smarty_display) { 281 $html = parent::display($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent); 282 } else { 283 $html = parent::fetch($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent); 284 } 285 286 if (! $this->extends_recursion) { 287 $this->extends_recursion = true; 288 } 289 290 return $html; 291 } 292 293 /** 294 * Clears the value of an assigned variable 295 * @param $var mixed 296 * @return Smarty_Internal_Data 297 */ 298 public function clear_assign($var) 299 { 300 return parent::clearAssign($var); 301 } 302 303 /** 304 * This is used to assign() values to the templates by reference instead of making a copy. 305 * @param $var string 306 * @param $value mixed 307 * @return Smarty_Internal_Data 308 */ 309 public function assign_by_ref($var, &$value) 310 { 311 return parent::assignByRef($var, $value); 312 } 313 314 /** 315 * fetch in a specific language without theme consideration 316 * @param $lg 317 * @param $_smarty_tpl_file 318 * @param null $_smarty_cache_id 319 * @param null $_smarty_compile_id 320 * @param bool $_smarty_display 321 * @return mixed 322 */ 323 public function fetchLang($lg, $_smarty_tpl_file, $_smarty_cache_id = null, $_smarty_compile_id = null) 324 { 325 global $prefs; 326 327 $_smarty_tpl_file = $this->get_filename($_smarty_tpl_file); 328 329 $lgSave = $prefs['language']; 330 $prefs['language'] = $lg; 331 $this->refreshLanguage(); 332 $res = parent::fetch($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id); 333 $prefs['language'] = $lgSave; // Restore the language of the user triggering the notification 334 $this->refreshLanguage(); 335 336 return preg_replace("/^[ \t]*/", '', $res); 337 } 338 339 /** 340 * needs a proper description 341 * @param null $resource_name 342 * @param null $cache_id 343 * @param null $compile_id 344 * @param null $parent 345 * @param string $content_type 346 * @return Purified|void 347 */ 348 public function display($resource_name = null, $cache_id = null, $compile_id = null, $parent = null, $content_type = 'text/html; charset=utf-8') 349 { 350 351 global $prefs; 352 $this->muteExpectedErrors(); 353 if (! empty($prefs['feature_htmlpurifier_output']) and $prefs['feature_htmlpurifier_output'] == 'y') { 354 static $loaded = false; 355 static $purifier = null; 356 if (! $loaded) { 357 require_once('lib/htmlpurifier_tiki/HTMLPurifier.tiki.php'); 358 $config = getHTMLPurifierTikiConfig(); 359 $purifier = new HTMLPurifier($config); 360 $loaded = true; 361 } 362 } 363 364 /** 365 * Add security headers. By default there headers are not sent. 366 * To change go to admin > security > site access 367 */ 368 if (! headers_sent()) { 369 if (! isset($prefs['http_header_frame_options'])) { 370 $frame = false; 371 } else { 372 $frame = $prefs['http_header_frame_options']; 373 } 374 if (! isset($prefs['http_header_xss_protection'])) { 375 $xss = false; // prevent smarty E_NOTICE 376 } else { 377 $xss = $prefs['http_header_xss_protection']; 378 } 379 380 if (! isset($prefs['http_header_content_type_options'])) { 381 $content_type_options = false; // prevent smarty E_NOTICE 382 } else { 383 $content_type_options = $prefs['http_header_content_type_options']; 384 } 385 386 if (! isset($prefs['http_header_content_security_policy'])) { 387 $content_security_policy = false; // prevent smarty E_NOTICE 388 } else { 389 $content_security_policy = $prefs['http_header_content_security_policy']; 390 } 391 392 if (! isset($prefs['http_header_strict_transport_security'])) { 393 $strict_transport_security = false; // prevent smarty E_NOTICE 394 } else { 395 $strict_transport_security = $prefs['http_header_strict_transport_security']; 396 } 397 398 if (! isset($prefs['http_header_public_key_pins'])) { 399 $public_key_pins = false; // prevent smarty E_NOTICE 400 } else { 401 $public_key_pins = $prefs['http_header_public_key_pins']; 402 } 403 404 if ($frame == 'y') { 405 $header_value = $prefs['http_header_frame_options_value']; 406 header('X-Frame-Options: ' . $header_value); 407 } 408 if ($xss == 'y') { 409 $header_value = $prefs['http_header_xss_protection_value']; 410 header('X-XSS-Protection: ' . $header_value); 411 } 412 if ($content_type_options == 'y') { 413 header('X-Content-Type-Options: nosniff'); 414 } 415 if ($content_security_policy == 'y') { 416 $header_value = $prefs['http_header_content_security_policy_value']; 417 header('Content-Security-Policy: ' . $header_value); 418 } 419 420 if ($strict_transport_security == 'y') { 421 $header_value = $prefs['http_header_strict_transport_security_value']; 422 header('Strict-Transport-Security: ' . $header_value); 423 } 424 425 if ($public_key_pins == 'y') { 426 $header_value = $prefs['http_header_public_key_pins_value']; 427 header('Public-Key-Pins: ' . $header_value); 428 } 429 } 430 431 /** 432 * By default, display is used with text/html content in UTF-8 encoding 433 * If you want to output other data from smarty, 434 * - either use fetch() / fetchLang() 435 * - or set $content_type to '' (empty string) or another content type. 436 */ 437 if ($content_type != '' && ! headers_sent()) { 438 header('Content-Type: ' . $content_type); 439 } 440 441 if (function_exists('current_object') && $obj = current_object()) { 442 $attributes = TikiLib::lib('attribute')->get_attributes($obj['type'], $obj['object']); 443 if (isset($attributes['tiki.object.layout'])) { 444 $prefs['site_layout'] = $attributes['tiki.object.layout']; 445 } 446 } 447 448 $this->refreshLanguage(); 449 450 TikiLib::events()->trigger('tiki.process.render', []); 451 452 $this->assign_layout_sections($resource_name, $cache_id, $compile_id, $parent); 453 454 if (! empty($prefs['feature_htmlpurifier_output']) and $prefs['feature_htmlpurifier_output'] == 'y') { 455 return $purifier->purify(parent::display($resource_name, $cache_id, $compile_id)); 456 } else { 457 return parent::display($resource_name, $cache_id, $compile_id); 458 } 459 } 460 461 /** 462 * Since Smarty 3.1.23, display no longer calls fetch function, so we need to have this Tiki layout section assignment 463 * and modules loading called in both places 464 */ 465 private function assign_layout_sections($_smarty_tpl_file, $_smarty_cache_id, $_smarty_compile_id, $parent) 466 { 467 global $prefs; 468 469 if (($tpl = $this->getTemplateVars('mid')) && ( $_smarty_tpl_file == 'tiki.tpl' || $_smarty_tpl_file == 'tiki-print.tpl' || $_smarty_tpl_file == 'tiki_full.tpl' )) { 470 // Set the last mid template to be used by AJAX to simulate a 'BACK' action 471 if (isset($_SESSION['last_mid_template'])) { 472 $this->assign('last_mid_template', $_SESSION['last_mid_template']); 473 $this->assign('last_mid_php', $_SESSION['last_mid_php']); 474 } 475 $_SESSION['last_mid_template'] = $tpl; 476 $_SESSION['last_mid_php'] = $_SERVER['REQUEST_URI']; 477 478 // set the first part of the browser title for admin pages 479 if (null === $this->getTemplateVars('headtitle')) { 480 $script_name = basename($_SERVER['SCRIPT_NAME']); 481 if ($script_name === 'route.php' && ! empty($inclusion)) { 482 $script_name = $inclusion; 483 } 484 if ($script_name != 'tiki-admin.php' && strpos($script_name, 'tiki-admin') === 0) { 485 $str = substr($script_name, 10, strpos($script_name, '.php') - 10); 486 $str = ucwords(trim(str_replace('_', ' ', $str))); 487 $this->assign('headtitle', 'Admin ' . $str); 488 } elseif (strpos($script_name, 'tiki-list') === 0) { 489 $str = substr($script_name, 9, strpos($script_name, '.php') - 9); 490 $str = ucwords(trim(str_replace('_', ' ', $str))); 491 $this->assign('headtitle', 'List ' . $str); 492 } elseif (strpos($script_name, 'tiki-view') === 0) { 493 $str = substr($script_name, 9, strpos($script_name, '.php') - 9); 494 $str = ucwords(trim(str_replace('_', ' ', $str))); 495 $this->assign('headtitle', 'View ' . $str); 496 } elseif ($prefs['urlIndex'] && strpos($script_name, $prefs['urlIndex']) === 0) { 497 $this->assign('headtitle', tra($prefs['urlIndexBrowserTitle'])); // Viewing Custom Homepage 498 } else { // still not set? guess... 499 $str = str_replace(['tiki-', '.php', '_'], ['', '', ' '], $script_name); 500 $str = ucwords($str); 501 $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 502 } 503 } 504 505 if ($_smarty_tpl_file == 'tiki-print.tpl') { 506 $this->assign('print_page', 'y'); 507 } 508 $data = $this->fetch($tpl, $_smarty_cache_id, $_smarty_compile_id, $parent);//must get the mid because the modules can overwrite smarty variables 509 510 $this->assign('mid_data', $data); 511 } elseif ($_smarty_tpl_file == 'confirm.tpl' || $_smarty_tpl_file == 'error.tpl' || $_smarty_tpl_file == 'error_ticket.tpl' || $_smarty_tpl_file == 'error_simple.tpl') { 512 if (! empty(ob_get_status())) { 513 ob_end_clean(); // Empty existing Output Buffer that may have been created in smarty before the call of this confirm / error* template 514 } 515 if ($prefs['feature_obzip'] == 'y') { 516 ob_start('ob_gzhandler'); 517 } 518 } 519 520 if (! defined('TIKI_IN_INSTALLER') && ! defined('TIKI_IN_TEST')) { 521 require_once 'tiki-modules.php'; 522 } 523 } 524 525 /** 526 * Returns the file path associated to the template name 527 * Check if the path is a template inside one of the template dirs and not an arbitrary file 528 * @param $template 529 * @return string 530 */ 531 public function get_filename($template) 532 { 533 if (substr($template, 0, 5) === 'file:') { 534 $template = substr($template, 5); 535 } 536 537 // could be extends: or something else? 538 if (preg_match('/^[a-z]+\:/', $template)) { 539 return $template; 540 } 541 542 //get the list of template directories 543 $dirs = array_merge( 544 $this->getTemplateDir(), 545 ['temp/cache'], 546 $this->security_policy ? array_map('realpath', $this->security_policy->secure_dir) : [] 547 ); 548 549 // sanity check 550 if (file_exists($template)) { 551 $valid_path = false; 552 foreach ($dirs as $dir) { 553 $dirPath = realpath($dir); 554 if ($dirPath === false) { 555 continue; 556 } 557 558 if (strpos(realpath($template), $dirPath) === 0) { 559 $valid_path = true; 560 break; 561 } 562 } 563 if (! $valid_path) { 564 Feedback::error(tr("Invalid template name: %0", $template)); 565 return ""; 566 } 567 return $template; 568 } 569 570 //go through directories in search of the template 571 foreach ($dirs as $dir) { 572 if (file_exists($dir . $template)) { 573 return $dir . $template; 574 } 575 } 576 return ""; 577 } 578 579 /** 580 * needs a proper description 581 * @param $url_arguments_prefix 582 * @param $arguments_list 583 */ 584 public function set_request_overriders($url_arguments_prefix, $arguments_list) 585 { 586 $this->url_overriding_prefix_stack[] = [ $url_arguments_prefix . '-', $arguments_list ]; 587 $this->url_overriding_prefix =& $this->url_overriding_prefix_stack[ count($this->url_overriding_prefix_stack) - 1 ]; 588 } 589 590 /** 591 * needs a proper description 592 * @param $url_arguments_prefix 593 * @param $arguments_list 594 */ 595 public function remove_request_overriders($url_arguments_prefix, $arguments_list) 596 { 597 $last_override_prefix = empty($this->url_overriding_prefix_stack) ? false : array_pop($this->url_overriding_prefix_stack); 598 if (! is_array($last_override_prefix) || $url_arguments_prefix . '-' != $last_override_prefix[0]) { 599 trigger_error('URL Overriding prefix stack is in a bad state', E_USER_ERROR); 600 } 601 $this->url_overriding_prefix =& $this->url_overriding_prefix_stack[ count($this->url_overriding_prefix_stack) - 1 ]; 602 ; 603 } 604 605 public function refreshLanguage() 606 { 607 global $tikidomain, $prefs; 608 609 $lang = $prefs['language']; 610 if (empty($lang)) { 611 $lang = 'default'; 612 } 613 614 if (! empty($prefs['site_layout'])) { 615 $layout = $prefs['site_layout']; 616 } else { 617 $layout = 'classic'; 618 } 619 620 $this->setCompileId("$lang-$tikidomain-$layout"); 621 $this->initializePaths(); 622 } 623 624 /* 625 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 626 */ 627 public function initializePaths() 628 { 629 global $prefs, $tikidomainslash, $section; 630 631 if (! $this->main_template_dir) { 632 // First run only 633 $this->main_template_dir = TIKI_PATH . '/templates/'; 634 $this->setCompileDir(TIKI_PATH . "/temp/templates_c"); 635 $this->setPluginsDir( 636 [ // the directory order must be like this to overload a plugin 637 TIKI_PATH . '/' . TIKI_SMARTY_DIR, 638 SMARTY_DIR . 'plugins' 639 ] 640 ); 641 } 642 643 $this->setTemplateDir([]); 644 645 // when called from release.php TikiLib isn't initialised so we can ignore the themes and addons 646 if (class_exists('TikiLib')) { 647 // Theme templates 648 $themelib = TikiLib::lib('theme'); 649 if (! empty($prefs['theme']) && ! in_array($prefs['theme'], ['custom_url'])) { 650 $theme_path = $themelib->get_theme_path($prefs['theme'], $prefs['theme_option'], '', 'templates'); // path to the theme options 651 $this->addTemplateDir(TIKI_PATH . "/$theme_path/"); 652 //if theme_admin is empty, use main theme and site_layout instead of site_layout_admin 653 if ($section != "admin" || empty($prefs['theme_admin'])) { 654 $layout = TIKI_PATH . "/$theme_path/" . 'layouts/' . $prefs['site_layout'] . '/'; 655 if (! is_readable($layout)) { 656 $layout = TIKI_PATH . "/$theme_path/" . 'layouts/basic/'; 657 } 658 $this->addTemplateDir($layout); 659 } else { 660 $layout = TIKI_PATH . "/$theme_path/" . 'layouts/' . $prefs['site_layout_admin'] . '/'; 661 if (! is_readable($layout)) { 662 $layout = TIKI_PATH . "/$theme_path/" . 'layouts/basic/'; 663 } 664 $this->addTemplateDir($layout); 665 } 666 $this->addTemplateDir(TIKI_PATH . "/$theme_path/" . 'layouts/'); 667 668 $main_theme_path = $themelib->get_theme_path($prefs['theme'], '', '', 'templates'); // path to the main theme 669 $this->addTemplateDir(TIKI_PATH . "/$main_theme_path/"); 670 //if theme_admin is empty, use main theme and site_layout instead of site_layout_admin 671 if ($section != "admin" || empty($prefs['theme_admin'])) { 672 $layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/' . $prefs['site_layout'] . '/'; 673 if (! is_readable($layout)) { 674 $layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/basic/'; 675 } 676 $this->addTemplateDir($layout); 677 } else { 678 $layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/' . $prefs['site_layout_admin'] . '/'; 679 if (! is_readable($layout)) { 680 $layout = TIKI_PATH . "/$main_theme_path/" . 'layouts/basic/'; 681 } 682 $this->addTemplateDir($layout); 683 } 684 } 685 // Tikidomain main template folder 686 if (! empty($tikidomainslash)) { 687 $this->addTemplateDir(TIKI_PATH . "/themes/{$tikidomainslash}templates/"); // This dir is for all the themes in the tikidomain 688 $this->addTemplatedir($this->main_template_dir . '/' . $tikidomainslash); // legacy tpls just in case, for example: /templates/mydomain.ltd/ 689 } 690 691 $this->addTemplateDir(TIKI_PATH . "/themes/templates/"); //This dir stores templates for all the themes 692 693 //Addon templates 694 foreach (\Tiki\Package\ExtensionManager::getPaths() as $path) { 695 $this->addTemplateDir($path . '/templates/'); 696 } 697 } 698 699 //Layout templates 700 if (! empty($prefs['site_layout']) && ($section != "admin" || empty($prefs['theme_admin']))) { //use the admin layout if in the admin section 701 $layout = $this->main_template_dir . '/layouts/' . $prefs['site_layout'] . '/'; 702 if (! is_readable($layout)) { 703 $layout = $this->main_template_dir . '/layouts/basic/'; 704 } 705 $this->addTemplateDir($layout); 706 } elseif (! empty($prefs['site_layout_admin'])) { 707 $layout = $this->main_template_dir . '/layouts/' . $prefs['site_layout_admin'] . '/'; 708 if (! is_readable($layout)) { 709 $layout = $this->main_template_dir . '/layouts/basic/'; 710 } 711 $this->addTemplateDir($layout); 712 } 713 $this->addTemplateDir($this->main_template_dir . '/layouts/'); 714 $this->addTemplateDir($this->main_template_dir); 715 716 //Test templates 717 $this->addTemplateDir(TIKI_PATH . '/lib/test/core/Search/'); 718 } 719 720 /** 721 * When calling directly smarty functions, from PHP, you need to provide a object of type Smarty_Internal_Template 722 * The method signature for smarty functions is: smarty_function_xxxx($params, Smarty_Internal_Template $template) 723 * 724 * @return Smarty_Internal_Template 725 */ 726 public function getEmptyInternalTemplate() 727 { 728 $tpl = new Smarty_Internal_Template('empty', $this); 729 return $tpl; 730 } 731} 732