Completed
Pull Request — master (#3992)
by Roeland
15:48
created

OC_Template::printUserPage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 7
Ratio 100 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 3
dl 7
loc 7
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Brice Maron <[email protected]>
7
 * @author Frank Karlitschek <[email protected]>
8
 * @author Hendrik Leppelsack <[email protected]>
9
 * @author Individual IT Services <[email protected]>
10
 * @author Jakob Sack <[email protected]>
11
 * @author Jan-Christoph Borchardt <[email protected]>
12
 * @author Joas Schilling <[email protected]>
13
 * @author Jörn Friedrich Dreyer <[email protected]>
14
 * @author Lukas Reschke <[email protected]>
15
 * @author Morris Jobke <[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
 * @license AGPL-3.0
23
 *
24
 * This code is free software: you can redistribute it and/or modify
25
 * it under the terms of the GNU Affero General Public License, version 3,
26
 * as published by the Free Software Foundation.
27
 *
28
 * This program is distributed in the hope that it will be useful,
29
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
 * GNU Affero General Public License for more details.
32
 *
33
 * You should have received a copy of the GNU Affero General Public License, version 3,
34
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
35
 *
36
 */
37
38
use OC\TemplateLayout;
39
40
require_once __DIR__.'/template/functions.php';
41
42
/**
43
 * This class provides the templates for ownCloud.
44
 */
45
class OC_Template extends \OC\Template\Base {
46
47
	/** @var string */
48
	private $renderAs; // Create a full page?
49
50
	/** @var string */
51
	private $path; // The path to the template
52
53
	/** @var array */
54
	private $headers = array(); //custom headers
55
56
	/** @var string */
57
	protected $app; // app id
58
59
	protected static $initTemplateEngineFirstRun = true;
60
61
	/**
62
	 * Constructor
63
	 *
64
	 * @param string $app app providing the template
65
	 * @param string $name of the template file (without suffix)
66
	 * @param string $renderAs If $renderAs is set, OC_Template will try to
67
	 *                         produce a full page in the according layout. For
68
	 *                         now, $renderAs can be set to "guest", "user" or
69
	 *                         "admin".
70
	 * @param bool $registerCall = true
71
	 */
72
	public function __construct( $app, $name, $renderAs = "", $registerCall = true ) {
73
		// Read the selected theme from the config file
74
		self::initTemplateEngine($renderAs);
75
76
		$theme = OC_Util::getTheme();
77
78
		$requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
79
80
		$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
81
		$l10n = \OC::$server->getL10N($parts[0]);
82
		$themeDefaults = \OC::$server->getThemingDefaults();
83
84
		list($path, $template) = $this->findTemplate($theme, $app, $name);
85
86
		// Set the private data
87
		$this->renderAs = $renderAs;
88
		$this->path = $path;
89
		$this->app = $app;
90
91
		parent::__construct($template, $requestToken, $l10n, $themeDefaults);
92
	}
93
94
	/**
95
	 * @param string $renderAs
96
	 */
97
	public static function initTemplateEngine($renderAs) {
98
		if (self::$initTemplateEngineFirstRun){
99
100
			//apps that started before the template initialization can load their own scripts/styles
101
			//so to make sure this scripts/styles here are loaded first we use OC_Util::addScript() with $prepend=true
102
			//meaning the last script/style in this list will be loaded first
103
			if (\OC::$server->getSystemConfig()->getValue ('installed', false) && $renderAs !== 'error' && !\OCP\Util::needUpgrade()) {
104
				if (\OC::$server->getConfig ()->getAppValue ( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax') {
105
					OC_Util::addScript ( 'backgroundjobs', null, true );
106
				}
107
			}
108
109
			OC_Util::addStyle('jquery-ui-fixes',null,true);
110
			OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
111
			OC_Util::addStyle('server', null, true);
112
113
			// avatars
114
			\OC_Util::addScript('jquery.avatar', null, true);
115
			\OC_Util::addScript('placeholder', null, true);
116
117
			OC_Util::addVendorScript('select2/select2');
118
			OC_Util::addVendorStyle('select2/select2', null, true);
119
			OC_Util::addScript('select2-toggleselect');
120
121
			OC_Util::addScript('oc-backbone', null, true);
122
			OC_Util::addVendorScript('core', 'backbone/backbone', true);
123
			OC_Util::addVendorScript('snapjs/dist/latest/snap', null, true);
124
			OC_Util::addScript('mimetypelist', null, true);
125
			OC_Util::addScript('mimetype', null, true);
126
			OC_Util::addScript("apps", null, true);
127
			OC_Util::addScript("oc-requesttoken", null, true);
128
			OC_Util::addScript('search', 'search', true);
129
			OC_Util::addScript("config", null, true);
130
			OC_Util::addScript("public/appconfig", null, true);
131
			OC_Util::addScript("eventsource", null, true);
132
			OC_Util::addScript("octemplate", null, true);
133
			OC_Util::addTranslations("core", null, true);
134
			OC_Util::addScript("l10n", null, true);
135
			OC_Util::addScript("js", null, true);
136
			OC_Util::addScript("oc-dialogs", null, true);
137
			OC_Util::addScript("jquery.ocdialog", null, true);
138
			OC_Util::addScript("jquery-ui-fixes");
139
			OC_Util::addStyle("jquery.ocdialog");
140
			OC_Util::addScript('files/fileinfo');
141
			OC_Util::addScript('files/client');
142
143
			// Add the stuff we need always
144
			// following logic will import all vendor libraries that are
145
			// specified in core/js/core.json
146
			$fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
147
			if($fileContent !== false) {
148
				$coreDependencies = json_decode($fileContent, true);
149
				foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
150
					// remove trailing ".js" as addVendorScript will append it
151
					OC_Util::addVendorScript(
152
							substr($vendorLibrary, 0, strlen($vendorLibrary) - 3),null,true);
153
				}
154
			} else {
155
				throw new \Exception('Cannot read core/js/core.json');
156
			}
157
158
			if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
159
				// polyfill for btoa/atob for IE friends
160
				OC_Util::addVendorScript('base64/base64');
161
				// shim for the davclient.js library
162
				\OCP\Util::addScript('files/iedavclient');
163
			}
164
165
			self::$initTemplateEngineFirstRun = false;
166
		}
167
168
	}
169
170
171
	/**
172
	 * find the template with the given name
173
	 * @param string $name of the template file (without suffix)
174
	 *
175
	 * Will select the template file for the selected theme.
176
	 * Checking all the possible locations.
177
	 * @param string $theme
178
	 * @param string $app
179
	 * @return string[]
180
	 */
181
	protected function findTemplate($theme, $app, $name) {
182
		// Check if it is a app template or not.
183
		if( $app !== '' ) {
184
			$dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
185
		} else {
186
			$dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
187
		}
188
		$locator = new \OC\Template\TemplateFileLocator( $dirs );
189
		$template = $locator->find($name);
190
		$path = $locator->getPath();
191
		return array($path, $template);
192
	}
193
194
	/**
195
	 * Add a custom element to the header
196
	 * @param string $tag tag name of the element
197
	 * @param array $attributes array of attributes for the element
198
	 * @param string $text the text content for the element. If $text is null then the
199
	 * element will be written as empty element. So use "" to get a closing tag.
200
	 */
201 View Code Duplication
	public function addHeader($tag, $attributes, $text=null) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
202
		$this->headers[]= array(
203
			'tag' => $tag,
204
			'attributes' => $attributes,
205
			'text' => $text
206
		);
207
	}
208
209
	/**
210
	 * Process the template
211
	 * @return boolean|string
212
	 *
213
	 * This function process the template. If $this->renderAs is set, it
214
	 * will produce a full page.
215
	 */
216
	public function fetchPage($additionalParams = null) {
217
		$data = parent::fetchPage($additionalParams);
218
219
		if( $this->renderAs ) {
220
			$page = new TemplateLayout($this->renderAs, $this->app);
221
222
			// Add custom headers
223
			$headers = '';
224
			foreach(OC_Util::$headers as $header) {
225
				$headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
226
				foreach($header['attributes'] as $name=>$value) {
227
					$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
228
				}
229
				if ($header['text'] !== null) {
230
					$headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
231
				} else {
232
					$headers .= '/>';
233
				}
234
			}
235
236
			$page->assign('headers', $headers);
237
238
			$page->assign('content', $data);
239
			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 239 which is incompatible with the return type of the parent method OC\Template\Base::fetchPage of type string.
Loading history...
240
		}
241
242
		return $data;
243
	}
244
245
	/**
246
	 * Include template
247
	 *
248
	 * @param string $file
249
	 * @param array|null $additionalParams
250
	 * @return string returns content of included template
251
	 *
252
	 * Includes another template. use <?php echo $this->inc('template'); ?> to
253
	 * do this.
254
	 */
255
	public function inc( $file, $additionalParams = null ) {
256
		return $this->load($this->path.$file.'.php', $additionalParams);
257
	}
258
259
	/**
260
	 * Shortcut to print a simple page for users
261
	 * @param string $application The application we render the template for
262
	 * @param string $name Name of the template
263
	 * @param array $parameters Parameters for the template
264
	 * @return boolean|null
265
	 */
266 View Code Duplication
	public static function printUserPage( $application, $name, $parameters = array() ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
267
		$content = new OC_Template( $application, $name, "user" );
268
		foreach( $parameters as $key => $value ) {
269
			$content->assign( $key, $value );
270
		}
271
		print $content->printPage();
272
	}
273
274
	/**
275
	 * Shortcut to print a simple page for admins
276
	 * @param string $application The application we render the template for
277
	 * @param string $name Name of the template
278
	 * @param array $parameters Parameters for the template
279
	 * @return bool
280
	 */
281 View Code Duplication
	public static function printAdminPage( $application, $name, $parameters = array() ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
282
		$content = new OC_Template( $application, $name, "admin" );
283
		foreach( $parameters as $key => $value ) {
284
			$content->assign( $key, $value );
285
		}
286
		return $content->printPage();
287
	}
288
289
	/**
290
	 * Shortcut to print a simple page for guests
291
	 * @param string $application The application we render the template for
292
	 * @param string $name Name of the template
293
	 * @param array|string $parameters Parameters for the template
294
	 * @return bool
295
	 */
296 View Code Duplication
	public static function printGuestPage( $application, $name, $parameters = array() ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
297
		$content = new OC_Template( $application, $name, "guest" );
298
		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...
299
			$content->assign( $key, $value );
300
		}
301
		return $content->printPage();
302
	}
