Issues (106)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

Classes/Element.php (7 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace AOE\Languagevisibility;
4
5
/***************************************************************
6
 *  Copyright notice
7
 *
8
 *  (c) 2016 AOE GmbH <[email protected]>
9
 *
10
 *  All rights reserved
11
 *
12
 *  This script is part of the TYPO3 project. The TYPO3 project is
13
 *  free software; you can redistribute it and/or modify
14
 *  it under the terms of the GNU General Public License as published by
15
 *  the Free Software Foundation; either version 3 of the License, or
16
 *  (at your option) any later version.
17
 *
18
 *  The GNU General Public License can be found at
19
 *  http://www.gnu.org/copyleft/gpl.html.
20
 *
21
 *  This script is distributed in the hope that it will be useful,
22
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 *  GNU General Public License for more details.
25
 *
26
 *  This copyright notice MUST APPEAR in all copies of the script!
27
 ***************************************************************/
28
29
/**
30
 * Class tx_languagevisibility_element
31
 *
32
 * Abstract basis class for all elements (elements are any translateable records in the system)
33
 */
34
abstract class Element {
35
36
	/**
37
	 * @var string
38
	 */
39
	protected $table;
40
41
	/**
42
	 * @var string
43
	 */
44
	protected $row;
45
46
	/**
47
	 * This array holds the local visibility settings (from the 'tx_languagevisibility_visibility' field)
48
	 *
49
	 * @var array
50
	 */
51
	protected $localVisibilitySetting;
52
53
	/**
54
	 * This array holds the global visibility setting, the global visibility setting. The translation of an element can overwrite
55
	 * the visibility of its own language.
56
	 *
57
	 * @var array
58
	 */
59
	protected $overlayVisibilitySetting;
60
61
	/**
62
	 * @var \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
63
	 */
64
	protected $cache = NULL;
65
66
	/**
67
	 * @param string $row
68
	 * @param string $tablename
69
	 * @throws \AOE\Languagevisibility\Exceptions\InvalidRowException
70
	 * @return \AOE\Languagevisibility\Element
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
71
	 */
72
	public function __construct($row, $tablename = '') {
73
		if ((!is_array($row)) || !$this->isRowOriginal($row)) {
74
			throw new Exceptions\InvalidRowException();
75
		}
76
77
		$this->row = $row;
0 ignored issues
show
Documentation Bug introduced by
It seems like $row of type array is incompatible with the declared type string of property $row.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
78
79
		$cacheKey = NULL;
80
		if ($tablename && array_key_exists('uid', $this->row) && $this->row['uid'] > 0) {
81
			$cacheKey = sha1(implode('_', array(get_class($this), $tablename, $this->row['uid'])));
82
		}
83
84
		if ($cacheKey && $this->getCache()->has($cacheKey)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
85
			$this->localVisibilitySetting = $this->getCache()->get($cacheKey);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->getCache()->get($cacheKey) of type * is incompatible with the declared type array of property $localVisibilitySetting.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
86
		} elseif ($cacheKey) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $cacheKey of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
87
			$this->localVisibilitySetting = @unserialize($this->row['tx_languagevisibility_visibility']);
88
			$this->getCache()->set($cacheKey, $this->localVisibilitySetting);
89
		} else {
90
			$this->localVisibilitySetting = @unserialize($this->row['tx_languagevisibility_visibility']);
91
		}
92
93
		if (!is_array($this->localVisibilitySetting)) {
94
			$this->localVisibilitySetting = array();
95
		}
96
97
		if (!is_array($this->overlayVisibilitySetting)) {
98
			$this->overlayVisibilitySetting = array();
99
		}
100
101
		$this->initialisations();
102
	}
103
104
	/**
105
	 * Sets the table name
106
	 *
107
	 * @param string $table
108
	 * @return void
109
	 */
110
	public function setTable($table) {
111
		$this->table = $table;
112
	}
113
114
	/**
115
	 * Gets the table name
116
	 *
117
	 * @return string
118
	 */
119
	public function getTable() {
120
		return $this->table;
121
	}
122
123
	/**
124
	 * Method to determine that an Element will not be instantiated with
125
	 * data of an overlay.
126
	 */
127
	protected function isRowOriginal($row) {
128
		if (!isset($row['l18n_parent']) && !isset($row['l10n_parent'])) {
129
			return TRUE;
130
		}
131
		if (isset($row['l18n_parent']) && $row['l18n_parent'] == 0) {
132
			return TRUE;
133
		}
134
		if (isset($row['l10n_parent']) && $row['l10n_parent'] == 0) {
135
			return TRUE;
136
		}
137
		return FALSE;
138
	}
139
140
	/**
141
	 * possibility to add inits in subclasses
142
	 **/
143
	protected function initialisations() {
144
	}
145
146
	/**
147
	 * Returns the Uid of the Element
148
	 *
149
	 * @return int
150
	 */
151
	public function getUid() {
152
		return $this->row['uid'];
153
	}
154
155
	/**
156
	 * Returns the pid of the Element
157
	 *
158
	 * @return int
159
	 */
160
	public function getPid() {
161
		return $this->row['pid'];
162
	}
163
164
	/**
165
	 * Return the content of the title field
166
	 *
167
	 * @return unknown
168
	 */
169
	public function getTitle() {
170
		return $this->row['title'];
171
	}
172
173
	/**
174
	 * Returns the uid of the original element. This method will only return
175
	 * a non zero value if the element is an overlay;
176
	 *
177
	 * @return int
178
	 */
179
	public function getOrigElementUid() {
180
		if (isset($this->row['l18n_parent'])) {
181
			   return $this->row['l18n_parent'];
182
	   }
183
	   if (isset($this->row['l10n_parent'])) {
184
				return $this->row['l10n_parent'];
185
		}
186
	   return 0;
187
	}
188
189
	/**
190
	 * Returns the workspace uid of an element.
191
	 *
192
	 * @return unknown
193
	 */
194
	public function getWorkspaceUid() {
195
		$wsId = 0;
196
		if (isset($GLOBALS['TCA'][$this->table]['ctrl']['versioningWS']) && $GLOBALS['TCA'][$this->table]['ctrl']['versioningWS'] > 0) {
197
			$wsId = $this->row['t3ver_wsid'];
198
		}
199
		return $wsId;
200
	}
201
202
	/**
203
	 * Returns an description of the element.
204
	 *
205
	 * @return string
206
	 */
207
	public function getInformativeDescription() {
208
		if ($this->isMonolithicTranslated()) {
209
			 return 'this content element is not in default language. Its only visible in the selected language';
210
		}
211
		elseif ( $this->isLanguageSetToAll()) {
212
			return 'Language is set to all - element is visibily in every language';
213
		}
214
		elseif ( $this->isLanguageSetToDefault()) {
215
			return 'this is a normal content element (translations are managed with overlay records)';
216
217
		} else {
218
			return 'this content element is already a translated version therefore content overlays are not suppoted';
219
		}
220
	}
221
222
	/**
223
	 * This method is used to determine the visibility of the element. Technically it merges the visibility of
224
	 * the default language record and the overlay record and returns the visibility. The visibility in the overlayrecord
225
	 * can overwrite the visibility of its own language.
226
	 *
227
	 * @param $languageid
228
	 * @return string
229
	 */
230
	public function getLocalVisibilitySetting($languageid) {
231
		$overlayVisibility = $this->getVisibilitySettingStoredInOverlayRecord($languageid);
232
		$localVisibility = $this->getVisibilitySettingStoredInDefaultRecord($languageid);
233
234
		if ($overlayVisibility == 'no+' || $localVisibility == 'no+') {
235
			$res = 'no+';
236
		} elseif ($overlayVisibility == 'no') {
237
			$res = $overlayVisibility;
238
		} else {
239
			$res = $localVisibility;
240
		}
241
242
		return $res;
243
	}
244
245
	//make protected?
246
	/**
247
	 * Returns the global visibility setting for the element (saved in the overlay)
248
	 *
249
	 * @param $languageid
250
	 * @return string
251
	 */
252
	public function getVisibilitySettingStoredInOverlayRecord($languageid) {
253
			//if global visibility has not been determined, determine and cache it
254
		if (is_array($this->overlayVisibilitySetting)) {
255
			if (! isset($this->overlayVisibilitySetting[$languageid])) {
256
				$overlay = $this->getOverLayRecordForCertainLanguage($languageid);
257
				$overlayVisibilitySettings = @unserialize($overlay['tx_languagevisibility_visibility']);
258
259
				if (is_array($overlayVisibilitySettings)) {
260
					$this->overlayVisibilitySetting[$languageid] = $overlayVisibilitySettings[$languageid];
261
				} else {
262
					$this->overlayVisibilitySetting[$languageid] = '-';
263
				}
264
			}
265
		}
266
267
		return $this->overlayVisibilitySetting[$languageid];
268
	}
269
270
	/**
271
	 * This method is only need to display the visibility setting in the backend.
272
	 *
273
	 * @param int $languageid
274
	 * @return string
275
	 */
276
	public function getVisibilitySettingStoredInDefaultRecord($languageid) {
277
		return $this->localVisibilitySetting[$languageid];
278
	}
279
280
	/**
281
	 * This method returns an overlay of a record, independent from
282
	 * a frontend or backend context
283
	 *
284
	 * @param string $table
285
	 * @param string $olrow
286
	 * @return array
287
	 */
288
	protected function getContextIndependentWorkspaceOverlay($table, $olrow) {
289
		if (is_object($GLOBALS['TSFE']->sys_page)) {
290
			$GLOBALS['TSFE']->sys_page->versionOL($table, $olrow);
291
		} else {
292
			\TYPO3\CMS\Backend\Utility\BackendUtility::workspaceOL($table, $olrow);
0 ignored issues
show
$olrow is of type string, but the function expects a array.

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...
293
		}
294
295
		return $olrow;
296
	}
297
298
	/**
299
	 * receive relevant fallbackOrder
300
	 */
301
	public function getFallbackOrder(Language $language) {
302
		return $language->getFallbackOrder($this);
303
	}
304
305
306
	/**
307
	 * Check if the element is set to the default language
308
	 *
309
	 * @return boolean
310
	 */
311
	public function isLanguageSetToDefault() {
312
		return $this->row['sys_language_uid'] == '0';
313
	}
314
315
	/**
316
	 * Determines if the elements is a original or a overlay-element
317
	 *
318
	 * @return boolean
319
	 */
320
	protected function isOrigElement() {
321
		if ($this->getOrigElementUid() > 0 ) {
322
			return FALSE;
323
	   }
324
	   return TRUE;
325
	}
326
327
	/**
328
	 * Checks if the current record is set to language all (that is typically used to indicate that per default this element is visible in all langauges)
329
	 *
330
	 * @return boolean
331
	 */
332
	public function isLanguageSetToAll() {
333
		if ($this->row['sys_language_uid'] == '-1') {
334
			return TRUE;
335
		} else {
336
			return FALSE;
337
		}
338
	}
339
340
	/**
341
	 * Method to check the element is an Workspaceelement or not.
342
	 *
343
	 * @return boolean
344
	 */
345
	public function isLiveWorkspaceElement() {
346
		return ($this->row['pid'] != - 1);
347
	}
348
349
	/**
350
	 * Determines whether the element is a translated original record ...
351
	 *
352
	 * @return boolean
353
	 */
354
	public function isMonolithicTranslated() {
355
		/*
356
		 * Timo: this does not work with pages because pages do not have the field 'sys_language_uid'
357
		 * and the languagevisibility_pages class only represent elements from the table pages not
358
		 * from page_language_overlay
359
		 */
360
		return ( !$this->isLanguageSetToDefault()) && (!$this->isLanguageSetToAll())  && $this->isOrigElement();
361
	}
362
363
	/**
364
	 * Compare element-language and foreign language.
365
	 * @ todo make this method work for pages
366
	 *
367
	 * @param Language $language
368
	 * @return boolean
369
	 */
370
	public function languageEquals(Language $language) {
371
		return $this->row['sys_language_uid'] == $language->getUid();
372
	}
373
374
	/**
375
	 * Checks if this element has a translation, therefor several DB accesses are required
376
	 *
377
	 * @param $languageid
378
	 * @return boolean
379
	 */
380
	public function hasTranslation($languageid) {
381
382
		$result = FALSE;
383
		if (! is_numeric($languageid)) {
384
			$result = FALSE;
385
		} else if ($languageid == 0) {
386
			$result = TRUE;
387
		} else if ($this->_hasOverlayRecordForLanguage($languageid)) {
388
			$result = TRUE;
389
		}
390
391
		return $result;
392
	}
393
394
	/**
395
	 * Checks if this Element has a Translation in any workspace.
396
	 *
397
	 * @return boolean
398
	 */
399
	public function hasAnyTranslationInAnyWorkspace() {
400
		if ($this->hasOverLayRecordForAnyLanguageInAnyWorkspace()) {
401
			return TRUE;
402
		} else {
403
			return FALSE;
404
		}
405
	}
406
407
	/**
408
	 * This method can be used to determine if an overlay for a language exists.
409
	 *
410
	 * @return boolean
411
	 * @param int $langid
412
	 */
413
	protected function _hasOverlayRecordForLanguage($langid) {
414
		$row = $this->getOverLayRecordForCertainLanguage($langid, TRUE);
415
		return $row['uid'] != '';
416
	}
417
418
	/**
419
	 * Returns which field in the language should be used to read the default visibility
420
	 *
421
	 *@return string (blank=default / page=page)
422
	 **/
423
	public function getFieldToUseForDefaultVisibility() {
424
		return '';
425
	}
426
427
	/**
428
	 * Method to get a short description  of the elementtype.
429
	 * An extending class should overwrite this method.
430
	 *
431
	 * @return string
432
	 */
433
	public function getElementDescription() {
434
		return 'TYPO3 Element';
435
	}
436
437
	/**
438
	 * By default no element supports inheritance
439
	 *
440
	 * @param void
441
	 * @return boolean
442
	 */
443
	public function supportsInheritance() {
444
		return FALSE;
445
	}
446
447
	/**
448
	 * Gets the cache
449
	 *
450
	 * @return \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend
451
	 */
452
	protected function getCache() {
453
		if (!$this->cache) {
454
			$this->cache = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')
455
				->getCache('tx_languagevisibility');
456
		}
457
458
		return $this->cache;
459
	}
460
461
	/**
462
	 * This method is used to retrieve an overlay record of a given record.
463
	 *
464
	 * @param $languageId
465
	 * @param $onlyUid
466
	 * @return array
467
	 */
468
	public function getOverLayRecordForCertainLanguage($languageId, $onlyUid = FALSE) {
0 ignored issues
show
The parameter $onlyUid is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
469
		//get caching hints
470
		$table = $this->getTable();
471
		$uid = $this->getUid();
472
		$workspace = intval($GLOBALS['BE_USER']->workspace);
473
474
		$cacheManager = CacheManager::getInstance();
475
476
		$cacheData = $cacheManager->get('overlayRecordCache');
477
		$isCacheEnabled = $cacheManager->isCacheEnabled();
478
		if (! $isCacheEnabled || ! isset($cacheData[$table][$uid][$languageId][$workspace])) {
479
			$cacheData[$table][$uid][$languageId][$workspace] = $this->getOverLayRecordForCertainLanguageImplementation($languageId);
480
			$cacheManager->set('overlayRecordCache', $cacheData);
481
		}
482
483
		return $cacheData[$table][$uid][$languageId][$workspace];
484
	}
485
486
	/**
487
	 * Check the records enableColumns
488
	 *
489
	 * @param  $row
490
	 * @return bool
491
	 */
492
	protected function getEnableFieldResult($row) {
493
		$ctrl = $GLOBALS['TCA'][$this->table]['ctrl'];
494
		$enabled = TRUE;
495
		if (is_array($ctrl['enablecolumns'])) {
496
			if ($ctrl['enablecolumns']['disabled']) {
497
				$enabled = $row[$ctrl['enablecolumns']['disabled']] == 0;
498
			}
499
			if ($ctrl['enablecolumns']['starttime']) {
500
				$enabled &= $row[$ctrl['enablecolumns']['starttime']] <= $GLOBALS['SIM_ACCESS_TIME'];
501
			}
502
			if ($ctrl['enablecolumns']['endtime']) {
503
				$endtime = $row[$ctrl['enablecolumns']['endtime']];
504
				$enabled &= $endtime == 0 || $endtime > $GLOBALS['SIM_ACCESS_TIME'];
505
			}
506
507
			if ($ctrl['enablecolumns']['fe_group'] && is_object($GLOBALS['TSFE'])) {
508
				$fe_group = $row[$ctrl['enablecolumns']['fe_group']];
509
				if ($fe_group) {
510
					$currentUserGroups = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $GLOBALS['TSFE']->gr_list);
511
					$recordGroups = \TYPO3\CMS\Core\Utility\GeneralUtility::intExplode(',', $fe_group);
512
					$sharedGroups = array_intersect($recordGroups, $currentUserGroups);
513
					$enabled &= count($sharedGroups) > 0;
514
				}
515
			}
516
		}
517
		return $enabled;
518
	}
519
520
	/**
521
	 * Abstract method to determine if there exsists any translation in any workspace.
522
	 *
523
	 * @return boolean
524
	 */
525
	abstract public function hasOverLayRecordForAnyLanguageInAnyWorkspace();
526
527
	/**
528
	 * This method should provide the implementation to get the overlay of an element for a
529
	 * certain language. The result is cached be the method getOverLayRecordForCertainLanguage.
530
	 *
531
	 * @param int $languageId
532
	 * @return
533
	 */
534
	abstract protected function getOverLayRecordForCertainLanguageImplementation($languageId);
535
}
536