TYPO3  7.6
PreviewHook.php
Go to the documentation of this file.
1 <?php
2 namespace TYPO3\CMS\Version\Hook;
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
24 {
30  protected $previewKey = 'ADMCMD_prev';
31 
37  protected $tsfeObj;
38 
44  protected $previewConfiguration = false;
45 
54  public function checkForPreview($params, &$pObj)
55  {
56  $this->tsfeObj = $pObj;
57  $this->previewConfiguration = $this->getPreviewConfiguration();
58  if (is_array($this->previewConfiguration)) {
59  // In case of a keyword-authenticated preview,
60  // re-initialize the TSFE object:
61  // because the GET variables are taken from the preview
62  // configuration
63  $this->tsfeObj = GeneralUtility::makeInstance(
64  \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class,
65  $GLOBALS['TYPO3_CONF_VARS'],
66  GeneralUtility::_GP('id'),
67  GeneralUtility::_GP('type'),
68  GeneralUtility::_GP('no_cache'),
69  GeneralUtility::_GP('cHash'),
70  GeneralUtility::_GP('jumpurl'),
71  GeneralUtility::_GP('MP'),
72  GeneralUtility::_GP('RDCT')
73  );
74  $GLOBALS['TSFE'] = $this->tsfeObj;
75  // Configuration after initialization of TSFE object.
76  // Basically this unsets the BE cookie if any and forces
77  // the BE user set according to the preview configuration.
78  // @previouslyknownas TSFE->ADMCMD_preview_postInit
79  // Clear cookies:
80  unset($_COOKIE['be_typo_user']);
81  }
82  }
83 
93  public function initializePreviewUser(&$params, &$pObj)
94  {
95  if ((is_null($params['BE_USER']) || $params['BE_USER'] === false) && $this->previewConfiguration !== false && $this->previewConfiguration['BEUSER_uid'] > 0) {
96  // New backend user object
97  $BE_USER = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\FrontendBackendUserAuthentication::class);
98  $BE_USER->userTS_dontGetCached = 1;
99  $BE_USER->setBeUserByUid($this->previewConfiguration['BEUSER_uid']);
100  $BE_USER->unpack_uc('');
101  if ($BE_USER->user['uid']) {
102  $BE_USER->fetchGroupData();
103  $pObj->beUserLogin = true;
104  } else {
105  $BE_USER = null;
106  $pObj->beUserLogin = false;
107  }
108  $params['BE_USER'] = $BE_USER;
109  }
110  // if there is a valid BE user, and the full workspace should be
111  // previewed, the workspacePreview option shouldbe set
112  $workspaceUid = $this->previewConfiguration['fullWorkspace'];
113  if ($pObj->beUserLogin && is_object($params['BE_USER']) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($workspaceUid)) {
114  if ($workspaceUid == 0 || $workspaceUid >= -1 && $params['BE_USER']->checkWorkspace($workspaceUid)) {
115  // Check Access to workspace. Live (0) is OK to preview for all.
116  $pObj->workspacePreview = (int)$workspaceUid;
117  } else {
118  // No preview, will default to "Live" at the moment
119  $pObj->workspacePreview = -99;
120  }
121  }
122  }
123 
140  public function getPreviewConfiguration()
141  {
142  $inputCode = $this->getPreviewInputCode();
143  // If inputcode is available, look up the settings
144  if ($inputCode) {
145  // "log out"
146  if ($inputCode == 'LOGOUT') {
147  setcookie($this->previewKey, '', 0, GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
148  if ($this->tsfeObj->TYPO3_CONF_VARS['FE']['workspacePreviewLogoutTemplate']) {
149  $templateFile = PATH_site . $this->tsfeObj->TYPO3_CONF_VARS['FE']['workspacePreviewLogoutTemplate'];
150  if (@is_file($templateFile)) {
151  $message = GeneralUtility::getUrl(PATH_site . $this->tsfeObj->TYPO3_CONF_VARS['FE']['workspacePreviewLogoutTemplate']);
152  } else {
153  $message = '<strong>ERROR!</strong><br>Template File "'
154  . $this->tsfeObj->TYPO3_CONF_VARS['FE']['workspacePreviewLogoutTemplate']
155  . '" configured with $TYPO3_CONF_VARS["FE"]["workspacePreviewLogoutTemplate"] not found. Please contact webmaster about this problem.';
156  }
157  } else {
158  $message = 'You logged out from Workspace preview mode. Click this link to <a href="%1$s">go back to the website</a>';
159  }
160  $returnUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GET('returnUrl'));
161  die(sprintf($message, htmlspecialchars(preg_replace('/\\&?' . $this->previewKey . '=[[:alnum:]]+/', '', $returnUrl))));
162  }
163  // Look for keyword configuration record:
164  $where = 'keyword=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($inputCode, 'sys_preview') . ' AND endtime>' . $GLOBALS['EXEC_TIME'];
165  $previewData = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('*', 'sys_preview', $where);
166  // Get: Backend login status, Frontend login status
167  // - Make sure to remove fe/be cookies (temporarily);
168  // BE already done in ADMCMD_preview_postInit()
169  if (is_array($previewData)) {
170  if (empty(GeneralUtility::_POST())) {
171  // Unserialize configuration:
172  $previewConfig = unserialize($previewData['config']);
173  // For full workspace preview we only ADD a get variable
174  // to set the preview of the workspace - so all other Get
175  // vars are accepted. Hope this is not a security problem.
176  // Still posting is not allowed and even if a backend user
177  // get initialized it shouldn't lead to situations where
178  // users can use those credentials.
179  if ($previewConfig['fullWorkspace']) {
180  // Set the workspace preview value:
181  GeneralUtility::_GETset($previewConfig['fullWorkspace'], 'ADMCMD_previewWS');
182  // If ADMCMD_prev is set the $inputCode value cannot come
183  // from a cookie and we set that cookie here. Next time it will
184  // be found from the cookie if ADMCMD_prev is not set again...
185  if (GeneralUtility::_GP($this->previewKey)) {
186  // Lifetime is 1 hour, does it matter much?
187  // Requires the user to click the link from their email again if it expires.
188  SetCookie($this->previewKey, GeneralUtility::_GP($this->previewKey), 0, GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'));
189  }
190  return $previewConfig;
191  } elseif (GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'index.php?' . $this->previewKey . '=' . $inputCode === GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL')) {
192  // Set GET variables
193  $GET_VARS = '';
194  parse_str($previewConfig['getVars'], $GET_VARS);
195  GeneralUtility::_GETset($GET_VARS);
196  // Return preview keyword configuration
197  return $previewConfig;
198  } else {
199  // This check is to prevent people from setting additional
200  // GET vars via realurl or other URL path based ways of passing parameters.
201  throw new \Exception(htmlspecialchars('Request URL did not match "'
202  . GeneralUtility::getIndpEnv('TYPO3_SITE_URL') . 'index.php?' . $this->previewKey . '='
203  . $inputCode . '"', 1294585190));
204  }
205  } else {
206  throw new \Exception('POST requests are incompatible with keyword preview.', 1294585191);
207  }
208  } else {
209  throw new \Exception('ADMCMD command could not be executed! (No keyword configuration found)', 1294585192);
210  }
211  }
212  return false;
213  }
214 
220  protected function getPreviewInputCode()
221  {
222  $inputCode = GeneralUtility::_GP($this->previewKey);
223  // If no inputcode and a cookie is set, load input code from cookie:
224  if (!$inputCode && $_COOKIE[$this->previewKey]) {
225  $inputCode = $_COOKIE[$this->previewKey];
226  }
227  return $inputCode;
228  }
229 
244  public function compilePreviewKeyword($getVarsStr, $backendUserUid, $ttl = 172800, $fullWorkspace = null)
245  {
246  $fieldData = array(
247  'keyword' => md5(uniqid(microtime(), true)),
248  'tstamp' => $GLOBALS['EXEC_TIME'],
249  'endtime' => $GLOBALS['EXEC_TIME'] + $ttl,
250  'config' => serialize(array(
251  'fullWorkspace' => $fullWorkspace,
252  'getVars' => $getVarsStr,
253  'BEUSER_uid' => $backendUserUid
254  ))
255  );
256  $GLOBALS['TYPO3_DB']->exec_INSERTquery('sys_preview', $fieldData);
257  return $fieldData['keyword'];
258  }
259 
267  public function getPreviewLinkLifetime()
268  {
269  $ttlHours = (int)$GLOBALS['BE_USER']->getTSConfigVal('options.workspaces.previewLinkTTLHours');
270  return $ttlHours ? $ttlHours : 24 * 2;
271  }
272 }