Completed
Push — master ( fecf72...7cc750 )
by Lukas
19:48 queued 07:22
created

OC_Template   B

Complexity

Total Complexity 38

Size/Duplication

Total Lines 335
Duplicated Lines 11.94 %

Coupling/Cohesion

Components 3
Dependencies 12

Importance

Changes 0
Metric Value
dl 40
loc 335
rs 8.3999
c 0
b 0
f 0
wmc 38
lcom 3
cbo 12

12 Methods

Rating   Name   Duplication   Size   Complexity  
A findTemplate() 0 12 2
A addHeader() 7 7 1
B fetchPage() 0 28 5
A inc() 0 3 1
A printUserPage() 7 7 2
A printAdminPage() 7 7 2
A printGuestPage() 7 7 2
A __construct() 0 22 3
C initTemplateEngine() 0 56 10
B printErrorPage() 0 27 5
B printExceptionErrorPage() 0 31 3
A getHttpProtocol() 12 12 2

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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
		/** @var \OCP\Defaults $themeDefaults */
83
		$themeDefaults = \OC::$server->query(\OCP\Defaults::class);
84
85
		list($path, $template) = $this->findTemplate($theme, $app, $name);
86
87
		// Set the private data
88
		$this->renderAs = $renderAs;
89
		$this->path = $path;
90
		$this->app = $app;
91
92
		parent::__construct($template, $requestToken, $l10n, $themeDefaults);
93
	}
94
95
	/**
96
	 * @param string $renderAs
97
	 */
98
	public static function initTemplateEngine($renderAs) {
99
		if (self::$initTemplateEngineFirstRun){
100
101
			//apps that started before the template initialization can load their own scripts/styles
102
			//so to make sure this scripts/styles here are loaded first we use OC_Util::addScript() with $prepend=true
103
			//meaning the last script/style in this list will be loaded first
104
			if (\OC::$server->getSystemConfig()->getValue ('installed', false) && $renderAs !== 'error' && !\OCP\Util::needUpgrade()) {
105
				if (\OC::$server->getConfig ()->getAppValue ( 'core', 'backgroundjobs_mode', 'ajax' ) == 'ajax') {
106
					OC_Util::addScript ( 'backgroundjobs', null, true );
107
				}
108
			}
109
110
			OC_Util::addStyle('jquery-ui-fixes',null,true);
111
			OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
112
			OC_Util::addStyle('server', null, true);
113
			OC_Util::addVendorStyle('select2/select2', null, true);
114
			OC_Util::addStyle('jquery.ocdialog');
115
			OC_Util::addTranslations("core", null, true);
116
			OC_Util::addScript('search', 'search', true);
117
			OC_Util::addScript('merged-template-prepend', null, true);
118
			OC_Util::addScript('jquery-ui-fixes');
119
			OC_Util::addScript('files/fileinfo');
120
			OC_Util::addScript('files/client');
121
			OC_Util::addScript('contactsmenu');
122
123
			if (\OC::$server->getConfig()->getSystemValue('debug')) {
124
				// Add the stuff we need always
125
				// following logic will import all vendor libraries that are
126
				// specified in core/js/core.json
127
				$fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
128
				if($fileContent !== false) {
129
					$coreDependencies = json_decode($fileContent, true);
130
					foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
131
						//remove trailing ".js" as addVendorScript will append it
132
						OC_Util::addVendorScript(
133
							substr($vendorLibrary, 0, strlen($vendorLibrary) - 3),null,true);
134
						}
135
 				} else {
136
					throw new \Exception('Cannot read core/js/core.json');
137
				}
138
			} else {
139
				// Import all (combined) default vendor libraries
140
				OC_Util::addVendorScript('core', null, true);
141
			}
142
143
			if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
144
				// polyfill for btoa/atob for IE friends
145
				OC_Util::addVendorScript('base64/base64');
146
				// shim for the davclient.js library
147
				\OCP\Util::addScript('files/iedavclient');
148
			}
149
150
			self::$initTemplateEngineFirstRun = false;
151
		}
152
153
	}
154
155
156
	/**
157
	 * find the template with the given name
158
	 * @param string $name of the template file (without suffix)
159
	 *
160
	 * Will select the template file for the selected theme.
161
	 * Checking all the possible locations.
162
	 * @param string $theme
163
	 * @param string $app
164
	 * @return string[]
165
	 */
166
	protected function findTemplate($theme, $app, $name) {
167
		// Check if it is a app template or not.
168
		if( $app !== '' ) {
169
			$dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
170
		} else {
171
			$dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
172
		}
173
		$locator = new \OC\Template\TemplateFileLocator( $dirs );
174
		$template = $locator->find($name);
175
		$path = $locator->getPath();
176
		return array($path, $template);
177
	}
178
179
	/**
180
	 * Add a custom element to the header
181
	 * @param string $tag tag name of the element
182
	 * @param array $attributes array of attributes for the element
183
	 * @param string $text the text content for the element. If $text is null then the
184
	 * element will be written as empty element. So use "" to get a closing tag.
185
	 */
186 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...
187
		$this->headers[]= array(
188
			'tag' => $tag,
189
			'attributes' => $attributes,
190
			'text' => $text
191
		);
192
	}
193
194
	/**
195
	 * Process the template
196
	 * @return boolean|string
197
	 *
198
	 * This function process the template. If $this->renderAs is set, it
199
	 * will produce a full page.
200
	 */
