Completed
Pull Request — master (#27730)
by Victor
16:06
created

OC_Template::isAssetPipelineEnabled()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 37
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 21
nc 8
nop 0
dl 0
loc 37
rs 6.7272
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Adam Williamson <[email protected]>
4
 * @author Bart Visscher <[email protected]>
5
 * @author Brice Maron <[email protected]>
6
 * @author Frank Karlitschek <[email protected]>
7
 * @author Hendrik Leppelsack <[email protected]>
8
 * @author Individual IT Services <[email protected]>
9
 * @author Jakob Sack <[email protected]>
10
 * @author Jan-Christoph Borchardt <[email protected]>
11
 * @author Joas Schilling <[email protected]>
12
 * @author Jörn Friedrich Dreyer <[email protected]>
13
 * @author Lukas Reschke <[email protected]>
14
 * @author Morris Jobke <[email protected]>
15
 * @author phisch <[email protected]>
16
 * @author Raghu Nayyar <[email protected]>
17
 * @author Robin Appelman <[email protected]>
18
 * @author Roeland Jago Douma <[email protected]>
19
 * @author Thomas Müller <[email protected]>
20
 * @author Vincent Petry <[email protected]>
21
 *
22
 * @copyright Copyright (c) 2017, ownCloud GmbH
23
 * @license AGPL-3.0
24
 *
25
 * This code is free software: you can redistribute it and/or modify
26
 * it under the terms of the GNU Affero General Public License, version 3,
27
 * as published by the Free Software Foundation.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32
 * GNU Affero General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Affero General Public License, version 3,
35
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
36
 *
37
 */
38
39
use OC\TemplateLayout;
40
use OC\Theme\Theme;
41
42
require_once __DIR__.'/template/functions.php';
43
44
/**
45
 * This class provides the templates for ownCloud.
46
 */
47
class OC_Template extends \OC\Template\Base {
48
49
	/**
50
	 * @var string
51
	 */
52
	private $renderAs;
53
54
	/**
55
	 * @var array
56
	 */
57
	private $headers = [];
58
59
	/**
60
	 * @var string
61
	 */
62
	protected $app;
63
64
	/**
65
	 * @var bool
66
	 */
67
	protected static $initTemplateEngineFirstRun = true;
68
69
	/**
70
	 * Constructor
71
	 *
72
	 * @param string $app app providing the template
73
	 * @param string $name of the template file (without suffix)
74
	 * @param string $renderAs If $renderAs is set, OC_Template will try to
75
	 *                         produce a full page in the according layout. For
76
	 *                         now, $renderAs can be set to "guest", "user" or
77
	 *                         "admin".
78
	 * @param bool $registerCall = true
79
	 */
80
	public function __construct( $app, $name, $renderAs = "", $registerCall = true ) {
81
		self::initTemplateEngine($renderAs);
82
		$requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
83
84
		$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
85
		$l10n = \OC::$server->getL10N($parts[0]);
86
87
		$theme = OC_Util::getTheme();
88
		$template = $this->findTemplate($theme, $app, $name);
89
90
		$this->renderAs = $renderAs;
91
		$this->app = $app;
92
93
		parent::__construct($template, $requestToken, $l10n, $theme, new OC_Defaults());
94
	}
95
96
	/**
97
	 * @param string $renderAs
98
	 * @throws Exception
99
	 */
100
	public static function initTemplateEngine($renderAs) {
101
		if (self::$initTemplateEngineFirstRun){
102
103
			//apps that started before the template initialization can load their own scripts/styles
104
			//so to make sure this scripts/styles here are loaded first we use OC_Util::addScript() with $prepend=true
105
			//meaning the last script/style in this list will be loaded first
106
			if (\OC::$server->getSystemConfig()->getValue ('installed', false) && $renderAs !== 'error' && !\OCP\Util::needUpgrade()) {
107
				if (\OC::$server->getConfig ()->getAppValue ( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax') {
108
					OC_Util::addScript ( 'backgroundjobs', null, true );
109
				}
110
			}
111
112
			OC_Util::addStyle("tooltip",null,true);
113
			OC_Util::addStyle('jquery-ui-fixes',null,true);
114
			OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
115
			OC_Util::addStyle("mobile",null,true);
116
			OC_Util::addStyle("multiselect",null,true);
117
			OC_Util::addStyle("fixes",null,true);
118
			OC_Util::addStyle("global",null,true);
119
			OC_Util::addStyle("apps",null,true);
120
			OC_Util::addStyle("fonts",null,true);
121
			OC_Util::addStyle("icons",null,true);
122
			OC_Util::addStyle("header",null,true);
123
			OC_Util::addStyle("inputs",null,true);
124
			OC_Util::addStyle("styles",null,true);
125
126
			// avatars
127
			if (\OC::$server->getSystemConfig()->getValue('enable_avatars', true) === true) {
128
				\OC_Util::addScript('jquery.avatar', null, true);
129
				\OC_Util::addScript('placeholder', null, true);
130
			}
131
132
			OC_Util::addScript('oc-backbone', null, true);
133
			OC_Util::addVendorScript('core', 'backbone/backbone', true);
134
			OC_Util::addVendorScript('snapjs/dist/latest/snap', null, true);
135
			OC_Util::addScript('mimetypelist', null, true);
136
			OC_Util::addScript('mimetype', null, true);
137
			OC_Util::addScript("apps", null, true);
138
			OC_Util::addScript("oc-requesttoken", null, true);
139
			OC_Util::addScript('search', 'search', true);
140
			OC_Util::addScript("config", null, true);
141
			OC_Util::addScript("eventsource", null, true);
142
			OC_Util::addScript("octemplate", null, true);
143
			OC_Util::addTranslations("core", null, true);
144
			OC_Util::addScript("l10n", null, true);
145
			OC_Util::addScript("js", null, true);
146
			OC_Util::addScript("oc-dialogs", null, true);
147
			OC_Util::addScript("jquery.ocdialog", null, true);
148
			OC_Util::addStyle("jquery.ocdialog");
149
			OC_Util::addScript('files/fileinfo');
150
			OC_Util::addScript('files/client');
151
152
			// Add the stuff we need always
153
			// following logic will import all vendor libraries that are
154
			// specified in core/js/core.json
155
			$fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
156
			if($fileContent !== false) {
157
				$coreDependencies = json_decode($fileContent, true);
158
				foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
159
					// remove trailing ".js" as addVendorScript will append it
160
					OC_Util::addVendorScript(
161
							substr($vendorLibrary, 0, strlen($vendorLibrary) - 3),null,true);
162
				}
163
			} else {
164
				throw new \Exception('Cannot read core/js/core.json');
165
			}
166
167
			if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
168
				// polyfill for btoa/atob for IE friends
169
				OC_Util::addVendorScript('base64/base64');
170
				// shim for the davclient.js library
171
				\OCP\Util::addScript('files/iedavclient');
172
			}
173
174
			self::$initTemplateEngineFirstRun = false;
175
		}
176
177
	}
178
179
180
	/**
181
	 * find the template with the given name
182
	 * @param string $name of the template file (without suffix)
183
	 *
184
	 * Will select the template file for the selected theme.
185
	 * Checking all the possible locations.
186
	 * @param Theme $theme
187
	 * @param string $app
188
	 * @return string
189
	 */
190
	protected function findTemplate($theme, $app, $name) {
191
		// Check if it is a app template or not.
192
		if( $app !== '' && $app !== 'core' ) {
193
			$dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
194
		} else {
195
			$dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
196
		}
197
198
		$locator = new \OC\Template\TemplateFileLocator( $dirs );
199
		$template = $locator->find($name);
200
201
		return $template;
202
	}
203
204
	/**
205
	 * Add a custom element to the header
206
	 * @param string $tag tag name of the element
207
	 * @param array $attributes array of attributes for the element
208
	 * @param string $text the text content for the element. If $text is null then the
209
	 * element will be written as empty element. So use "" to get a closing tag.
210
	 */
211 View Code Duplication
	public function addHeader($tag, $attributes, $text=null) {
212
		$this->headers[]= [
213
			'tag' => $tag,
214
			'attributes' => $attributes,
215
			'text' => $text
216
		];
217
	}
218
219
	/**
220
	 * Process the template
221
	 * @return boolean|string
222
	 *
223
	 * This function process the template. If $this->renderAs is set, it
224
	 * will produce a full page.
225
	 */
226
	public function fetchPage($additionalParams = null) {
227
		$data = parent::fetchPage($additionalParams);
228
229
		if( $this->renderAs ) {
230
			$page = new TemplateLayout($this->renderAs, $this->app);
231
232
			// Add custom headers
233
			$headers = '';
234
			foreach(OC_Util::$headers as $header) {
235
				$headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
236
				foreach($header['attributes'] as $name=>$value) {
237
					$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
238
				}
239
				if ($header['text'] !== null) {
240
					$headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
241
				} else {
242
					$headers .= '/>';
243
				}
244
			}
245
246
			$page->assign('headers', $headers);
247
248
			$page->assign('content', $data);
249
			return $page->fetchPage();
0 ignored issues
show
Bug Compatibility introduced by
The expression $page->fetchPage(); of type boolean|string adds the type boolean to the return on line 249 which is incompatible with the return type of the parent method OC\Template\Base::fetchPage of type string.
Loading history...
250
		}
251
252
		return $data;
253
	}
254
255
	/**
256
	 * Include template
257
	 *
258
	 * @param string $file
259
	 * @param array|null $additionalParams
260
	 * @return string returns content of included template
261
	 *
262
	 * Includes another template. use <?php echo $this->inc('template'); ?> to
263
	 * do this.
264
	 */
265
	public function inc($file, $additionalParams = null) {
266
		$template = $this->findTemplate($this->theme, $this->app, $file);
267
		return $this->load($template, $additionalParams);
268
	}
269
270
	/**
271
	 * Shortcut to print a simple page for users
272
	 * @param string $application The application we render the template for
273
	 * @param string $name Name of the template
274
	 * @param array $parameters Parameters for the template
275
	 * @return boolean|null
276
	 */
277 View Code Duplication
	public static function printUserPage( $application, $name, $parameters = []) {
278
		$content = new OC_Template( $application, $name, "user" );
279
		foreach( $parameters as $key => $value ) {
280
			$content->assign( $key, $value );
281
		}
282
		print $content->printPage();
283
	}
284
285
	/**
286
	 * Shortcut to print a simple page for admins
287
	 * @param string $application The application we render the template for
288
	 * @param string $name Name of the template
289
	 * @param array $parameters Parameters for the template
290
	 * @return bool
291
	 */
292 View Code Duplication
	public static function printAdminPage( $application, $name, $parameters = []) {
293
		$content = new OC_Template( $application, $name, "admin" );
294
		foreach( $parameters as $key => $value ) {
295
			$content->assign( $key, $value );
296
		}
297
		return $content->printPage();
298
	}
299
300
	/**
301
	 * Shortcut to print a simple page for guests
302
	 * @param string $application The application we render the template for
303
	 * @param string $name Name of the template
304
	 * @param array|string $parameters Parameters for the template
305
	 * @return bool
306
	 */
307 View Code Duplication
	public static function printGuestPage( $application, $name, $parameters = []) {
308
		$content = new OC_Template( $application, $name, "guest" );
309
		foreach( $parameters as $key => $value ) {
0 ignored issues
show
Bug introduced by
The expression $parameters of type array|string is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
310
			$content->assign( $key, $value );
311
		}
312
		return $content->printPage();
313
	}
314
315
	/**
316
		* Print a fatal error page and terminates the script
317
		* @param string $error_msg The error message to show
318
		* @param string $hint An optional hint message - needs to be properly escaped
319
		*/
320
	public static function printErrorPage( $error_msg, $hint = '' ) {
321
		if ($error_msg === $hint) {
322
			// If the hint is the same as the message there is no need to display it twice.
323
			$hint = '';
324
		}
325
326
		try {
327
			$content = new \OC_Template( '', 'error', 'error', false );
328
			$errors = [['error' => $error_msg, 'hint' => $hint]];
329
			$content->assign( 'errors', $errors );
330
			$content->printPage();
331
		} catch (\Exception $e) {
332
			$logger = \OC::$server->getLogger();
333
			$logger->error("$error_msg $hint", ['app' => 'core']);
334
			$logger->logException($e, ['app' => 'core']);
335
336
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
337
			header('Content-Type: text/plain; charset=utf-8');
338
			print("$error_msg $hint");
339
		}
340
		die();
341
	}
342
343
	/**
344
	 * print error page using Exception details
345
	 * @param Exception | Throwable $exception
346
	 * @param bool $fetchPage
347
	 * @return bool|string
348
	 */
349
	public static function printExceptionErrorPage($exception, $fetchPage = false) {
350
		try {
351
			$request = \OC::$server->getRequest();
352
			$content = new \OC_Template('', 'exception', 'error', false);
353
			$content->assign('errorClass', get_class($exception));
354
			$content->assign('errorMsg', $exception->getMessage());
355
			$content->assign('errorCode', $exception->getCode());
356
			$content->assign('file', $exception->getFile());
357
			$content->assign('line', $exception->getLine());
358
			$content->assign('trace', $exception->getTraceAsString());
359
			$content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
360
			$content->assign('remoteAddr', $request->getRemoteAddress());
361
			$content->assign('requestID', $request->getId());
362
			if ($fetchPage) {
363
				return $content->fetchPage();
364
			}
365
			$content->printPage();
366
		} catch (\Exception $e) {
367
			$logger = \OC::$server->getLogger();
368
			$logger->logException($exception, ['app' => 'core']);
369
			$logger->logException($e, ['app' => 'core']);
370
371
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
372
			header('Content-Type: text/plain; charset=utf-8');
373
			print("Internal Server Error\n\n");
374
			print("The server encountered an internal error and was unable to complete your request.\n");
375
			print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
376
			print("More details can be found in the server log.\n");
377
		}
378
		die();
379
	}
380
381
	/**
382
	 * This is only here to reduce the dependencies in case of an exception to
383
	 * still be able to print a plain error message.
384
	 *
385
	 * Returns the used HTTP protocol.
386
	 *
387
	 * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
388
	 * @internal Don't use this - use AppFramework\Http\Request->getHttpProtocol instead
389
	 */
390 View Code Duplication
	protected static function getHttpProtocol() {
391
		$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
392
		$validProtocols = [
393
			'HTTP/1.0',
394
			'HTTP/1.1',
395
			'HTTP/2',
396
		];
397
		if(in_array($claimedProtocol, $validProtocols, true)) {
398
			return $claimedProtocol;
399
		}
400
		return 'HTTP/1.1';
401
	}
402
}
403