|
| 1 | +<?php |
| 2 | +/** |
| 3 | + * Smart abstraction layer. |
| 4 | + * |
| 5 | + * @author Mark O'Sullivan <markm@vanillaforums.com> |
| 6 | + * @copyright 2009-2019 Vanilla Forums Inc. |
| 7 | + * @license GPL-2.0-only |
| 8 | + * @package Core |
| 9 | + * @since 2.0 |
| 10 | + */ |
| 11 | + |
| 12 | +/** |
| 13 | + * Vanilla implementation of Smarty templating engine. |
| 14 | + */ |
| 15 | +class Gdn_Smarty implements \Vanilla\Contracts\Web\LegacyViewHandlerInterface { |
| 16 | + |
| 17 | + /** @var Smarty The smarty object used for the template. */ |
| 18 | + protected $_Smarty = null; |
| 19 | + |
| 20 | + /** |
| 21 | + * |
| 22 | + * |
| 23 | + * @param string $path |
| 24 | + * @param Gdn_Controller $controller |
| 25 | + */ |
| 26 | + public function init($path, $controller) { |
| 27 | + $smarty = $this->smarty(); |
| 28 | + |
| 29 | + // Get a friendly name for the controller. |
| 30 | + $controllerName = get_class($controller); |
| 31 | + if (stringEndsWith($controllerName, 'Controller', true)) { |
| 32 | + $controllerName = substr($controllerName, 0, -10); |
| 33 | + } |
| 34 | + |
| 35 | + $smarty->assign('UniversalNavUrl', c('Theme.UniversalNavUrl')); |
| 36 | + $smarty->assign('SignInUrl', signInUrl()); |
| 37 | + $smarty->assign('SignUpUrl', registerUrl('discussions')); |
| 38 | + $smarty->assign('SignOutUrl', signOutUrl()); |
| 39 | + |
| 40 | + // Get an ID for the body. |
| 41 | + $bodyIdentifier = strtolower($controller->ApplicationFolder.'_'.$controllerName.'_'.Gdn_Format::alphaNumeric(strtolower($controller->RequestMethod))); |
| 42 | + $smarty->assign('BodyID', htmlspecialchars($bodyIdentifier)); |
| 43 | + //$Smarty->assign('Config', Gdn::config()); |
| 44 | + |
| 45 | + // Assign some information about the user. |
| 46 | + $session = Gdn::session(); |
| 47 | + if ($session->isValid()) { |
| 48 | + $user = [ |
| 49 | + 'Name' => htmlspecialchars($session->User->Name), |
| 50 | + 'Photo' => '', |
| 51 | + 'CountNotifications' => (int)val('CountNotifications', $session->User, 0), |
| 52 | + 'CountUnreadConversations' => (int)val('CountUnreadConversations', $session->User, 0), |
| 53 | + 'SignedIn' => true, |
| 54 | + 'TopcoderPhotoUrl' => $session->getAttribute('TopcoderPhotoUrl', null), |
| 55 | + 'TopcoderUserID' => $session->getAttribute('TopcoderUserID', null) |
| 56 | + ]; |
| 57 | + |
| 58 | + $photo = $session->User->Photo; |
| 59 | + if ($photo) { |
| 60 | + if (!isUrl($photo)) { |
| 61 | + $photo = Gdn_Upload::url(changeBasename($photo, 'n%s')); |
| 62 | + } |
| 63 | + } else { |
| 64 | + $photo = UserModel::getDefaultAvatarUrl($session->User); |
| 65 | + } |
| 66 | + $user['Photo'] = $photo; |
| 67 | + } else { |
| 68 | + $user = false; /*array( |
| 69 | + 'Name' => '', |
| 70 | + 'CountNotifications' => 0, |
| 71 | + 'SignedIn' => FALSE);*/ |
| 72 | + } |
| 73 | + $smarty->assign('User', $user); |
| 74 | + |
| 75 | + // Make sure that any datasets use arrays instead of objects. |
| 76 | + foreach ($controller->Data as $key => $value) { |
| 77 | + if ($value instanceof Gdn_DataSet) { |
| 78 | + $controller->Data[$key] = $value->resultArray(); |
| 79 | + } elseif ($value instanceof stdClass) { |
| 80 | + $controller->Data[$key] = (array)$value; |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + $bodyClass = val('CssClass', $controller->Data, '', true); |
| 85 | + $sections = Gdn_Theme::section(null, 'get'); |
| 86 | + if (is_array($sections)) { |
| 87 | + foreach ($sections as $section) { |
| 88 | + $bodyClass .= ' Section-'.$section; |
| 89 | + } |
| 90 | + } |
| 91 | + |
| 92 | + $controller->Data['BodyClass'] = $bodyClass; |
| 93 | + |
| 94 | + // Set the current locale for themes to take advantage of. |
| 95 | + $locale = Gdn::locale()->Locale; |
| 96 | + $currentLocale = [ |
| 97 | + 'Key' => $locale, |
| 98 | + 'Lang' => str_replace('_', '-', Gdn::locale()->language(true)) // mirrors html5 lang attribute |
| 99 | + ]; |
| 100 | + if (class_exists('Locale')) { |
| 101 | + $currentLocale['Language'] = Locale::getPrimaryLanguage($locale); |
| 102 | + $currentLocale['Region'] = Locale::getRegion($locale); |
| 103 | + $currentLocale['DisplayName'] = Locale::getDisplayName($locale, $locale); |
| 104 | + $currentLocale['DisplayLanguage'] = Locale::getDisplayLanguage($locale, $locale); |
| 105 | + $currentLocale['DisplayRegion'] = Locale::getDisplayRegion($locale, $locale); |
| 106 | + } |
| 107 | + $smarty->assign('CurrentLocale', $currentLocale); |
| 108 | + |
| 109 | + $smarty->assign('Assets', (array)$controller->Assets); |
| 110 | + // 2016-07-07 Linc: Request used to return blank for homepage. |
| 111 | + // Now it returns defaultcontroller. This restores BC behavior. |
| 112 | + $isHomepage = val('isHomepage', $controller->Data); |
| 113 | + $path = ($isHomepage) ? "" : Gdn::request()->path(); |
| 114 | + $smarty->assign('Path', $path); |
| 115 | + $smarty->assign('Homepage', $isHomepage); // true/false |
| 116 | + |
| 117 | + // Assign the controller data last so the controllers override any default data. |
| 118 | + $smarty->assign($controller->Data); |
| 119 | + |
| 120 | + $security = new SmartySecurityVanilla($smarty); |
| 121 | + |
| 122 | + $security->php_handling = Smarty::PHP_REMOVE; |
| 123 | + $security->allow_constants = false; |
| 124 | + $security->allow_super_globals = false; |
| 125 | + $security->streams = null; |
| 126 | + |
| 127 | + $security->setPhpFunctions(array_merge($security->php_functions, [ |
| 128 | + 'array', // Yes, Smarty really blocks this. |
| 129 | + 'category', |
| 130 | + 'categoryUrl', |
| 131 | + 'checkPermission', |
| 132 | + 'commentUrl', |
| 133 | + 'discussionUrl', |
| 134 | + 'inSection', |
| 135 | + 'inCategory', |
| 136 | + 'ismobile', |
| 137 | + 'multiCheckPermission', |
| 138 | + 'getValue', |
| 139 | + 'setValue', |
| 140 | + 'url', |
| 141 | + 'useragenttype', |
| 142 | + 'userUrl', |
| 143 | + ])); |
| 144 | + |
| 145 | + $security->php_modifiers = array_merge( |
| 146 | + $security->php_functions, |
| 147 | + ['sprintf'] |
| 148 | + ); |
| 149 | + |
| 150 | + $smarty->enableSecurity($security); |
| 151 | + |
| 152 | + } |
| 153 | + |
| 154 | + /** |
| 155 | + * Render the given view. |
| 156 | + * |
| 157 | + * @param string $path The path to the view's file. |
| 158 | + * @param Controller $controller The controller that is rendering the view. |
| 159 | + */ |
| 160 | + public function render($path, $controller) { |
| 161 | + $smarty = $this->smarty(); |
| 162 | + $this->init($path, $controller); |
| 163 | + $compileID = $smarty->compile_id; |
| 164 | + if (defined('CLIENT_NAME')) { |
| 165 | + $compileID = CLIENT_NAME; |
| 166 | + } |
| 167 | + |
| 168 | + $smarty->setTemplateDir(dirname($path)); |
| 169 | + $smarty->display($path, null, $compileID); |
| 170 | + } |
| 171 | + |
| 172 | + /** |
| 173 | + * |
| 174 | + * |
| 175 | + * @return Smarty The smarty object used for rendering. |
| 176 | + */ |
| 177 | + public function smarty() { |
| 178 | + if (is_null($this->_Smarty)) { |
| 179 | + $smarty = new SmartyBC(); |
| 180 | + |
| 181 | + $smarty->setCacheDir(PATH_CACHE.'/Smarty/cache'); |
| 182 | + $smarty->setCompileDir(PATH_CACHE.'/Smarty/compile'); |
| 183 | + $smarty->addPluginsDir(PATH_LIBRARY.'/SmartyPlugins'); |
| 184 | + |
| 185 | +// Gdn::pluginManager()->Trace = TRUE; |
| 186 | + Gdn::pluginManager()->callEventHandlers($smarty, 'Gdn_Smarty', 'Init'); |
| 187 | + |
| 188 | + $this->_Smarty = $smarty; |
| 189 | + } |
| 190 | + return $this->_Smarty; |
| 191 | + } |
| 192 | + |
| 193 | + /** |
| 194 | + * See if the provided template causes any errors. |
| 195 | + * |
| 196 | + * @param type $path Path of template file to test. |
| 197 | + * @return boolean TRUE if template loads successfully. |
| 198 | + */ |
| 199 | + public function testTemplate($path) { |
| 200 | + $smarty = $this->smarty(); |
| 201 | + $this->init($path, Gdn::controller()); |
| 202 | + $compileID = $smarty->compile_id; |
| 203 | + if (defined('CLIENT_NAME')) { |
| 204 | + $compileID = CLIENT_NAME; |
| 205 | + } |
| 206 | + |
| 207 | + $return = true; |
| 208 | + try { |
| 209 | + $result = $smarty->fetch($path, null, $compileID); |
| 210 | + // echo wrap($Result, 'textarea', array('style' => 'width: 900px; height: 400px;')); |
| 211 | + $return = ($result == '' || strpos($result, '<title>Fatal Error</title>') > 0 || strpos($result, '<h1>Something has gone wrong.</h1>') > 0) ? false : true; |
| 212 | + } catch (Exception $ex) { |
| 213 | + $return = false; |
| 214 | + } |
| 215 | + return $return; |
| 216 | + } |
| 217 | +} |
0 commit comments