201
	public function fetchPage($additionalParams = null) {
202
		$data = parent::fetchPage($additionalParams);
203
204
		if( $this->renderAs ) {
205
			$page = new TemplateLayout($this->renderAs, $this->app);
206
207
			// Add custom headers
208
			$headers = '';
209
			foreach(OC_Util::$headers as $header) {
210
				$headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
211
				foreach($header['attributes'] as $name=>$value) {
212
					$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
213
				}
214
				if ($header['text'] !== null) {
215
					$headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
216
				} else {
217
					$headers .= '/>';
218
				}
219
			}
220
221
			$page->assign('headers', $headers);
222
223
			$page->assign('content', $data);
224
			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 224 which is incompatible with the return type of the parent method OC\Template\Base::fetchPage of type string.
Loading history...
225
		}
226
227
		return $data;
228
	}
229
230
	/**
231
	 * Include template
232
	 *
233
	 * @param string $file
234
	 * @param array|null $additionalParams
235
	 * @return string returns content of included template
236
	 *
237
	 * Includes another template. use <?php echo $this->inc('template'); ?> to
238
	 * do this.
239
	 */
240
	public function inc( $file, $additionalParams = null ) {
241
		return $this->load($this->path.$file.'.php', $additionalParams);
242
	}
243
244
	/**
245
	 * Shortcut to print a simple page for users
246
	 * @param string $application The application we render the template for
247
	 * @param string $name Name of the template
248
	 * @param array $parameters Parameters for the template
249
	 * @return boolean|null
250
	 */
251 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...
252
		$content = new OC_Template( $application, $name, "user" );
253
		foreach( $parameters as $key => $value ) {
254
			$content->assign( $key, $value );
255
		}
256
		print $content->printPage();
257
	}
258
259
	/**
260
	 * Shortcut to print a simple page for admins
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 bool
265
	 */
266 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...
267
		$content = new OC_Template( $application, $name, "admin" );
268
		foreach( $parameters as $key => $value ) {
269
			$content->assign( $key, $value );
270
		}
271
		return $content->printPage();
272
	}
273
274
	/**
275
	 * Shortcut to print a simple page for guests
276
	 * @param string $application The application we render the template for
277
	 * @param string $name Name of the template
278
	 * @param array|string $parameters Parameters for the template
279
	 * @return bool
280
	 */
281 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...
282
		$content = new OC_Template( $application, $name, "guest" );
283
		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...
284
			$content->assign( $key, $value );
285
		}
286
		return $content->printPage();
287
	}
288
289
	/**
290
		* Print a fatal error page and terminates the script
291
		* @param string $error_msg The error message to show
292
		* @param string $hint An optional hint message - needs to be properly escaped
293
		*/
294
	public static function printErrorPage( $error_msg, $hint = '' ) {
295
		if (\OC_App::isEnabled('theming') && !\OC_App::isAppLoaded('theming')) {
296
			\OC_App::loadApp('theming');
297
		}
298
299
300
		if ($error_msg === $hint) {
301
			// If the hint is the same as the message there is no need to display it twice.
302
			$hint = '';
303
		}
304
305
		try {
306
			$content = new \OC_Template( '', 'error', 'error', false );
307
			$errors = array(array('error' => $error_msg, 'hint' => $hint));
308
			$content->assign( 'errors', $errors );
309
			$content->printPage();
310
		} catch (\Exception $e) {
311
			$logger = \OC::$server->getLogger();
312
			$logger->error("$error_msg $hint", ['app' => 'core']);
313
			$logger->logException($e, ['app' => 'core']);
314
315
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
316
			header('Content-Type: text/plain; charset=utf-8');
317
			print("$error_msg $hint");
318
		}
319
		die();
320
	}
321
322
	/**
323
	 * print error page using Exception details
324
	 * @param Exception | Throwable $exception
325
	 */
326
	public static function printExceptionErrorPage($exception, $fetchPage = false) {
327
		try {
328
			$request = \OC::$server->getRequest();
329
			$content = new \OC_Template('', 'exception', 'error', false);
330
			$content->assign('errorClass', get_class($exception));
331
			$content->assign('errorMsg', $exception->getMessage());
332
			$content->assign('errorCode', $exception->getCode());
333
			$content->assign('file', $exception->getFile());
334
			$content->assign('line', $exception->getLine());
335
			$content->assign('trace', $exception->getTraceAsString());
336
			$content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
337
			$content->assign('remoteAddr', $request->getRemoteAddress());
338
			$content->assign('requestID', $request->getId());
339
			if ($fetchPage) {
340
				return $content->fetchPage();
341
			}
342
			$content->printPage();
343
		} catch (\Exception $e) {
344
			$logger = \OC::$server->getLogger();
345
			$logger->logException($exception, ['app' => 'core']);
346
			$logger->logException($e, ['app' => 'core']);
347
348
			header(self::getHttpProtocol() . ' 500 Internal Server Error');
349
			header('Content-Type: text/plain; charset=utf-8');
350
			print("Internal Server Error\n\n");
351
			print("The server encountered an internal error and was unable to complete your request.\n");
352
			print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
353
			print("More details can be found in the server log.\n");
354
		}
355
		die();
356
	}
357
358
	/**
359
	 * This is only here to reduce the dependencies in case of an exception to
360
	 * still be able to print a plain error message.
361
	 *
362
	 * Returns the used HTTP protocol.
363
	 *
364
	 * @return string HTTP protocol. HTTP/2, HTTP/1.1 or HTTP/1.0.
365
	 * @internal Don't use this - use AppFramework\Http\Request->getHttpProtocol instead
366
	 */
367 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...
368
		$claimedProtocol = strtoupper($_SERVER['SERVER_PROTOCOL']);
369
		$validProtocols = [
370
			'HTTP/1.0',
371
			'HTTP/1.1',
372
			'HTTP/2',
373
		];
374
		if(in_array($claimedProtocol, $validProtocols, true)) {
375
			return $claimedProtocol;
376
		}
377
		return 'HTTP/1.1';
378
	}
379
}
380