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.

388 lines
13 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
12 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Bart Visscher <bartv@thisnet.nl>
  6. * @author Brice Maron <brice@bmaron.net>
  7. * @author Christoph Wurst <christoph@owncloud.com>
  8. * @author Frank Karlitschek <frank@karlitschek.de>
  9. * @author Individual IT Services <info@individual-it.net>
  10. * @author Jakob Sack <mail@jakobsack.de>
  11. * @author Jan-Christoph Borchardt <hey@jancborchardt.net>
  12. * @author Joas Schilling <coding@schilljs.com>
  13. * @author John Molakvoæ <skjnldsv@users.noreply.github.com>
  14. * @author Jörn Friedrich Dreyer <jfd@butonic.de>
  15. * @author Lukas Reschke <lukas@statuscode.ch>
  16. * @author Marin Treselj <marin@pixelipo.com>
  17. * @author Michael Letzgus <www@chronos.michael-letzgus.de>
  18. * @author Morris Jobke <hey@morrisjobke.de>
  19. * @author Robin Appelman <robin@icewind.nl>
  20. * @author Roeland Jago Douma <roeland@famdouma.nl>
  21. * @author Thomas Müller <thomas.mueller@tmit.eu>
  22. * @author Vincent Petry <pvince81@owncloud.com>
  23. *
  24. * @license AGPL-3.0
  25. *
  26. * This code is free software: you can redistribute it and/or modify
  27. * it under the terms of the GNU Affero General Public License, version 3,
  28. * as published by the Free Software Foundation.
  29. *
  30. * This program is distributed in the hope that it will be useful,
  31. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  33. * GNU Affero General Public License for more details.
  34. *
  35. * You should have received a copy of the GNU Affero General Public License, version 3,
  36. * along with this program. If not, see <http://www.gnu.org/licenses/>
  37. *
  38. */
  39. use OC\TemplateLayout;
  40. require_once __DIR__.'/template/functions.php';
  41. /**
  42. * This class provides the templates for ownCloud.
  43. */
  44. class OC_Template extends \OC\Template\Base {
  45. /** @var string */
  46. private $renderAs; // Create a full page?
  47. /** @var string */
  48. private $path; // The path to the template
  49. /** @var array */
  50. private $headers = array(); //custom headers
  51. /** @var string */
  52. protected $app; // app id
  53. protected static $initTemplateEngineFirstRun = true;
  54. /**
  55. * Constructor
  56. *
  57. * @param string $app app providing the template
  58. * @param string $name of the template file (without suffix)
  59. * @param string $renderAs If $renderAs is set, OC_Template will try to
  60. * produce a full page in the according layout. For
  61. * now, $renderAs can be set to "guest", "user" or
  62. * "admin".
  63. * @param bool $registerCall = true
  64. */
  65. public function __construct( $app, $name, $renderAs = "", $registerCall = true ) {
  66. // Read the selected theme from the config file
  67. self::initTemplateEngine($renderAs);
  68. $theme = OC_Util::getTheme();
  69. $requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
  70. $parts = explode('/', $app); // fix translation when app is something like core/lostpassword
  71. $l10n = \OC::$server->getL10N($parts[0]);
  72. /** @var \OCP\Defaults $themeDefaults */
  73. $themeDefaults = \OC::$server->query(\OCP\Defaults::class);
  74. list($path, $template) = $this->findTemplate($theme, $app, $name);
  75. // Set the private data
  76. $this->renderAs = $renderAs;
  77. $this->path = $path;
  78. $this->app = $app;
  79. parent::__construct($template, $requestToken, $l10n, $themeDefaults);
  80. }
  81. /**
  82. * @param string $renderAs
  83. */
  84. public static function initTemplateEngine($renderAs) {
  85. if (self::$initTemplateEngineFirstRun){
  86. //apps that started before the template initialization can load their own scripts/styles
  87. //so to make sure this scripts/styles here are loaded first we use OC_Util::addScript() with $prepend=true
  88. //meaning the last script/style in this list will be loaded first
  89. if (\OC::$server->getSystemConfig()->getValue ('installed', false) && $renderAs !== 'error' && !\OCP\Util::needUpgrade()) {
  90. if (\OC::$server->getConfig ()->getAppValue ( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax') {
  91. OC_Util::addScript ( 'backgroundjobs', null, true );
  92. }
  93. }
  94. OC_Util::addStyle('server', null, true);
  95. OC_Util::addStyle('jquery-ui-fixes',null,true);
  96. OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
  97. OC_Util::addVendorStyle('select2/select2', null, true);
  98. OC_Util::addStyle('jquery.ocdialog');
  99. OC_Util::addTranslations("core", null, true);
  100. OC_Util::addScript('search', 'search', true);
  101. OC_Util::addScript('merged-template-prepend', null, true);
  102. OC_Util::addScript('jquery-ui-fixes');
  103. OC_Util::addScript('files/fileinfo');
  104. OC_Util::addScript('files/client');
  105. OC_Util::addScript('contactsmenu');
  106. if (\OC::$server->getConfig()->getSystemValue('debug')) {
  107. // Add the stuff we need always
  108. // following logic will import all vendor libraries that are
  109. // specified in core/js/core.json
  110. $fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
  111. if($fileContent !== false) {
  112. $coreDependencies = json_decode($fileContent, true);
  113. foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
  114. //remove trailing ".js" as addVendorScript will append it
  115. OC_Util::addVendorScript(
  116. substr($vendorLibrary, 0, -3),null,true);
  117. }
  118. } else {
  119. throw new \Exception('Cannot read core/js/core.json');
  120. }
  121. } else {
  122. // Import all (combined) default vendor libraries
  123. OC_Util::addVendorScript('core', null, true);
  124. }
  125. if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
  126. // polyfill for btoa/atob for IE friends
  127. OC_Util::addVendorScript('base64/base64');
  128. // shim for the davclient.js library
  129. \OCP\Util::addScript('files/iedavclient');
  130. }
  131. self::$initTemplateEngineFirstRun = false;
  132. }
  133. }
  134. /**
  135. * find the template with the given name
  136. * @param string $name of the template file (without suffix)
  137. *
  138. * Will select the template file for the selected theme.
  139. * Checking all the possible locations.
  140. * @param string $theme
  141. * @param string $app
  142. * @return string[]
  143. */
  144. protected function findTemplate($theme, $app, $name) {
  145. // Check if it is a app template or not.
  146. if( $app !== '' ) {
  147. $dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
  148. } else {
  149. $dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
  150. }
  151. $locator = new \OC\Template\TemplateFileLocator( $dirs );
  152. $template = $locator->find($name);
  153. $path = $locator->getPath();
  154. return array($path, $template);
  155. }
  156. /**
  157. * Add a custom element to the header
  158. * @param string $tag tag name of the element
  159. * @param array $attributes array of attributes for the element
  160. * @param string $text the text content for the element. If $text is null then the
  161. * element will be written as empty element. So use "" to get a closing tag.
  162. */
  163. public function addHeader($tag, $attributes, $text=null) {
  164. $this->headers[]= array(
  165. 'tag' => $tag,
  166. 'attributes' => $attributes,
  167. 'text' => $text
  168. );
  169. }
  170. /**
  171. * Process the template
  172. * @return boolean|string
  173. *
  174. * This function process the template. If $this->renderAs is set, it
  175. * will produce a full page.
  176. */
  177. public function fetchPage($additionalParams = null) {
  178. $data = parent::fetchPage($additionalParams);
  179. if( $this->renderAs ) {
  180. $page = new TemplateLayout($this->renderAs, $this->app);
  181. // Add custom headers
  182. $headers = '';
  183. foreach(OC_Util::$headers as $header) {
  184. $headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
  185. if ( strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes']))) ) {
  186. $headers .= ' defer';
  187. }
  188. foreach($header['attributes'] as $name=>$value) {
  189. $headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
  190. }
  191. if ($header['text'] !== null) {
  192. $headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
  193. } else {
  194. $headers .= '/>';
  195. }
  196. }
  197. $page->assign('headers', $headers);
  198. $page->assign('content', $data);
  199. return $page->fetchPage();
  200. }
  201. return $data;
  202. }
  203. /**
  204. * Include template
  205. *
  206. * @param string $file
  207. * @param array|null $additionalParams
  208. * @return string returns content of included template
  209. *
  210. * Includes another template. use <?php echo $this->inc('template'); ?> to
  211. * do this.
  212. */
  213. public function inc( $file, $additionalParams = null ) {
  214. return $this->load($this->path.$file.'.php', $additionalParams);
  215. }
  216. /**
  217. * Shortcut to print a simple page for users
  218. * @param string $application The application we render the template for
  219. * @param string $name Name of the template
  220. * @param array $parameters Parameters for the template
  221. * @return boolean|null
  222. */
  223. public static function printUserPage( $application, $name, $parameters = array() ) {
  224. $content = new OC_Template( $application, $name, "user" );
  225. foreach( $parameters as $key => $value ) {
  226. $content->assign( $key, $value );
  227. }
  228. print $content->printPage();
  229. }
  230. /**
  231. * Shortcut to print a simple page for admins
  232. * @param string $application The application we render the template for
  233. * @param string $name Name of the template
  234. * @param array $parameters Parameters for the template
  235. * @return bool
  236. */
  237. public static function printAdminPage( $application, $name, $parameters = array() ) {
  238. $content = new OC_Template( $application, $name, "admin" );
  239. foreach( $parameters as $key => $value ) {
  240. $content->assign( $key, $value );
  241. }
  242. return $content->printPage();
  243. }
  244. /**
  245. * Shortcut to print a simple page for guests
  246. * @param string $application The application we render the template for
  247. * @param string $name Name of the template
  248. * @param array|string $parameters Parameters for the template
  249. * @return bool
  250. */
  251. public static function printGuestPage( $application, $name, $parameters = array() ) {
  252. $content = new OC_Template( $application, $name, "guest" );
  253. foreach( $parameters as $key => $value ) {
  254. $content->assign( $key, $value );
  255. }
  256. return $content->printPage();
  257. }
  258. /**
  259. * Print a fatal error page and terminates the script
  260. * @param string $error_msg The error message to show
  261. * @param string $hint An optional hint message - needs to be properly escape
  262. * @suppress PhanAccessMethodInternal
  263. */
  264. public static function printErrorPage( $error_msg, $hint = '' ) {
  265. if (\OC::$server->getAppManager()->isEnabledForUser('theming') && !\OC_App::isAppLoaded('theming')) {
  266. \OC_App::loadApp('theming');
  267. }
  268. if ($error_msg === $hint) {
  269. // If the hint is the same as the message there is no need to display it twice.
  270. $hint = '';
  271. }
  272. try {
  273. $content = new \OC_Template( '', 'error', 'error', false );
  274. $errors = array(array('error' => $error_msg, 'hint' => $hint));
  275. $content->assign( 'errors', $errors );
  276. $content->printPage();
  277. } catch (\Exception $e) {
  278. $logger = \OC::$server->getLogger();
  279. $logger->error("$error_msg $hint", ['app' => 'core']);
  280. $logger->logException($e, ['app' => 'core']);
  281. header(self::getHttpProtocol() . ' 500 Internal Server Error');
  282. header('Content-Type: text/plain; charset=utf-8');
  283. print("$error_msg $hint");
  284. }
  285. die();
  286. }
  287. /**
  288. * print error page using Exception details
  289. * @param Exception|Throwable $exception
  290. * @param bool $fetchPage
  291. * @return bool|string
  292. * @suppress PhanAccessMethodInternal
  293. */
  294. public static function printExceptionErrorPage($exception, $fetchPage = false) {
  295. try {
  296. $request = \OC::$server->getRequest();
  297. $content = new \OC_Template('', 'exception', 'error', false);
  298. $content->assign('errorClass', get_class($exception));
  299. $content->assign('errorMsg', $exception->getMessage());
  300. $content->assign('errorCode', $exception->getCode());
  301. $content->assign('file', $exception->getFile());
  302. $content->assign('line', $exception->getLine());
  303. $content->assign('trace', $exception->getTraceAsString());
  304. $content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
  305. $content->assign('remoteAddr', $request->getRemoteAddress());
  306. $content->assign('requestID', $request->getId());
  307. if ($fetchPage) {
  308. return $content->fetchPage();
  309. }
  310. $content->printPage();
  311. } catch (\Exception $e) {
  312. $logger = \OC::$server->getLogger();
  313. $logger->logException($exception, ['app' => 'core']);
  314. $logger->logException($e, ['app' => 'core']);
  315. header(self::getHttpProtocol() . ' 500 Internal Server Error');
  316. header('Content-Type: text/plain; charset=utf-8');
  317. print("Internal Server Error\n\n");
  318. print("The server encountered an internal error and was unable to complete your request.\n");
  319. print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
  320. print("More details can be found in the server log.\n");
  321. }
  322. die();
  323. }
  324. /**
  325. * This is only here to reduce the dependencies in case of an exception to
  326. * still be able to print a plain error message.
  327. *
  328. * Returns the used HTTP protocol.
  329. *
  330. * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
  331. * @internal Don't use this - use AppFramework\Http\Request->getHttpProtocol instead
  332. */
  333. protected static function getHttpProtocol() {
  334. $claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
  335. $validProtocols = [
  336. 'HTTP/1.0',
  337. 'HTTP/1.1',
  338. 'HTTP/2',
  339. ];
  340. if(in_array($claimedProtocol, $validProtocols, true)) {
  341. return $claimedProtocol;
  342. }
  343. return 'HTTP/1.1';
  344. }
  345. }