Completed
Push — master ( 684ee6...1bb552 )
by Morris
203:09 queued 174:55
created

OC_Template::getHttpProtocol()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 0
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 47 and the first side effect is on line 42.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bart Visscher <[email protected]>
6
 * @author Brice Maron <[email protected]>
7
 * @author Christoph Wurst <[email protected]>
8
 * @author Frank Karlitschek <[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 John Molakvoæ <[email protected]>
14
 * @author Jörn Friedrich Dreyer <[email protected]>
15
 * @author Lukas Reschke <[email protected]>
16
 * @author Marin Treselj <[email protected]>
17
 * @author Michael Letzgus <[email protected]>
18
 * @author Morris Jobke <[email protected]>
19
 * @author Robin Appelman <[email protected]>
20
 * @author Roeland Jago Douma <[email protected]>
21
 * @author Thomas Müller <[email protected]>
22
 * @author Vincent Petry <[email protected]>
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
40
use OC\TemplateLayout;
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 {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
48
49
	/** @var string */
50
	private $renderAs; // Create a full page?
51
52
	/** @var string */
53
	private $path; // The path to the template
54
55
	/** @var array */
56
	private $headers = array(); //custom headers
57
58
	/** @var string */
59
	protected $app; // app id
60
61
	protected static $initTemplateEngineFirstRun = true;
62
63
	/**
64
	 * Constructor
65
	 *
66
	 * @param string $app app providing the template
67
	 * @param string $name of the template file (without suffix)
68
	 * @param string $renderAs If $renderAs is set, OC_Template will try to
69
	 *                         produce a full page in the according layout. For
70
	 *                         now, $renderAs can be set to "guest", "user" or
71
	 *                         "admin".
72
	 * @param bool $registerCall = true
73
	 */
74
	public function __construct( $app, $name, $renderAs = "", $registerCall = true ) {
75
		// Read the selected theme from the config file
76
		self::initTemplateEngine($renderAs);
77
78
		$theme = OC_Util::getTheme();
79
80
		$requestToken = (OC::$server->getSession() && $registerCall) ? \OCP\Util::callRegister() : '';
81
82
		$parts = explode('/', $app); // fix translation when app is something like core/lostpassword
83
		$l10n = \OC::$server->getL10N($parts[0]);
84
		/** @var \OCP\Defaults $themeDefaults */
85
		$themeDefaults = \OC::$server->query(\OCP\Defaults::class);
86
87
		list($path, $template) = $this->findTemplate($theme, $app, $name);
88
89
		// Set the private data
90
		$this->renderAs = $renderAs;
91
		$this->path = $path;
92
		$this->app = $app;
93
94
		parent::__construct($template, $requestToken, $l10n, $themeDefaults);
95
	}
96
97
	/**
98
	 * @param string $renderAs
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('css-variables', null, true);
113
			OC_Util::addStyle('server', null, true);
114
			OC_Util::addStyle('jquery-ui-fixes',null,true);
115
			OC_Util::addVendorStyle('jquery-ui/themes/base/jquery-ui',null,true);
116
			OC_Util::addVendorStyle('select2/select2', null, true);
117
			OC_Util::addStyle('jquery.ocdialog');
118
			OC_Util::addTranslations("core", null, true);
119
			OC_Util::addStyle('search', 'results');
120
			OC_Util::addScript('search', 'search', true);
121
			OC_Util::addScript('search', 'searchprovider');
122
			OC_Util::addScript('merged-template-prepend', null, true);
123
			OC_Util::addScript('jquery-ui-fixes');
124
			OC_Util::addScript('files/fileinfo');
125
			OC_Util::addScript('files/client');
126
			OC_Util::addScript('contactsmenu');
127
128
			if (\OC::$server->getConfig()->getSystemValue('debug')) {
129
				// Add the stuff we need always
130
				// following logic will import all vendor libraries that are
131
				// specified in core/js/core.json
132
				$fileContent = file_get_contents(OC::$SERVERROOT . '/core/js/core.json');
133
				if($fileContent !== false) {
134
					$coreDependencies = json_decode($fileContent, true);
135
					foreach(array_reverse($coreDependencies['vendor']) as $vendorLibrary) {
136
						//remove trailing ".js" as addVendorScript will append it
137
						OC_Util::addVendorScript(
138
							substr($vendorLibrary, 0, -3),null,true);
139
						}
140
 				} else {
141
					throw new \Exception('Cannot read core/js/core.json');
142
				}
143
			} else {
144
				// Import all (combined) default vendor libraries
145
				OC_Util::addVendorScript('core', null, true);
146
			}
147
148
			if (\OC::$server->getRequest()->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE])) {
149
				// polyfill for btoa/atob for IE friends
150
				OC_Util::addVendorScript('base64/base64');
151
				// shim for the davclient.js library
152
				\OCP\Util::addScript('files/iedavclient');
153
			}
154
155
			self::$initTemplateEngineFirstRun = false;
156
		}
157
158
	}
159
160
161
	/**
162
	 * find the template with the given name
163
	 * @param string $name of the template file (without suffix)
164
	 *
165
	 * Will select the template file for the selected theme.
166
	 * Checking all the possible locations.
167
	 * @param string $theme
168
	 * @param string $app
169
	 * @return string[]
170
	 */
171
	protected function findTemplate($theme, $app, $name) {
172
		// Check if it is a app template or not.
173
		if( $app !== '' ) {
174
			$dirs = $this->getAppTemplateDirs($theme, $app, OC::$SERVERROOT, OC_App::getAppPath($app));
175
		} else {
176
			$dirs = $this->getCoreTemplateDirs($theme, OC::$SERVERROOT);
177
		}
178
		$locator = new \OC\Template\TemplateFileLocator( $dirs );
179
		$template = $locator->find($name);
180
		$path = $locator->getPath();
181
		return array($path, $template);
182
	}
183
184
	/**
185
	 * Add a custom element to the header
186
	 * @param string $tag tag name of the element
187
	 * @param array $attributes array of attributes for the element
188
	 * @param string $text the text content for the element. If $text is null then the
189
	 * element will be written as empty element. So use "" to get a closing tag.
190
	 */
191 View Code Duplication
	public function addHeader($tag, $attributes, $text=null) {
192
		$this->headers[]= array(
193
			'tag' => $tag,
194
			'attributes' => $attributes,
195
			'text' => $text
196
		);
197
	}
198
199
	/**
200
	 * Process the template
201
	 * @return boolean|string
202
	 *
203
	 * This function process the template. If $this->renderAs is set, it
204
	 * will produce a full page.
205
	 */
206
	public function fetchPage($additionalParams = null) {
207
		$data = parent::fetchPage($additionalParams);
208
209
		if( $this->renderAs ) {
210
			$page = new TemplateLayout($this->renderAs, $this->app);
211
212
			if(is_array($additionalParams)) {
213
				foreach ($additionalParams as $key => $value) {
214
					$page->assign($key, $value);
215
				}
216
			}
217
218
			// Add custom headers
219
			$headers = '';
220
			foreach(OC_Util::$headers as $header) {
221
				$headers .= '<'.\OCP\Util::sanitizeHTML($header['tag']);
222
				if ( strcasecmp($header['tag'], 'script') === 0 && in_array('src', array_map('strtolower', array_keys($header['attributes']))) ) {
223
					$headers .= ' defer';
224
				}
225
				foreach($header['attributes'] as $name=>$value) {
226
					$headers .= ' '.\OCP\Util::sanitizeHTML($name).'="'.\OCP\Util::sanitizeHTML($value).'"';
227
				}
228
				if ($header['text'] !== null) {
229
					$headers .= '>'.\OCP\Util::sanitizeHTML($header['text']).'</'.\OCP\Util::sanitizeHTML($header['tag']).'>';
230
				} else {
231
					$headers .= '/>';
232
				}
233
			}
234
235
			$page->assign('headers', $headers);
236
237
			$page->assign('content', $data);
238
			return $page->fetchPage($additionalParams);
0 ignored issues
show
Bug Compatibility introduced by
The expression $page->fetchPage($additionalParams); of type boolean|string adds the type boolean to the return on line 238 which is incompatible with the return type of the parent method OC\Template\Base::fetchPage of type string.
Loading history...
239
		}
240
241
		return $data;
242
	}
243
244
	/**
245
	 * Include template
246
	 *
247
	 * @param string $file
248
	 * @param array|null $additionalParams
249
	 * @return string returns content of included template
250
	 *
251
	 * Includes another template. use <?php echo $this->inc('template'); ?> to
252
	 * do this.
253
	 */
254
	public function inc( $file, $additionalParams = null ) {
255
		return $this->load($this->path.$file.'.php', $additionalParams);
256
	}
257
258
	/**
259
	 * Shortcut to print a simple page for users
260
	 * @param string $application The application we render the template for
261
	 * @param string $name Name of the template
262
	 * @param array $parameters Parameters for the template
263
	 * @return boolean|null
264
	 */
265 View Code Duplication
	public static function printUserPage( $application, $name, $parameters = array() ) {
266
		$content = new OC_Template( $application, $name, "user" );
267
		foreach( $parameters as $key => $value ) {
268
			$content->assign( $key, $value );
269
		}
270
		print $content->printPage();
271
	}
272
273
	/**
274
	 * Shortcut to print a simple page for admins
275
	 * @param string $application The application we render the template for
276
	 * @param string $name Name of the template
277
	 * @param array $parameters Parameters for the template
278
	 * @return bool
279
	 */
280 View Code Duplication
	public static function printAdminPage( $application, $name, $parameters = array() ) {
281
		$content = new OC_Template( $application, $name, "admin" );
282
		foreach( $parameters as $key => $value ) {
283
			$content->assign( $key, $value );
284
		}
285
		return $content->printPage();
286
	}
287
288
	/**
289
	 * Shortcut to print a simple page for guests
290
	 * @param string $application The application we render the template for
291
	 * @param string $name Name of the template
292
	 * @param array|string $parameters Parameters for the template
293
	 * @return bool
294
	 */
295 View Code Duplication
	public static function printGuestPage( $application, $name, $parameters = array() ) {
296
		$content = new OC_Template( $application, $name, "guest" );
297
		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...
298
			$content->assign( $key, $value );
299
		}
300
		return $content->printPage();
301
	}
302
303
	/**
304
	 * Print a fatal error page and terminates the script
305
	 * @param string $error_msg The error message to show
306
	 * @param string $hint An optional hint message - needs to be properly escape
307
	 * @param int $statusCode
308
	 * @suppress PhanAccessMethodInternal
309
	 */
310
	public static function printErrorPage( $error_msg, $hint = '', $statusCode = 500) {
311
		if (\OC::$server->getAppManager()->isEnabledForUser('theming') && !\OC_App::isAppLoaded('theming')) {
312
			\OC_App::loadApp('theming');
313
		}
314
315
316
		if ($error_msg === $hint) {
317
			// If the hint is the same as the message there is no need to display it twice.
318
			$hint = '';
319
		}
320
321
		http_response_code($statusCode);
322
		try {
323
			$content = new \OC_Template( '', 'error', 'error', false );
324
			$errors = array(array('error' => $error_msg, 'hint' => $hint));
325
			$content->assign( 'errors', $errors );
326
			$content->printPage();
327
		} catch (\Exception $e) {
328
			$logger = \OC::$server->getLogger();
329
			$logger->error("$error_msg $hint", ['app' => 'core']);
330
			$logger->logException($e, ['app' => 'core']);
0 ignored issues
show
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
331
332
			header('Content-Type: text/plain; charset=utf-8');
333
			print("$error_msg $hint");
334
		}
335
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method printErrorPage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
336
	}
337
338
	/**
339
	 * print error page using Exception details
340
	 * @param Exception|Throwable $exception
341
	 * @param int $statusCode
342
	 * @return bool|string
343
	 * @suppress PhanAccessMethodInternal
344
	 */
345
	public static function printExceptionErrorPage($exception, $statusCode = 503) {
346
		http_response_code($statusCode);
347
		try {
348
			$request = \OC::$server->getRequest();
349
			$content = new \OC_Template('', 'exception', 'error', false);
350
			$content->assign('errorClass', get_class($exception));
351
			$content->assign('errorMsg', $exception->getMessage());
352
			$content->assign('errorCode', $exception->getCode());
353
			$content->assign('file', $exception->getFile());
354
			$content->assign('line', $exception->getLine());
355
			$content->assign('trace', $exception->getTraceAsString());
356
			$content->assign('debugMode', \OC::$server->getSystemConfig()->getValue('debug', false));
357
			$content->assign('remoteAddr', $request->getRemoteAddress());
358
			$content->assign('requestID', $request->getId());
359
			$content->printPage();
360
		} catch (\Exception $e) {
361
			$logger = \OC::$server->getLogger();
362
			$logger->logException($exception, ['app' => 'core']);
0 ignored issues
show
Bug introduced by
It seems like $exception defined by parameter $exception on line 345 can also be of type object<Exception>; however, OCP\ILogger::logException() does only seem to accept object<Throwable>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
363
			$logger->logException($e, ['app' => 'core']);
0 ignored issues
show
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Throwable>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
364
365
			header('Content-Type: text/plain; charset=utf-8');
366
			print("Internal Server Error\n\n");
367
			print("The server encountered an internal error and was unable to complete your request.\n");
368
			print("Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.\n");
369
			print("More details can be found in the server log.\n");
370
		}
371
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The method printExceptionErrorPage() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
372
	}
373
}
374