303
304
	/**
305
		* Print a fatal error page and terminates the script
306
		* @param string $error_msg The error message to show
307
		* @param string $hint An optional hint message - needs to be properly escaped
308
		*/
309
	public static function printErrorPage( $error_msg, $hint = '' ) {
310
		if ($error_msg === $hint) {
311
			// If the hint is the same as the message there is no need to display it twice.
312
			$hint = '';
313
		}
314
315
		try {
316
			$content = new \OC_Template( '', 'error', 'error', false );
317
			$errors = array(array('error' => $error_msg, 'hint' => $hint));
318
			$content->assign( 'errors', $errors );
319
			$content->printPage();
320
		} catch (\Exception $e) {
321
			$logger = \OC::$server->getLogger();
322
			$logger->error("$error_msg $hint", ['app' => 'core']);
323
			$logger->logException($e, ['app' => 'core']);
324
325
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
326
			header('Content-Type: text/plain; charset=utf-8');
327
			print("$error_msg $hint");
328
		}
329
		die();
330
	}
331
332
	/**
333
	 * print error page using Exception details
334
	 * @param Exception | Throwable $exception
335
	 */
336
	public static function printExceptionErrorPage($exception, $fetchPage = false) {
337
		try {
338
			$request = \OC::$server->getRequest();
339
			$content = new \OC_Template('', 'exception', 'error', false);
340
			$content->assign('errorClass', get_class($exception));
341
			$content->assign('errorMsg', $exception->getMessage());
342
			$content->assign('errorCode', $exception->getCode());
343
			$content->assign('file', $exception->getFile());
344
			$content->assign('line', $exception->getLine());
345
			$content->assign('trace', $exception->getTraceAsString());
346
			$content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
347
			$content->assign('remoteAddr', $request->getRemoteAddress());
348
			$content->assign('requestID', $request->getId());
349
			if ($fetchPage) {
350
				return $content->fetchPage();
351
			}
352
			$content->printPage();
353
		} catch (\Exception $e) {
354
			$logger = \OC::$server->getLogger();
355
			$logger->logException($exception, ['app' => 'core']);
356
			$logger->logException($e, ['app' => 'core']);
357
358
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
359
			header('Content-Type: text/plain; charset=utf-8');
360
			print("Internal Server Error\n\n");
361
			print("The server encountered an internal error and was unable to complete your request.\n");
362
			print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
363
			print("More details can be found in the server log.\n");
364
		}
365
		die();
366
	}
367
368
	/**
369
	 * This is only here to reduce the dependencies in case of an exception to
370
	 * still be able to print a plain error message.
371
	 *
372
	 * Returns the used HTTP protocol.
373
	 *
374
	 * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
375
	 * @internal Don't use this - use AppFramework\Http\Request->getHttpProtocol instead
376
	 */
377 View Code Duplication
	protected static function getHttpProtocol() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
378
		$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
379
		$validProtocols = [
380
			'HTTP/1.0',
381
			'HTTP/1.1',
382
			'HTTP/2',
383
		];
384
		if(in_array($claimedProtocol, $validProtocols, true)) {
385
			return $claimedProtocol;
386
		}
387
		return 'HTTP/1.1';
388
	}
389
}
390