TYPO3 CMS  TYPO3_6-2
TypoScriptFrontendController.php
Go to the documentation of this file.
1 <?php
3 
24 
43 
44  // CURRENT PAGE
45 
51  public $id = '';
52 
58  public $type = '';
59 
65  public $cHash = '';
66 
73  public $no_cache = FALSE;
74 
80  public $rootLine = '';
81 
86  public $page = '';
87 
94  public $contentPid = 0;
95 
103  protected $originalMountPointPage = NULL;
104 
112  protected $originalShortcutPage = NULL;
113 
120  public $sys_page = '';
121 
126  public $jumpurl = '';
127 
133  public $pageNotFound = 0;
134 
140  public $domainStartPage = 0;
141 
147  public $pageAccessFailureHistory = array();
148 
153  public $MP = '';
154 
159  public $RDCT = '';
160 
168  public $page_cache_reg1 = 0;
169 
177  public $siteScript = '';
178 
185  public $fe_user = '';
186 
194  public $loginUser = FALSE;
195 
203  public $gr_list = '';
204 
209  public $beUserLogin = FALSE;
210 
216  public $workspacePreview = 0;
217 
223  public $loginAllowedInBranch = TRUE;
224 
231 
238 
239  // PREVIEW
240 
249  public $fePreview = 0;
250 
257  public $showHiddenPage = FALSE;
258 
266  public $showHiddenRecords = FALSE;
267 
273  public $simUserGroup = 0;
274 
275  // CONFIGURATION
276 
282  public $TYPO3_CONF_VARS = array();
283 
289  public $config = '';
290 
291  // TEMPLATE / CACHE
292 
299  public $tmpl = NULL;
300 
307  public $cacheTimeOutDefault = FALSE;
308 
315  public $cacheContentFlag = FALSE;
316 
322  public $cacheExpires = 0;
323 
329  public $isClientCachable = FALSE;
330 
338  public $all = array();
339 
345  public $sPre = '';
346 
353  public $pSetup = '';
354 
361  public $newHash = '';
362 
371  public $getMethodUrlIdToken = '';
372 
381  public $no_cacheBeforePageGen = FALSE;
382 
389  public $tempContent = FALSE;
390 
396  public $forceTemplateParsing = FALSE;
397 
403  public $cHash_array = array();
404 
410  public $pagesTSconfig = '';
411 
412  // PAGE-GENERATION / cOBJ
413 
434  public $additionalHeaderData = array();
435 
440  public $additionalFooterData = array();
441 
449  public $additionalJavaScript = array();
450 
457  public $additionalCSS = array();
458 
467  public $JSeventFuncCalls = array(
468  'onmousemove' => array(),
469  'onmouseup' => array(),
470  'onkeydown' => array(),
471  'onkeyup' => array(),
472  'onkeypress' => array(),
473  'onload' => array(),
474  'onunload' => array()
475  );
476 
482  public $JSImgCode = '';
483 
489  public $divSection = '';
490 
497  public $defaultBodyTag = '<body>';
498 
499  // RENDERING configuration, settings from TypoScript is loaded into these
500  // vars. See pagegen.php
501 
507  public $debug = '';
508 
514  public $intTarget = '';
515 
521  public $extTarget = '';
522 
528  public $fileTarget = '';
529 
536  public $MP_defaults = array();
537 
544 
550  public $absRefPrefix = '';
551 
560  public $absRefPrefix_force = FALSE;
561 
568 
574  public $lockFilePath = '';
575 
581  public $ATagParams = '';
582 
590  public $sWordRegEx = '';
591 
598  public $sWordList = '';
599 
607  public $linkVars = '';
608 
616  public $excludeCHashVars = '';
617 
624  public $displayEditIcons = '';
625 
634 
643  public $sys_language_uid = 0;
644 
650  public $sys_language_mode = '';
651 
659 
668 
677 
678  // RENDERING data
679 
686  public $applicationData = array();
687 
692  public $register = array();
693 
700  public $registerStack = array();
701 
708  public $cObjectDepthCounter = 50;
709 
716  public $recordRegister = array();
717 
726  public $currentRecord = '';
727 
734  public $accessKey = array();
735 
742  public $imagesOnPage = array();
743 
751  public $lastImageInfo = array();
752 
759  public $uniqueCounter = 0;
760 
765  public $uniqueString = '';
766 
773  public $indexedDocTitle = '';
774 
781  public $altPageTitle = '';
782 
788  public $baseUrl = '';
789 
796  public $anchorPrefix = '';
797 
802  private $usedUniqueIds = array();
803 
810  public $cObj = '';
811 
812  // CONTENT accumulation
813 
818  public $content = '';
819 
820  // GENERAL
821 
827  public $clientInfo = '';
828 
833  public $scriptParseTime = 0;
834 
842  public $csConvObj;
843 
849  public $defaultCharSet = 'utf-8';
850 
856  public $renderCharset = '';
857 
865  public $metaCharset = '';
866 
872  public $localeCharset = '';
873 
874  // LANG
875 
881  public $lang = '';
882 
887  public $LL_labels_cache = array();
888 
893  public $LL_files_cache = array();
894 
902  protected $languageDependencies = array();
903 
911 
919 
923  protected $pageRenderer;
924 
931  protected $pageCache;
932 
936  protected $pageCacheTags = array();
937 
941  protected $cacheHash;
942 
948  protected $domainDataCache = array();
949 
967  public function __construct($TYPO3_CONF_VARS, $id, $type, $no_cache = '', $cHash = '', $jumpurl = '', $MP = '', $RDCT = '') {
968  // Setting some variables:
969  $this->TYPO3_CONF_VARS = $TYPO3_CONF_VARS;
970  $this->id = $id;
971  $this->type = $type;
972  if ($no_cache) {
973  if ($this->TYPO3_CONF_VARS['FE']['disableNoCacheParameter']) {
974  $warning = '&no_cache=1 has been ignored because $TYPO3_CONF_VARS[\'FE\'][\'disableNoCacheParameter\'] is set!';
975  $GLOBALS['TT']->setTSlogMessage($warning, 2);
976  } else {
977  $warning = '&no_cache=1 has been supplied, so caching is disabled! URL: "' . GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL') . '"';
978  $this->disableCache();
979  }
980  GeneralUtility::sysLog($warning, 'cms', GeneralUtility::SYSLOG_SEVERITY_WARNING);
981  }
982  $this->cHash = $cHash;
983  $this->jumpurl = $jumpurl;
984  $this->MP = $this->TYPO3_CONF_VARS['FE']['enable_mount_pids'] ? (string) $MP : '';
985  $this->RDCT = $RDCT;
986  $this->clientInfo = GeneralUtility::clientInfo();
987  $this->uniqueString = md5(microtime());
988  $this->csConvObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Charset\\CharsetConverter');
989  // Call post processing function for constructor:
990  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'])) {
991  $_params = array('pObj' => &$this);
992  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-PostProc'] as $_funcRef) {
993  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
994  }
995  }
996  $this->cacheHash = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\CacheHashCalculator');
997  $this->initCaches();
998  }
999 
1008  public function connectToDB() {
1009  try {
1010  $GLOBALS['TYPO3_DB']->connectDB();
1011  } catch (\RuntimeException $exception) {
1012  switch ($exception->getCode()) {
1013  case 1270853883:
1014  // Cannot connect to current database
1015  $message = 'Cannot connect to the configured database "' . TYPO3_db . '"';
1016  if ($this->checkPageUnavailableHandler()) {
1017  $this->pageUnavailableAndExit($message);
1018  } else {
1019  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1020  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message, 1301648782);
1021  }
1022  break;
1023  case 1270853884:
1024  // Username / password not accepted
1025  $message = 'The current username, password or host was not accepted when' . ' the connection to the database was attempted to be established!';
1026  if ($this->checkPageUnavailableHandler()) {
1027  $this->pageUnavailableAndExit($message);
1028  } else {
1029  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1030  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException('Database Error: ' . $message, 1301648945);
1031  }
1032  break;
1033  default:
1034  throw $exception;
1035  }
1036  }
1037  // Call post processing function for DB connection:
1038  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'])) {
1039  $_params = array('pObj' => &$this);
1040  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['connectToDB'] as $_funcRef) {
1041  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1042  }
1043  }
1044  }
1045 
1054  public function sendRedirect() {
1055  if ($this->RDCT) {
1056  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('params', 'cache_md5params', 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->RDCT, 'cache_md5params'));
1057  if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
1058  $this->updateMD5paramsRecord($this->RDCT);
1059  header('Location: ' . $row['params']);
1060  die;
1061  }
1062  }
1063  }
1064 
1070  public function getPageRenderer() {
1071  if (!isset($this->pageRenderer)) {
1072  $this->pageRenderer = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Page\\PageRenderer');
1073  $this->pageRenderer->setTemplateFile(PATH_tslib . 'templates/tslib_page_frontend.html');
1074  $this->pageRenderer->setBackPath(TYPO3_mainDir);
1075  }
1076  return $this->pageRenderer;
1077  }
1078 
1085  $this->pageRenderer = $pageRenderer;
1086  }
1087 
1088  /********************************************
1089  *
1090  * Initializing, resolving page id
1091  *
1092  ********************************************/
1098  protected function initCaches() {
1099  $this->pageCache = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_pages');
1100  }
1101 
1107  public function initFEuser() {
1108  $this->fe_user = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Authentication\\FrontendUserAuthentication');
1109  $this->fe_user->lockIP = $this->TYPO3_CONF_VARS['FE']['lockIP'];
1110  $this->fe_user->checkPid = $this->TYPO3_CONF_VARS['FE']['checkFeUserPid'];
1111  $this->fe_user->lifetime = (int)$this->TYPO3_CONF_VARS['FE']['lifetime'];
1112  // List of pid's acceptable
1113  $pid = GeneralUtility::_GP('pid');
1114  $this->fe_user->checkPid_value = $pid ? $GLOBALS['TYPO3_DB']->cleanIntList($pid) : 0;
1115  // Check if a session is transferred:
1116  if (GeneralUtility::_GP('FE_SESSION_KEY')) {
1117  $fe_sParts = explode('-', GeneralUtility::_GP('FE_SESSION_KEY'));
1118  // If the session key hash check is OK:
1119  if (md5(($fe_sParts[0] . '/' . $this->TYPO3_CONF_VARS['SYS']['encryptionKey'])) === (string)$fe_sParts[1]) {
1121  $_COOKIE[$cookieName] = $fe_sParts[0];
1122  if (isset($_SERVER['HTTP_COOKIE'])) {
1123  // See http://forge.typo3.org/issues/27740
1124  $_SERVER['HTTP_COOKIE'] .= ';' . $cookieName . '=' . $fe_sParts[0];
1125  }
1126  $this->fe_user->forceSetCookie = 1;
1127  $this->fe_user->dontSetCookie = FALSE;
1128  unset($cookieName);
1129  }
1130  }
1131  $this->fe_user->start();
1132  $this->fe_user->unpack_uc('');
1133  // Gets session data
1134  $this->fe_user->fetchSessionData();
1135  $recs = GeneralUtility::_GP('recs');
1136  // If any record registration is submitted, register the record.
1137  if (is_array($recs)) {
1138  $this->fe_user->record_registration($recs, $this->TYPO3_CONF_VARS['FE']['maxSessionDataSize']);
1139  }
1140  // Call hook for possible manipulation of frontend user object
1141  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'])) {
1142  $_params = array('pObj' => &$this);
1143  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['initFEuser'] as $_funcRef) {
1144  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1145  }
1146  }
1147  // For every 60 seconds the is_online timestamp is updated.
1148  if (is_array($this->fe_user->user) && $this->fe_user->user['uid'] && $this->fe_user->user['is_online'] < $GLOBALS['EXEC_TIME'] - 60) {
1149  $GLOBALS['TYPO3_DB']->exec_UPDATEquery('fe_users', 'uid=' . (int)$this->fe_user->user['uid'], array('is_online' => $GLOBALS['EXEC_TIME']));
1150  }
1151  }
1152 
1160  public function initUserGroups() {
1161  // This affects the hidden-flag selecting the fe_groups for the user!
1162  $this->fe_user->showHiddenRecords = $this->showHiddenRecords;
1163  // no matter if we have an active user we try to fetch matching groups which can be set without an user (simulation for instance!)
1164  $this->fe_user->fetchGroupData();
1165  if (is_array($this->fe_user->user) && count($this->fe_user->groupData['uid'])) {
1166  // global flag!
1167  $this->loginUser = TRUE;
1168  // group -2 is not an existing group, but denotes a 'default' group when a user IS logged in. This is used to let elements be shown for all logged in users!
1169  $this->gr_list = '0,-2';
1170  $gr_array = $this->fe_user->groupData['uid'];
1171  } else {
1172  $this->loginUser = FALSE;
1173  // group -1 is not an existing group, but denotes a 'default' group when not logged in. This is used to let elements be hidden, when a user is logged in!
1174  $this->gr_list = '0,-1';
1175  if ($this->loginAllowedInBranch) {
1176  // For cases where logins are not banned from a branch usergroups can be set based on IP masks so we should add the usergroups uids.
1177  $gr_array = $this->fe_user->groupData['uid'];
1178  } else {
1179  // Set to blank since we will NOT risk any groups being set when no logins are allowed!
1180  $gr_array = array();
1181  }
1182  }
1183  // Clean up.
1184  // Make unique...
1185  $gr_array = array_unique($gr_array);
1186  // sort
1187  sort($gr_array);
1188  if (count($gr_array) && !$this->loginAllowedInBranch_mode) {
1189  $this->gr_list .= ',' . implode(',', $gr_array);
1190  }
1191  if ($this->fe_user->writeDevLog) {
1192  GeneralUtility::devLog('Valid usergroups for TSFE: ' . $this->gr_list, 'TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController');
1193  }
1194  }
1195 
1202  public function isUserOrGroupSet() {
1203  return is_array($this->fe_user->user) || $this->gr_list !== '0,-1';
1204  }
1205 
1215  public function checkAlternativeIdMethods() {
1216  $this->siteScript = GeneralUtility::getIndpEnv('TYPO3_SITE_SCRIPT');
1217  // Call post processing function for custom URL methods.
1218  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'])) {
1219  $_params = array('pObj' => &$this);
1220  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkAlternativeIdMethods-PostProc'] as $_funcRef) {
1221  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1222  }
1223  }
1224  }
1225 
1233  public function clear_preview() {
1234  $this->showHiddenPage = FALSE;
1235  $this->showHiddenRecords = FALSE;
1236  $GLOBALS['SIM_EXEC_TIME'] = $GLOBALS['EXEC_TIME'];
1237  $GLOBALS['SIM_ACCESS_TIME'] = $GLOBALS['ACCESS_TIME'];
1238  $this->fePreview = 0;
1239  }
1240 
1246  public function isBackendUserLoggedIn() {
1247  return (bool)$this->beUserLogin;
1248  }
1249 
1255  public function initializeBackendUser() {
1256  // PRE BE_USER HOOK
1257  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'])) {
1258  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['preBeUser'] as $_funcRef) {
1259  $_params = array();
1260  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1261  }
1262  }
1264  $BE_USER = NULL;
1265  // If the backend cookie is set,
1266  // we proceed and check if a backend user is logged in.
1267  if ($_COOKIE[\TYPO3\CMS\Core\Authentication\BackendUserAuthentication::getCookieName()]) {
1268  $GLOBALS['TYPO3_MISC']['microtime_BE_USER_start'] = microtime(TRUE);
1269  $GLOBALS['TT']->push('Back End user initialized', '');
1270  // TODO: validate the comment below: is this necessary? if so,
1271  // formfield_status should be set to "" in \TYPO3\CMS\Backend\FrontendBackendUserAuthentication
1272  // which is a subclass of \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
1273  // ----
1274  // the value this->formfield_status is set to empty in order to
1275  // disable login-attempts to the backend account through this script
1276  // New backend user object
1277  $BE_USER = GeneralUtility::makeInstance('TYPO3\\CMS\\Backend\\FrontendBackendUserAuthentication');
1278  $BE_USER->OS = TYPO3_OS;
1279  $BE_USER->lockIP = $this->TYPO3_CONF_VARS['BE']['lockIP'];
1280  // Object is initialized
1281  $BE_USER->start();
1282  $BE_USER->unpack_uc('');
1283  if (!empty($BE_USER->user['uid'])) {
1284  $BE_USER->fetchGroupData();
1285  $this->beUserLogin = TRUE;
1286  }
1287  // Unset the user initialization.
1288  if (!$BE_USER->checkLockToIP() || !$BE_USER->checkBackendAccessSettingsFromInitPhp() || empty($BE_USER->user['uid'])) {
1289  $BE_USER = NULL;
1290  $this->beUserLogin = FALSE;
1291  $_SESSION['TYPO3-TT-start'] = FALSE;
1292  }
1293  $GLOBALS['TT']->pull();
1294  $GLOBALS['TYPO3_MISC']['microtime_BE_USER_end'] = microtime(TRUE);
1295  }
1296  // POST BE_USER HOOK
1297  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'])) {
1298  $_params = array(
1299  'BE_USER' => &$BE_USER
1300  );
1301  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/index_ts.php']['postBeUser'] as $_funcRef) {
1302  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1303  }
1304  }
1305  return $BE_USER;
1306  }
1307 
1314  public function determineId() {
1315  // Call pre processing function for id determination
1316  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'])) {
1317  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PreProcessing'] as $functionReference) {
1318  $parameters = array('parentObject' => $this);
1319  GeneralUtility::callUserFunction($functionReference, $parameters, $this);
1320  }
1321  }
1322  // Getting ARG-v values if some
1323  $this->setIDfromArgV();
1324  // If there is a Backend login we are going to check for any preview settings:
1325  $GLOBALS['TT']->push('beUserLogin', '');
1326  $originalFrontendUser = NULL;
1327  if ($this->beUserLogin || $this->doWorkspacePreview()) {
1328  // Backend user preview features:
1329  if ($this->beUserLogin && $GLOBALS['BE_USER']->adminPanel instanceof \TYPO3\CMS\Frontend\View\AdminPanelView) {
1330  $this->fePreview = (bool)$GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview');
1331  // If admin panel preview is enabled...
1332  if ($this->fePreview) {
1333  if ($this->fe_user->user) {
1334  $originalFrontendUser = $this->fe_user->user;
1335  }
1336  $this->showHiddenPage = (bool)$GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview', 'showHiddenPages');
1337  $this->showHiddenRecords = (bool)$GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview', 'showHiddenRecords');
1338  // Simulate date
1339  $simTime = $GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview', 'simulateDate');
1340  if ($simTime) {
1341  $GLOBALS['SIM_EXEC_TIME'] = $simTime;
1342  $GLOBALS['SIM_ACCESS_TIME'] = $simTime - $simTime % 60;
1343  }
1344  // simulate user
1345  $simUserGroup = $GLOBALS['BE_USER']->adminPanel->extGetFeAdminValue('preview', 'simulateUserGroup');
1346  $this->simUserGroup = $simUserGroup;
1347  if ($simUserGroup) {
1348  if ($this->fe_user->user) {
1349  $this->fe_user->user[$this->fe_user->usergroup_column] = $simUserGroup;
1350  } else {
1351  $this->fe_user->user = array(
1352  $this->fe_user->usergroup_column => $simUserGroup
1353  );
1354  }
1355  }
1356  if (!$simUserGroup && !$simTime && !$this->showHiddenPage && !$this->showHiddenRecords) {
1357  $this->fePreview = 0;
1358  }
1359  }
1360  }
1361  if ($this->id) {
1362  if ($this->determineIdIsHiddenPage()) {
1363  // The preview flag is set only if the current page turns out to actually be hidden!
1364  $this->fePreview = 1;
1365  $this->showHiddenPage = TRUE;
1366  }
1367  // For Live workspace: Check root line for proper connection to tree root (done because of possible preview of page / branch versions)
1368  if (!$this->fePreview && $this->whichWorkspace() === 0) {
1369  // Initialize the page-select functions to check rootline:
1370  $temp_sys_page = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1371  $temp_sys_page->init($this->showHiddenPage);
1372  // If root line contained NO records and ->error_getRootLine_failPid tells us that it was because of a pid=-1 (indicating a "version" record)...:
1373  if (!count($temp_sys_page->getRootLine($this->id, $this->MP)) && $temp_sys_page->error_getRootLine_failPid == -1) {
1374  // Setting versioningPreview flag and try again:
1375  $temp_sys_page->versioningPreview = TRUE;
1376  if (count($temp_sys_page->getRootLine($this->id, $this->MP))) {
1377  // Finally, we got a root line (meaning that it WAS due to versioning preview of a page somewhere) and we set the fePreview flag which in itself will allow sys_page class to display previews of versionized records.
1378  $this->fePreview = 1;
1379  }
1380  }
1381  }
1382  }
1383  // The preview flag will be set if a backend user is in an offline workspace
1384  if (
1385  (
1386  $GLOBALS['BE_USER']->user['workspace_preview']
1387  || GeneralUtility::_GP('ADMCMD_view')
1388  || $this->doWorkspacePreview()
1389  )
1390  && (
1391  $this->whichWorkspace() === -1
1392  || $this->whichWorkspace() > 0
1393  )
1394  && !GeneralUtility::_GP('ADMCMD_noBeUser')
1395  ) {
1396  // Will show special preview message.
1397  $this->fePreview = 2;
1398  }
1399  // If the front-end is showing a preview, caching MUST be disabled.
1400  if ($this->fePreview) {
1401  $this->disableCache();
1402  }
1403  }
1404  $GLOBALS['TT']->pull();
1405  // Now, get the id, validate access etc:
1406  $this->fetch_the_id();
1407  // Check if backend user has read access to this page. If not, recalculate the id.
1408  if ($this->beUserLogin && $this->fePreview) {
1409  if (!$GLOBALS['BE_USER']->doesUserHaveAccess($this->page, 1)) {
1410  // Resetting
1411  $this->clear_preview();
1412  $this->fe_user->user = $originalFrontendUser;
1413  // Fetching the id again, now with the preview settings reset.
1414  $this->fetch_the_id();
1415  }
1416  }
1417  // Checks if user logins are blocked for a certain branch and if so, will unset user login and re-fetch ID.
1418  $this->loginAllowedInBranch = $this->checkIfLoginAllowedInBranch();
1419  // Logins are not allowed:
1420  if (!$this->loginAllowedInBranch) {
1421  // Only if there is a login will we run this...
1422  if ($this->isUserOrGroupSet()) {
1423  if ($this->loginAllowedInBranch_mode == 'all') {
1424  // Clear out user and group:
1425  $this->fe_user->hideActiveLogin();
1426  $this->gr_list = '0,-1';
1427  } else {
1428  $this->gr_list = '0,-2';
1429  }
1430  // Fetching the id again, now with the preview settings reset.
1431  $this->fetch_the_id();
1432  }
1433  }
1434  // Final cleaning.
1435  // Make sure it's an integer
1436  $this->id = ($this->contentPid = (int)$this->id);
1437  // Make sure it's an integer
1438  $this->type = (int)$this->type;
1439  // Call post processing function for id determination:
1440  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'])) {
1441  $_params = array('pObj' => &$this);
1442  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['determineId-PostProc'] as $_funcRef) {
1443  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1444  }
1445  }
1446  }
1447 
1454  protected function determineIdIsHiddenPage() {
1455  $field = \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->id) ? 'uid' : 'alias';
1456  $pageSelectCondition = $field . '=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($this->id, 'pages');
1457  $page = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow('uid,hidden,starttime,endtime', 'pages', $pageSelectCondition . ' AND pid>=0 AND deleted=0');
1458  $workspace = $this->whichWorkspace();
1459  if ($workspace !== 0 && $workspace !== FALSE) {
1460  // Fetch overlay of page if in workspace and check if it is hidden
1461  $pageSelectObject = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1462  $pageSelectObject->versioningPreview = TRUE;
1463  $pageSelectObject->init(FALSE);
1464  $targetPage = $pageSelectObject->getWorkspaceVersionOfRecord($this->whichWorkspace(), 'pages', $page['uid']);
1465  $result = $targetPage === -1 || $targetPage === -2;
1466  } else {
1467  $result = is_array($page) && ($page['hidden'] || $page['starttime'] > $GLOBALS['SIM_EXEC_TIME'] || $page['endtime'] != 0 && $page['endtime'] <= $GLOBALS['SIM_EXEC_TIME']);
1468  }
1469  return $result;
1470  }
1471 
1482  public function fetch_the_id() {
1483  $GLOBALS['TT']->push('fetch_the_id initialize/', '');
1484  // Initialize the page-select functions.
1485  $this->sys_page = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
1486  $this->sys_page->versioningPreview = $this->fePreview === 2 || (int)$this->workspacePreview || (bool)GeneralUtility::_GP('ADMCMD_view');
1487  $this->sys_page->versioningWorkspaceId = $this->whichWorkspace();
1488  $this->sys_page->init($this->showHiddenPage);
1489  // Set the valid usergroups for FE
1490  $this->initUserGroups();
1491  // Sets sys_page where-clause
1492  $this->setSysPageWhereClause();
1493  // Splitting $this->id by a period (.).
1494  // First part is 'id' and second part (if exists) will overrule the &type param
1495  $idParts = explode('.', $this->id, 2);
1496  $this->id = $idParts[0];
1497  if (isset($idParts[1])) {
1498  $this->type = $idParts[1];
1499  }
1500 
1501  // If $this->id is a string, it's an alias
1502  $this->checkAndSetAlias();
1503  // The id and type is set to the integer-value - just to be sure...
1504  $this->id = (int)$this->id;
1505  $this->type = (int)$this->type;
1506  $GLOBALS['TT']->pull();
1507  // We find the first page belonging to the current domain
1508  $GLOBALS['TT']->push('fetch_the_id domain/', '');
1509  // The page_id of the current domain
1510  $this->domainStartPage = $this->findDomainRecord($this->TYPO3_CONF_VARS['SYS']['recursiveDomainSearch']);
1511  if (!$this->id) {
1512  if ($this->domainStartPage) {
1513  // If the id was not previously set, set it to the id of the domain.
1514  $this->id = $this->domainStartPage;
1515  } else {
1516  // Find the first 'visible' page in that domain
1517  $theFirstPage = $this->sys_page->getFirstWebPage($this->id);
1518  if ($theFirstPage) {
1519  $this->id = $theFirstPage['uid'];
1520  } else {
1521  $message = 'No pages are found on the rootlevel!';
1522  if ($this->checkPageUnavailableHandler()) {
1523  $this->pageUnavailableAndExit($message);
1524  } else {
1525  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1526  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message, 1301648975);
1527  }
1528  }
1529  }
1530  }
1531  $GLOBALS['TT']->pull();
1532  $GLOBALS['TT']->push('fetch_the_id rootLine/', '');
1533  // We store the originally requested id
1534  $requestedId = $this->id;
1535  $this->getPageAndRootlineWithDomain($this->domainStartPage);
1536  $GLOBALS['TT']->pull();
1537  if ($this->pageNotFound && $this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
1538  $pNotFoundMsg = array(
1539  1 => 'ID was not an accessible page',
1540  2 => 'Subsection was found and not accessible',
1541  3 => 'ID was outside the domain',
1542  4 => 'The requested page alias does not exist'
1543  );
1544  $this->pageNotFoundAndExit($pNotFoundMsg[$this->pageNotFound]);
1545  }
1546  if ($this->page['url_scheme'] > 0) {
1547  $newUrl = '';
1548  $requestUrlScheme = parse_url(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), PHP_URL_SCHEME);
1549  if ((int)$this->page['url_scheme'] === HttpUtility::SCHEME_HTTP && $requestUrlScheme == 'https') {
1550  $newUrl = 'http://' . substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), 8);
1551  } elseif ((int)$this->page['url_scheme'] === HttpUtility::SCHEME_HTTPS && $requestUrlScheme == 'http') {
1552  $newUrl = 'https://' . substr(GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL'), 7);
1553  }
1554  if ($newUrl !== '') {
1555  if ($_SERVER['REQUEST_METHOD'] === 'POST') {
1556  $headerCode = HttpUtility::HTTP_STATUS_303;
1557  } else {
1558  $headerCode = HttpUtility::HTTP_STATUS_301;
1559  }
1560  HttpUtility::redirect($newUrl, $headerCode);
1561  }
1562  }
1563  // Set no_cache if set
1564  if ($this->page['no_cache']) {
1565  $this->set_no_cache('no_cache is set in page properties');
1566  }
1567  // Init SYS_LASTCHANGED
1568  $this->register['SYS_LASTCHANGED'] = (int)$this->page['tstamp'];
1569  if ($this->register['SYS_LASTCHANGED'] < (int)$this->page['SYS_LASTCHANGED']) {
1570  $this->register['SYS_LASTCHANGED'] = (int)$this->page['SYS_LASTCHANGED'];
1571  }
1572  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'])) {
1573  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['fetchPageId-PostProcessing'] as $functionReference) {
1574  $parameters = array('parentObject' => $this);
1575  GeneralUtility::callUserFunction($functionReference, $parameters, $this);
1576  }
1577  }
1578  }
1579 
1596  public function getPageAndRootline() {
1597  $this->page = $this->sys_page->getPage($this->id);
1598  if (!count($this->page)) {
1599  // If no page, we try to find the page before in the rootLine.
1600  // Page is 'not found' in case the id itself was not an accessible page. code 1
1601  $this->pageNotFound = 1;
1602  $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
1603  if (count($this->rootLine)) {
1604  $c = count($this->rootLine) - 1;
1605  while ($c > 0) {
1606  // Add to page access failure history:
1607  $this->pageAccessFailureHistory['direct_access'][] = $this->rootLine[$c];
1608  // Decrease to next page in rootline and check the access to that, if OK, set as page record and ID value.
1609  $c--;
1610  $this->id = $this->rootLine[$c]['uid'];
1611  $this->page = $this->sys_page->getPage($this->id);
1612  if (count($this->page)) {
1613  break;
1614  }
1615  }
1616  }
1617  // If still no page...
1618  if (!count($this->page)) {
1619  $message = 'The requested page does not exist!';
1620  if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
1621  $this->pageNotFoundAndExit($message);
1622  } else {
1623  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1624  throw new PageNotFoundException($message, 1301648780);
1625  }
1626  }
1627  }
1628  // Spacer is not accessible in frontend
1629  if ($this->page['doktype'] == PageRepository::DOKTYPE_SPACER) {
1630  $message = 'The requested page does not exist!';
1631  if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling']) {
1632  $this->pageNotFoundAndExit($message);
1633  } else {
1634  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1635  throw new PageNotFoundException($message, 1301648781);
1636  }
1637  }
1638  // Is the ID a link to another page??
1639  if ($this->page['doktype'] == PageRepository::DOKTYPE_SHORTCUT) {
1640  // We need to clear MP if the page is a shortcut. Reason is if the short cut goes to another page, then we LEAVE the rootline which the MP expects.
1641  $this->MP = '';
1642  // saving the page so that we can check later - when we know
1643  // about languages - whether we took the correct shortcut or
1644  // whether a translation of the page overwrites the shortcut
1645  // target and we need to follow the new target
1646  $this->originalShortcutPage = $this->page;
1647  $this->page = $this->getPageShortcut($this->page['shortcut'], $this->page['shortcut_mode'], $this->page['uid']);
1648  $this->id = $this->page['uid'];
1649  }
1650  // If the page is a mountpoint which should be overlaid with the contents of the mounted page,
1651  // it must never be accessible directly, but only in the mountpoint context. Therefore we change
1652  // the current ID and the user is redirected by checkPageForMountpointRedirect().
1653  if ($this->page['doktype'] == PageRepository::DOKTYPE_MOUNTPOINT && $this->page['mount_pid_ol']) {
1654  $this->originalMountPointPage = $this->page;
1655  $this->page = $this->sys_page->getPage($this->page['mount_pid']);
1656  if (empty($this->page)) {
1657  $message = 'This page (ID ' . $this->originalMountPointPage['uid'] . ') is of type "Mount point" and '
1658  . 'mounts a page which is not accessible (ID ' . $this->originalMountPointPage['mount_pid'] . ').';
1659  throw new PageNotFoundException($message, 1402043263);
1660  }
1661  $this->MP = $this->page['uid'] . '-' . $this->originalMountPointPage['uid'];
1662  $this->id = $this->page['uid'];
1663  }
1664  // Gets the rootLine
1665  $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
1666  // If not rootline we're off...
1667  if (!count($this->rootLine)) {
1668  $ws = $this->whichWorkspace();
1669  if ($this->sys_page->error_getRootLine_failPid == -1 && $ws) {
1670  $this->sys_page->versioningPreview = TRUE;
1671  $this->sys_page->versioningWorkspaceId = $ws;
1672  $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
1673  }
1674  if (!count($this->rootLine)) {
1675  $message = 'The requested page didn\'t have a proper connection to the tree-root!';
1676  if ($this->checkPageUnavailableHandler()) {
1677  $this->pageUnavailableAndExit($message);
1678  } else {
1679  $rootline = '(' . $this->sys_page->error_getRootLine . ')';
1680  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1681  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message . '<br /><br />' . $rootline, 1301648167);
1682  }
1683  }
1684  $this->fePreview = 1;
1685  }
1686  // Checking for include section regarding the hidden/starttime/endtime/fe_user (that is access control of a whole subbranch!)
1687  if ($this->checkRootlineForIncludeSection()) {
1688  if (!count($this->rootLine)) {
1689  $message = 'The requested page was not accessible!';
1690  if ($this->checkPageUnavailableHandler()) {
1691  $this->pageUnavailableAndExit($message);
1692  } else {
1693  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1694  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message, 1301648234);
1695  }
1696  } else {
1697  $el = reset($this->rootLine);
1698  $this->id = $el['uid'];
1699  $this->page = $this->sys_page->getPage($this->id);
1700  $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
1701  }
1702  }
1703  }
1704 
1721  public function getPageShortcut($SC, $mode, $thisUid, $itera = 20, $pageLog = array(), $disableGroupCheck = FALSE) {
1722  $idArray = GeneralUtility::intExplode(',', $SC);
1723  // Find $page record depending on shortcut mode:
1724  switch ($mode) {
1726 
1728  $pageArray = $this->sys_page->getMenu($idArray[0] ? $idArray[0] : $thisUid, '*', 'sorting', 'AND pages.doktype<199 AND pages.doktype!=' . PageRepository::DOKTYPE_BE_USER_SECTION);
1729  $pO = 0;
1730  if ($mode == PageRepository::SHORTCUT_MODE_RANDOM_SUBPAGE && count($pageArray)) {
1731  $randval = (int)rand(0, count($pageArray) - 1);
1732  $pO = $randval;
1733  }
1734  $c = 0;
1735  foreach ($pageArray as $pV) {
1736  if ($c == $pO) {
1737  $page = $pV;
1738  break;
1739  }
1740  $c++;
1741  }
1742  if (count($page) == 0) {
1743  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a subpage. ' . 'However, this page has no accessible subpages.';
1744  throw new PageNotFoundException($message, 1301648328);
1745  }
1746  break;
1748  $parent = $this->sys_page->getPage($thisUid, $disableGroupCheck);
1749  $page = $this->sys_page->getPage($parent['pid'], $disableGroupCheck);
1750 
1751  if (count($page) == 0) {
1752  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to its parent page. ' . 'However, the parent page is not accessible.';
1753  throw new PageNotFoundException($message, 1301648358);
1754  }
1755  break;
1756  default:
1757  $page = $this->sys_page->getPage($idArray[0], $disableGroupCheck);
1758  if (count($page) == 0) {
1759  $message = 'This page (ID ' . $thisUid . ') is of type "Shortcut" and configured to redirect to a page, which is not accessible (ID ' . $idArray[0] . ').';
1760  throw new PageNotFoundException($message, 1301648404);
1761  }
1762  }
1763  // Check if short cut page was a shortcut itself, if so look up recursively:
1764  if ($page['doktype'] == PageRepository::DOKTYPE_SHORTCUT) {
1765  if (!in_array($page['uid'], $pageLog) && $itera > 0) {
1766  $pageLog[] = $page['uid'];
1767  $page = $this->getPageShortcut($page['shortcut'], $page['shortcut_mode'], $page['uid'], $itera - 1, $pageLog, $disableGroupCheck);
1768  } else {
1769  $pageLog[] = $page['uid'];
1770  $message = 'Page shortcuts were looping in uids ' . implode(',', $pageLog) . '...!';
1771  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
1772  throw new \RuntimeException($message, 1294587212);
1773  }
1774  }
1775  // Return resulting page:
1776  return $page;
1777  }
1778 
1787  $c = count($this->rootLine);
1788  $removeTheRestFlag = 0;
1789  for ($a = 0; $a < $c; $a++) {
1790  if (!$this->checkPagerecordForIncludeSection($this->rootLine[$a])) {
1791  // Add to page access failure history:
1792  $this->pageAccessFailureHistory['sub_section'][] = $this->rootLine[$a];
1793  $removeTheRestFlag = 1;
1794  }
1795  if ($this->rootLine[$a]['doktype'] == PageRepository::DOKTYPE_BE_USER_SECTION) {
1796  // If there is a backend user logged in, check if he has read access to the page:
1797  if ($this->beUserLogin) {
1798  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('uid', 'pages', 'uid=' . (int)$this->id . ' AND ' . $GLOBALS['BE_USER']->getPagePermsClause(1));
1799  // versionOL()?
1800  list($isPage) = $GLOBALS['TYPO3_DB']->sql_fetch_row($res);
1801  if (!$isPage) {
1802  // If there was no page selected, the user apparently did not have read access to the current PAGE (not position in rootline) and we set the remove-flag...
1803  $removeTheRestFlag = 1;
1804  }
1805  } else {
1806  // Dont go here, if there is no backend user logged in.
1807  $removeTheRestFlag = 1;
1808  }
1809  }
1810  if ($removeTheRestFlag) {
1811  // Page is 'not found' in case a subsection was found and not accessible, code 2
1812  $this->pageNotFound = 2;
1813  unset($this->rootLine[$a]);
1814  }
1815  }
1816  return $removeTheRestFlag;
1817  }
1818 
1830  public function checkEnableFields($row, $bypassGroupCheck = FALSE) {
1831  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'])) {
1832  $_params = array('pObj' => $this, 'row' => &$row, 'bypassGroupCheck' => &$bypassGroupCheck);
1833  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_checkEnableFields'] as $_funcRef) {
1834  // Call hooks: If one returns FALSE, method execution is aborted with result "This record is not available"
1835  $return = GeneralUtility::callUserFunction($_funcRef, $_params, $this);
1836  if ($return === FALSE) {
1837  return FALSE;
1838  }
1839  }
1840  }
1841  if ((!$row['hidden'] || $this->showHiddenPage) && $row['starttime'] <= $GLOBALS['SIM_ACCESS_TIME'] && ($row['endtime'] == 0 || $row['endtime'] > $GLOBALS['SIM_ACCESS_TIME']) && ($bypassGroupCheck || $this->checkPageGroupAccess($row))) {
1842  return TRUE;
1843  }
1844  }
1845 
1855  public function checkPageGroupAccess($row, $groupList = NULL) {
1856  if (is_null($groupList)) {
1857  $groupList = $this->gr_list;
1858  }
1859  if (!is_array($groupList)) {
1860  $groupList = explode(',', $groupList);
1861  }
1862  $pageGroupList = explode(',', $row['fe_group'] ?: 0);
1863  return count(array_intersect($groupList, $pageGroupList)) > 0;
1864  }
1865 
1875  public function checkPagerecordForIncludeSection($row) {
1876  return !$row['extendToSubpages'] || $this->checkEnableFields($row) ? 1 : 0;
1877  }
1878 
1885  public function checkIfLoginAllowedInBranch() {
1886  // Initialize:
1887  $c = count($this->rootLine);
1888  $disable = FALSE;
1889  // Traverse root line from root and outwards:
1890  for ($a = 0; $a < $c; $a++) {
1891  // If a value is set for login state:
1892  if ($this->rootLine[$a]['fe_login_mode'] > 0) {
1893  // Determine state from value:
1894  if ((int)$this->rootLine[$a]['fe_login_mode'] === 1) {
1895  $disable = TRUE;
1896  $this->loginAllowedInBranch_mode = 'all';
1897  } elseif ((int)$this->rootLine[$a]['fe_login_mode'] === 3) {
1898  $disable = TRUE;
1899  $this->loginAllowedInBranch_mode = 'groups';
1900  } else {
1901  $disable = FALSE;
1902  }
1903  }
1904  }
1905  return !$disable;
1906  }
1907 
1914  public function getPageAccessFailureReasons() {
1915  $output = array();
1916  $combinedRecords = array_merge(is_array($this->pageAccessFailureHistory['direct_access']) ? $this->pageAccessFailureHistory['direct_access'] : array(array('fe_group' => 0)), is_array($this->pageAccessFailureHistory['sub_section']) ? $this->pageAccessFailureHistory['sub_section'] : array());
1917  if (count($combinedRecords)) {
1918  foreach ($combinedRecords as $k => $pagerec) {
1919  // If $k=0 then it is the very first page the original ID was pointing at and that will get a full check of course
1920  // If $k>0 it is parent pages being tested. They are only significant for the access to the first page IF they had the extendToSubpages flag set, hence checked only then!
1921  if (!$k || $pagerec['extendToSubpages']) {
1922  if ($pagerec['hidden']) {
1923  $output['hidden'][$pagerec['uid']] = TRUE;
1924  }
1925  if ($pagerec['starttime'] > $GLOBALS['SIM_ACCESS_TIME']) {
1926  $output['starttime'][$pagerec['uid']] = $pagerec['starttime'];
1927  }
1928  if ($pagerec['endtime'] != 0 && $pagerec['endtime'] <= $GLOBALS['SIM_ACCESS_TIME']) {
1929  $output['endtime'][$pagerec['uid']] = $pagerec['endtime'];
1930  }
1931  if (!$this->checkPageGroupAccess($pagerec)) {
1932  $output['fe_group'][$pagerec['uid']] = $pagerec['fe_group'];
1933  }
1934  }
1935  }
1936  }
1937  return $output;
1938  }
1939 
1949  public function setIDfromArgV() {
1950  if (!$this->id) {
1951  list($theAlias) = explode('&', GeneralUtility::getIndpEnv('QUERY_STRING'));
1952  $theAlias = trim($theAlias);
1953  $this->id = $theAlias != '' && strpos($theAlias, '=') === FALSE ? $theAlias : 0;
1954  }
1955  }
1956 
1967  $this->getPageAndRootline();
1968  // Checks if the $domain-startpage is in the rootLine. This is necessary so that references to page-id's from other domains are not possible.
1969  if ($domainStartPage && is_array($this->rootLine)) {
1970  $idFound = 0;
1971  foreach ($this->rootLine as $key => $val) {
1972  if ($val['uid'] == $domainStartPage) {
1973  $idFound = 1;
1974  break;
1975  }
1976  }
1977  if (!$idFound) {
1978  // Page is 'not found' in case the id was outside the domain, code 3
1979  $this->pageNotFound = 3;
1980  $this->id = $domainStartPage;
1981  // re-get the page and rootline if the id was not found.
1982  $this->getPageAndRootline();
1983  }
1984  }
1985  }
1986 
1994  public function setSysPageWhereClause() {
1995  $this->sys_page->where_hid_del .= ' AND pages.doktype<200';
1996  $this->sys_page->where_groupAccess = $this->sys_page->getMultipleGroupsWhereClause('pages.fe_group', 'pages');
1997  }
1998 
2007  public function findDomainRecord($recursive = FALSE) {
2008  if ($recursive) {
2009  $host = explode('.', GeneralUtility::getIndpEnv('HTTP_HOST'));
2010  while (count($host)) {
2011  $pageUid = $this->sys_page->getDomainStartPage(implode('.', $host), GeneralUtility::getIndpEnv('SCRIPT_NAME'), GeneralUtility::getIndpEnv('REQUEST_URI'));
2012  if ($pageUid) {
2013  return $pageUid;
2014  } else {
2015  array_shift($host);
2016  }
2017  }
2018  return $pageUid;
2019  } else {
2020  return $this->sys_page->getDomainStartPage(GeneralUtility::getIndpEnv('HTTP_HOST'), GeneralUtility::getIndpEnv('SCRIPT_NAME'), GeneralUtility::getIndpEnv('REQUEST_URI'));
2021  }
2022  }
2023 
2031  public function pageUnavailableAndExit($reason = '', $header = '') {
2032  $header = $header ?: $this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling_statheader'];
2033  $this->pageUnavailableHandler($this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling'], $header, $reason);
2034  die;
2035  }
2036 
2045  public function pageNotFoundAndExit($reason = '', $header = '') {
2046  $header = $header ?: $this->TYPO3_CONF_VARS['FE']['pageNotFound_handling_statheader'];
2047  $this->pageNotFoundHandler($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'], $header, $reason);
2048  die;
2049  }
2050 
2058  public function checkPageUnavailableHandler() {
2059  if (
2060  $this->TYPO3_CONF_VARS['FE']['pageUnavailable_handling']
2062  GeneralUtility::getIndpEnv('REMOTE_ADDR'),
2063  $this->TYPO3_CONF_VARS['SYS']['devIPmask']
2064  )
2065  ) {
2066  $checkPageUnavailableHandler = TRUE;
2067  } else {
2068  $checkPageUnavailableHandler = FALSE;
2069  }
2070  return $checkPageUnavailableHandler;
2071  }
2072 
2082  public function pageUnavailableHandler($code, $header, $reason) {
2083  $this->pageErrorHandler($code, $header, $reason);
2084  }
2085 
2095  public function pageNotFoundHandler($code, $header = '', $reason = '') {
2096  $this->pageErrorHandler($code, $header, $reason);
2097  }
2098 
2110  public function pageErrorHandler($code, $header = '', $reason = '') {
2111  // Issue header in any case:
2112  if ($header) {
2113  $headerArr = preg_split('/\\r|\\n/', $header, -1, PREG_SPLIT_NO_EMPTY);
2114  foreach ($headerArr as $header) {
2115  header($header);
2116  }
2117  }
2118  // Create response:
2119  // Simply boolean; Just shows TYPO3 error page with reason:
2120  if (gettype($code) == 'boolean' || (string)$code === '1') {
2121  $title = 'Page Not Found';
2122  $message = 'The page did not exist or was inaccessible.' . ($reason ? ' Reason: ' . htmlspecialchars($reason) : '');
2123  $messagePage = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\ErrorpageMessage', $message, $title);
2124  $messagePage->output();
2125  die;
2126  } elseif (GeneralUtility::isFirstPartOfStr($code, 'USER_FUNCTION:')) {
2127  $funcRef = trim(substr($code, 14));
2128  $params = array(
2129  'currentUrl' => GeneralUtility::getIndpEnv('REQUEST_URI'),
2130  'reasonText' => $reason,
2131  'pageAccessFailureReasons' => $this->getPageAccessFailureReasons()
2132  );
2133  echo GeneralUtility::callUserFunction($funcRef, $params, $this);
2134  } elseif (GeneralUtility::isFirstPartOfStr($code, 'READFILE:')) {
2135  $readFile = GeneralUtility::getFileAbsFileName(trim(substr($code, 9)));
2136  if (@is_file($readFile)) {
2137  echo str_replace(
2138  array(
2139  '###CURRENT_URL###',
2140  '###REASON###'
2141  ),
2142  array(
2143  GeneralUtility::getIndpEnv('REQUEST_URI'),
2144  htmlspecialchars($reason)
2145  ),
2146  GeneralUtility::getUrl($readFile)
2147  );
2148  } else {
2149  throw new \RuntimeException('Configuration Error: 404 page "' . $readFile . '" could not be found.', 1294587214);
2150  }
2151  } elseif (GeneralUtility::isFirstPartOfStr($code, 'REDIRECT:')) {
2152  HttpUtility::redirect(substr($code, 9));
2153  } elseif (strlen($code)) {
2154  // Check if URL is relative
2155  $url_parts = parse_url($code);
2156  if ($url_parts['host'] == '') {
2157  $url_parts['host'] = GeneralUtility::getIndpEnv('HTTP_HOST');
2158  if ($code[0] === '/') {
2159  $code = GeneralUtility::getIndpEnv('TYPO3_REQUEST_HOST') . $code;
2160  } else {
2161  $code = GeneralUtility::getIndpEnv('TYPO3_REQUEST_DIR') . $code;
2162  }
2163  $checkBaseTag = FALSE;
2164  } else {
2165  $checkBaseTag = TRUE;
2166  }
2167  // Check recursion
2168  if ($code == GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL')) {
2169  if ($reason == '') {
2170  $reason = 'Page cannot be found.';
2171  }
2172  $reason .= LF . LF . 'Additionally, ' . $code . ' was not found while trying to retrieve the error document.';
2173  throw new \RuntimeException(nl2br(htmlspecialchars($reason)), 1294587215);
2174  }
2175  // Prepare headers
2176  $headerArr = array(
2177  'User-agent: ' . GeneralUtility::getIndpEnv('HTTP_USER_AGENT'),
2178  'Referer: ' . GeneralUtility::getIndpEnv('TYPO3_REQUEST_URL')
2179  );
2180  $res = GeneralUtility::getUrl($code, 1, $headerArr);
2181  // Header and content are separated by an empty line
2182  list($header, $content) = explode(CRLF . CRLF, $res, 2);
2183  $content .= CRLF;
2184  if (FALSE === $res) {
2185  // Last chance -- redirect
2186  HttpUtility::redirect($code);
2187  } else {
2188  // Forward these response headers to the client
2189  $forwardHeaders = array(
2190  'Content-Type:'
2191  );
2192  $headerArr = preg_split('/\\r|\\n/', $header, -1, PREG_SPLIT_NO_EMPTY);
2193  foreach ($headerArr as $header) {
2194  foreach ($forwardHeaders as $h) {
2195  if (preg_match('/^' . $h . '/', $header)) {
2196  header($header);
2197  }
2198  }
2199  }
2200  // Put <base> if necesary
2201  if ($checkBaseTag) {
2202  // If content already has <base> tag, we do not need to do anything
2203  if (FALSE === stristr($content, '<base ')) {
2204  // Generate href for base tag
2205  $base = $url_parts['scheme'] . '://';
2206  if ($url_parts['user'] != '') {
2207  $base .= $url_parts['user'];
2208  if ($url_parts['pass'] != '') {
2209  $base .= ':' . $url_parts['pass'];
2210  }
2211  $base .= '@';
2212  }
2213  $base .= $url_parts['host'];
2214  // Add path portion skipping possible file name
2215  $base .= preg_replace('/(.*\\/)[^\\/]*/', '${1}', $url_parts['path']);
2216  // Put it into content (generate also <head> if necessary)
2217  $replacement = LF . '<base href="' . htmlentities($base) . '" />' . LF;
2218  if (stristr($content, '<head>')) {
2219  $content = preg_replace('/(<head>)/i', '\\1' . $replacement, $content);
2220  } else {
2221  $content = preg_replace('/(<html[^>]*>)/i', '\\1<head>' . $replacement . '</head>', $content);
2222  }
2223  }
2224  }
2225  // Output the content
2226  echo $content;
2227  }
2228  } else {
2229  $title = 'Page Not Found';
2230  $message = $reason ? 'Reason: ' . htmlspecialchars($reason) : 'Page cannot be found.';
2231  $messagePage = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Messaging\\ErrorpageMessage', $message, $title);
2232  $messagePage->output();
2233  }
2234  die;
2235  }
2236 
2245  public function checkAndSetAlias() {
2246  if ($this->id && !\TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($this->id)) {
2247  $aid = $this->sys_page->getPageIdFromAlias($this->id);
2248  if ($aid) {
2249  $this->id = $aid;
2250  } else {
2251  $this->pageNotFound = 4;
2252  }
2253  }
2254  }
2255 
2263  public function mergingWithGetVars($GET_VARS) {
2264  if (is_array($GET_VARS)) {
2265  // Getting $_GET var, unescaped.
2266  $realGet = GeneralUtility::_GET();
2267  if (!is_array($realGet)) {
2268  $realGet = array();
2269  }
2270  // Merge new values on top:
2271  ArrayUtility::mergeRecursiveWithOverrule($realGet, $GET_VARS);
2272  // Write values back to $_GET:
2273  GeneralUtility::_GETset($realGet);
2274  // Setting these specifically (like in the init-function):
2275  if (isset($GET_VARS['type'])) {
2276  $this->type = (int)$GET_VARS['type'];
2277  }
2278  if (isset($GET_VARS['cHash'])) {
2279  $this->cHash = $GET_VARS['cHash'];
2280  }
2281  if (isset($GET_VARS['jumpurl'])) {
2282  $this->jumpurl = $GET_VARS['jumpurl'];
2283  }
2284  if (isset($GET_VARS['MP'])) {
2285  $this->MP = $this->TYPO3_CONF_VARS['FE']['enable_mount_pids'] ? $GET_VARS['MP'] : '';
2286  }
2287  if (isset($GET_VARS['no_cache']) && $GET_VARS['no_cache']) {
2288  $this->set_no_cache('no_cache is requested via GET parameter');
2289  }
2290  }
2291  }
2292 
2293  /********************************************
2294  *
2295  * Template and caching related functions.
2296  *
2297  *******************************************/
2307  public function makeCacheHash() {
2308  // No need to test anything if caching was already disabled.
2309  if ($this->no_cache && !$this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
2310  return;
2311  }
2312  $GET = GeneralUtility::_GET();
2313  if ($this->cHash && is_array($GET)) {
2314  // Make sure we use the page uid and not the page alias
2315  $GET['id'] = $this->id;
2316  $this->cHash_array = $this->cacheHash->getRelevantParameters(GeneralUtility::implodeArrayForUrl('', $GET));
2317  $cHash_calc = $this->cacheHash->calculateCacheHash($this->cHash_array);
2318  if ($cHash_calc != $this->cHash) {
2319  if ($this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
2320  $this->pageNotFoundAndExit('Request parameters could not be validated (&cHash comparison failed)');
2321  } else {
2322  $this->disableCache();
2323  $GLOBALS['TT']->setTSlogMessage('The incoming cHash "' . $this->cHash . '" and calculated cHash "' . $cHash_calc . '" did not match, so caching was disabled. The fieldlist used was "' . implode(',', array_keys($this->cHash_array)) . '"', 2);
2324  }
2325  }
2326  } elseif (is_array($GET)) {
2327  // No cHash is set, check if that is correct
2328  if ($this->cacheHash->doParametersRequireCacheHash(GeneralUtility::implodeArrayForUrl('', $GET))) {
2329  $this->reqCHash();
2330  }
2331  }
2332  }
2333 
2342  public function reqCHash() {
2343  if (!$this->cHash) {
2344  if ($this->TYPO3_CONF_VARS['FE']['pageNotFoundOnCHashError']) {
2345  if ($this->tempContent) {
2346  $this->clearPageCacheContent();
2347  }
2348  $this->pageNotFoundAndExit('Request parameters could not be validated (&cHash empty)');
2349  } else {
2350  $this->disableCache();
2351  $GLOBALS['TT']->setTSlogMessage('TSFE->reqCHash(): No &cHash parameter was sent for GET vars though required so caching is disabled', 2);
2352  }
2353  }
2354  }
2355 
2361  public function initTemplate() {
2362  $this->tmpl = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\TemplateService');
2363  $this->tmpl->init();
2364  $this->tmpl->tt_track = (bool)$this->beUserLogin;
2365  }
2366 
2373  public function getFromCache() {
2374  if (!$this->no_cache) {
2375  $cc = $this->tmpl->getCurrentPageData();
2376  if (!is_array($cc)) {
2377  $key = $this->id . '::' . $this->MP;
2378  // Returns TRUE if the lock is active now
2379  $isLocked = $this->acquirePageGenerationLock($this->pagesection_lockObj, $key);
2380  if (!$isLocked) {
2381  // Lock is no longer active, the data in "cache_pagesection" is now ready
2382  $cc = $this->tmpl->getCurrentPageData();
2383  if (is_array($cc)) {
2384  // Release the lock
2385  $this->releasePageGenerationLock($this->pagesection_lockObj);
2386  }
2387  }
2388  }
2389  if (is_array($cc)) {
2390  // BE CAREFUL to change the content of the cc-array. This array is serialized and an md5-hash based on this is used for caching the page.
2391  // If this hash is not the same in here in this section and after page-generation, then the page will not be properly cached!
2392  // This array is an identification of the template. If $this->all is empty it's because the template-data is not cached, which it must be.
2393  $cc = $this->tmpl->matching($cc);
2394  ksort($cc);
2395  $this->all = $cc;
2396  }
2397  unset($cc);
2398  }
2399  // clearing the content-variable, which will hold the pagecontent
2400  $this->content = '';
2401  // Unsetting the lowlevel config
2402  unset($this->config);
2403  $this->cacheContentFlag = FALSE;
2404  // Look for page in cache only if caching is not disabled and if a shift-reload is not sent to the server.
2405  if (!$this->no_cache && !$this->headerNoCache()) {
2406  $lockHash = $this->getLockHash();
2407  if ($this->all) {
2408  $this->newHash = $this->getHash();
2409  $GLOBALS['TT']->push('Cache Row', '');
2410  $row = $this->getFromCache_queryRow();
2411  if (!is_array($row)) {
2412  $isLocked = $this->acquirePageGenerationLock($this->pages_lockObj, $lockHash);
2413  if (!$isLocked) {
2414  // Lock is no longer active, the data in "cache_pages" is now ready
2415  $row = $this->getFromCache_queryRow();
2416  if (is_array($row)) {
2417  // Release the lock
2418  $this->releasePageGenerationLock($this->pages_lockObj);
2419  }
2420  }
2421  }
2422  if (is_array($row)) {
2423  // Release this lock
2424  $this->releasePageGenerationLock($this->pages_lockObj);
2425  // Call hook when a page is retrieved from cache:
2426  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'])) {
2427  $_params = array('pObj' => &$this, 'cache_pages_row' => &$row);
2428  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageLoadedFromCache'] as $_funcRef) {
2429  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2430  }
2431  }
2432  // Fetches the lowlevel config stored with the cached data
2433  $this->config = $row['cache_data'];
2434  // Getting the content
2435  $this->content = $row['content'];
2436  // Flag for temp content
2437  $this->tempContent = $row['temp_content'];
2438  // Setting flag, so we know, that some cached content has been loaded
2439  $this->cacheContentFlag = TRUE;
2440  $this->cacheExpires = $row['expires'];
2441 
2442  // Restore page title information, this is needed to generate the page title for
2443  // partially cached pages.
2444  $this->page['title'] = $row['pageTitleInfo']['title'];
2445  $this->altPageTitle = $row['pageTitleInfo']['altPageTitle'];
2446  $this->indexedDocTitle = $row['pageTitleInfo']['indexedDocTitle'];
2447 
2448  if (isset($this->config['config']['debug'])) {
2449  $debugCacheTime = (bool)$this->config['config']['debug'];
2450  } else {
2451  $debugCacheTime = !empty($this->TYPO3_CONF_VARS['FE']['debug']);
2452  }
2453  if ($debugCacheTime) {
2454  $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
2455  $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
2456  $this->content .= LF . '<!-- Cached page generated ' . date(($dateFormat . ' ' . $timeFormat), $row['tstamp']) . '. Expires ' . Date(($dateFormat . ' ' . $timeFormat), $row['expires']) . ' -->';
2457  }
2458  }
2459  $GLOBALS['TT']->pull();
2460  } else {
2461  $this->acquirePageGenerationLock($this->pages_lockObj, $lockHash);
2462  }
2463  }
2464  }
2465 
2472  public function getFromCache_queryRow() {
2473  $GLOBALS['TT']->push('Cache Query', '');
2474  $row = $this->pageCache->get($this->newHash);
2475  $GLOBALS['TT']->pull();
2476  return $row;
2477  }
2478 
2487  public function headerNoCache() {
2488  $disableAcquireCacheData = FALSE;
2489  if ($this->beUserLogin) {
2490  if (strtolower($_SERVER['HTTP_CACHE_CONTROL']) === 'no-cache' || strtolower($_SERVER['HTTP_PRAGMA']) === 'no-cache') {
2491  $disableAcquireCacheData = TRUE;
2492  }
2493  }
2494  // Call hook for possible by-pass of requiring of page cache (for recaching purpose)
2495  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'])) {
2496  $_params = array('pObj' => &$this, 'disableAcquireCacheData' => &$disableAcquireCacheData);
2497  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['headerNoCache'] as $_funcRef) {
2498  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2499  }
2500  }
2501  return $disableAcquireCacheData;
2502  }
2503 
2514  public function getHash() {
2515  return md5($this->createHashBase(FALSE));
2516  }
2517 
2527  public function getLockHash() {
2528  $lockHash = $this->createHashBase(TRUE);
2529  return md5($lockHash);
2530  }
2531 
2542  protected function createHashBase($createLockHashBase = FALSE) {
2543  $hashParameters = array(
2544  'id' => (int)$this->id,
2545  'type' => (int)$this->type,
2546  'gr_list' => (string) $this->gr_list,
2547  'MP' => (string) $this->MP,
2548  'cHash' => $this->cHash_array,
2549  'domainStartPage' => $this->domainStartPage
2550  );
2551  // Include the template information if we shouldn't create a lock hash
2552  if (!$createLockHashBase) {
2553  $hashParameters['all'] = $this->all;
2554  }
2555  // Call hook to influence the hash calculation
2556  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'])) {
2557  $_params = array(
2558  'hashParameters' => &$hashParameters,
2559  'createLockHashBase' => $createLockHashBase
2560  );
2561  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['createHashBase'] as $_funcRef) {
2562  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2563  }
2564  }
2565  return serialize($hashParameters);
2566  }
2567 
2574  public function getConfigArray() {
2575  $setStatPageName = FALSE;
2576  // If config is not set by the cache (which would be a major mistake somewhere) OR if INTincScripts-include-scripts have been registered, then we must parse the template in order to get it
2577  if (!is_array($this->config) || is_array($this->config['INTincScript']) || $this->forceTemplateParsing) {
2578  $GLOBALS['TT']->push('Parse template', '');
2579  // Force parsing, if set?:
2580  $this->tmpl->forceTemplateParsing = $this->forceTemplateParsing;
2581  // Start parsing the TS template. Might return cached version.
2582  $this->tmpl->start($this->rootLine);
2583  $GLOBALS['TT']->pull();
2584  if ($this->tmpl->loaded) {
2585  $GLOBALS['TT']->push('Setting the config-array', '');
2586  // toplevel - objArrayName
2587  $this->sPre = $this->tmpl->setup['types.'][$this->type];
2588  $this->pSetup = $this->tmpl->setup[$this->sPre . '.'];
2589  if (!is_array($this->pSetup)) {
2590  $message = 'The page is not configured! [type=' . $this->type . '][' . $this->sPre . '].';
2591  if ($this->checkPageUnavailableHandler()) {
2592  $this->pageUnavailableAndExit($message);
2593  } else {
2594  $explanation = 'This means that there is no TypoScript object of type PAGE with typeNum=' . $this->type . ' configured.';
2595  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
2596  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message . ' ' . $explanation, 1294587217);
2597  }
2598  } else {
2599  if (!isset($this->config['config'])) {
2600  $this->config['config'] = array();
2601  }
2602  // Filling the config-array, first with the main "config." part
2603  if (is_array($this->tmpl->setup['config.'])) {
2604  ArrayUtility::mergeRecursiveWithOverrule($this->tmpl->setup['config.'], $this->config['config']);
2605  $this->config['config'] = $this->tmpl->setup['config.'];
2606  }
2607  // override it with the page/type-specific "config."
2608  if (is_array($this->pSetup['config.'])) {
2609  ArrayUtility::mergeRecursiveWithOverrule($this->config['config'], $this->pSetup['config.']);
2610  }
2611  if ($this->config['config']['typolinkEnableLinksAcrossDomains']) {
2612  $this->config['config']['typolinkCheckRootline'] = TRUE;
2613  }
2614  // Set default values for removeDefaultJS and inlineStyle2TempFile so CSS and JS are externalized if compatversion is higher than 4.0
2615  if (GeneralUtility::compat_version('4.0')) {
2616  if (!isset($this->config['config']['removeDefaultJS'])) {
2617  $this->config['config']['removeDefaultJS'] = 'external';
2618  }
2619  if (!isset($this->config['config']['inlineStyle2TempFile'])) {
2620  $this->config['config']['inlineStyle2TempFile'] = 1;
2621  }
2622  }
2623  if (!isset($this->config['config']['compressJs'])) {
2624  $this->config['config']['compressJs'] = 0;
2625  }
2626  // Processing for the config_array:
2627  $this->config['rootLine'] = $this->tmpl->rootLine;
2628  $this->config['mainScript'] = trim($this->config['config']['mainScript']) ?: 'index.php';
2629  // Class for render Header and Footer parts
2630  $template = '';
2631  if ($this->pSetup['pageHeaderFooterTemplateFile']) {
2632  $file = $this->tmpl->getFileName($this->pSetup['pageHeaderFooterTemplateFile']);
2633  if ($file) {
2634  $this->getPageRenderer()->setTemplateFile($file);
2635  }
2636  }
2637  }
2638  $GLOBALS['TT']->pull();
2639  } else {
2640  if ($this->checkPageUnavailableHandler()) {
2641  $this->pageUnavailableAndExit('No TypoScript template found!');
2642  } else {
2643  $message = 'No TypoScript template found!';
2644  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
2645  throw new \TYPO3\CMS\Core\Error\Http\ServiceUnavailableException($message, 1294587218);
2646  }
2647  }
2648  }
2649 
2650  // No cache
2651  // Set $this->no_cache TRUE if the config.no_cache value is set!
2652  if ($this->config['config']['no_cache']) {
2653  $this->set_no_cache('config.no_cache is set');
2654  }
2655  // Merge GET with defaultGetVars
2656  if (!empty($this->config['config']['defaultGetVars.'])) {
2657  $modifiedGetVars = GeneralUtility::removeDotsFromTS($this->config['config']['defaultGetVars.']);
2659  GeneralUtility::_GETset($modifiedGetVars);
2660  }
2661  // Hook for postProcessing the configuration array
2662  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'])) {
2663  $params = array('config' => &$this->config['config']);
2664  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['configArrayPostProc'] as $funcRef) {
2665  GeneralUtility::callUserFunction($funcRef, $params, $this);
2666  }
2667  }
2668  }
2669 
2670  /********************************************
2671  *
2672  * Further initialization and data processing
2673  * (jumpurl/submission of forms)
2674  *
2675  *******************************************/
2676 
2686  public function getCompressedTCarray() {
2687  // Full TCA is always loaded during bootstrap in FE, this method is obsolete.
2689  }
2690 
2703  public function includeTCA($TCAloaded = 1) {
2704  // Full TCA is always loaded during bootstrap in FE, this method is obsolete.
2706 
2707  // Compatibility layer:
2708  // The if below is NOT true in usual frontend (non eid) context, TCA is loaded by bootstrap.
2709  // If an eid script calls this method to load TCA, use
2710  // \TYPO3\CMS\Frontend\Utility\EidUtility::initTCA() instead.
2711  if (!isset($GLOBALS['TCA']['pages'])) {
2713  }
2714  }
2715 
2723  public function settingLanguage() {
2724  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'])) {
2725  $_params = array();
2726  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_preProcess'] as $_funcRef) {
2727  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2728  }
2729  }
2730 
2731  // Initialize charset settings etc.
2732  $this->initLLvars();
2733 
2734  // Get values from TypoScript:
2735  $this->sys_language_uid = ($this->sys_language_content = (int)$this->config['config']['sys_language_uid']);
2736  list($this->sys_language_mode, $sys_language_content) = GeneralUtility::trimExplode(';', $this->config['config']['sys_language_mode']);
2737  $this->sys_language_contentOL = $this->config['config']['sys_language_overlay'];
2738  // If sys_language_uid is set to another language than default:
2739  if ($this->sys_language_uid > 0) {
2740  // check whether a shortcut is overwritten by a translated page
2741  // we can only do this now, as this is the place where we get
2742  // to know about translations
2743  $this->checkTranslatedShortcut();
2744  // Request the overlay record for the sys_language_uid:
2745  $olRec = $this->sys_page->getPageOverlay($this->id, $this->sys_language_uid);
2746  if (!count($olRec)) {
2747  // If no OL record exists and a foreign language is asked for...
2748  if ($this->sys_language_uid) {
2749  // If requested translation is not available:
2750  if (GeneralUtility::hideIfNotTranslated($this->page['l18n_cfg'])) {
2751  $this->pageNotFoundAndExit('Page is not available in the requested language.');
2752  } else {
2753  switch ((string) $this->sys_language_mode) {
2754  case 'strict':
2755  $this->pageNotFoundAndExit('Page is not available in the requested language (strict).');
2756  break;
2757  case 'content_fallback':
2758  $fallBackOrder = GeneralUtility::intExplode(',', $sys_language_content);
2759  foreach ($fallBackOrder as $orderValue) {
2760  if ((string)$orderValue === '0' || count($this->sys_page->getPageOverlay($this->id, $orderValue))) {
2761  $this->sys_language_content = $orderValue;
2762  // Setting content uid (but leaving the sys_language_uid)
2763  break;
2764  }
2765  }
2766  break;
2767  case 'ignore':
2768  $this->sys_language_content = $this->sys_language_uid;
2769  break;
2770  default:
2771  // Default is that everything defaults to the default language...
2772  $this->sys_language_uid = ($this->sys_language_content = 0);
2773  }
2774  }
2775  }
2776  } else {
2777  // Setting sys_language if an overlay record was found (which it is only if a language is used)
2778  $this->page = $this->sys_page->getPageOverlay($this->page, $this->sys_language_uid);
2779  }
2780  }
2781  // Setting sys_language_uid inside sys-page:
2782  $this->sys_page->sys_language_uid = $this->sys_language_uid;
2783  // If default translation is not available:
2784  if ((!$this->sys_language_uid || !$this->sys_language_content) && GeneralUtility::hideIfDefaultLanguage($this->page['l18n_cfg'])) {
2785  $message = 'Page is not available in default language.';
2786  GeneralUtility::sysLog($message, 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
2787  $this->pageNotFoundAndExit($message);
2788  }
2790  // Finding the ISO code:
2791  if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('static_info_tables') && $this->sys_language_content) {
2792  // using sys_language_content because the ISO code only (currently) affect content selection from FlexForms - which should follow "sys_language_content"
2793  // Set the fourth parameter to TRUE in the next two getRawRecord() calls to
2794  // avoid versioning overlay to be applied as it generates an SQL error
2795  $sys_language_row = $this->sys_page->getRawRecord('sys_language', $this->sys_language_content, 'static_lang_isocode', TRUE);
2796  if (is_array($sys_language_row) && $sys_language_row['static_lang_isocode']) {
2797  $stLrow = $this->sys_page->getRawRecord('static_languages', $sys_language_row['static_lang_isocode'], 'lg_iso_2', TRUE);
2798  $this->sys_language_isocode = $stLrow['lg_iso_2'];
2799  }
2800  }
2801  // Setting softMergeIfNotBlank:
2802  $table_fields = GeneralUtility::trimExplode(',', $this->config['config']['sys_language_softMergeIfNotBlank'], TRUE);
2803  foreach ($table_fields as $TF) {
2804  list($tN, $fN) = explode(':', $TF);
2805  $GLOBALS['TCA'][$tN]['columns'][$fN]['l10n_mode'] = 'mergeIfNotBlank';
2806  }
2807  // Setting softExclude:
2808  $table_fields = GeneralUtility::trimExplode(',', $this->config['config']['sys_language_softExclude'], TRUE);
2809  foreach ($table_fields as $TF) {
2810  list($tN, $fN) = explode(':', $TF);
2811  $GLOBALS['TCA'][$tN]['columns'][$fN]['l10n_mode'] = 'exclude';
2812  }
2813  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'])) {
2814  $_params = array();
2815  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['settingLanguage_postProcess'] as $_funcRef) {
2816  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
2817  }
2818  }
2819  }
2820 
2824  protected function updateRootLinesWithTranslations() {
2825  if ($this->sys_language_uid) {
2826  $this->rootLine = $this->sys_page->getRootLine($this->id, $this->MP);
2827  $this->tmpl->updateRootlineData($this->rootLine);
2828  }
2829  }
2830 
2836  public function settingLocale() {
2837  // Setting locale
2838  if ($this->config['config']['locale_all']) {
2839  // There's a problem that PHP parses float values in scripts wrong if the
2840  // locale LC_NUMERIC is set to something with a comma as decimal point
2841  // Do we set all except LC_NUMERIC
2842  $locale = setlocale(LC_COLLATE, $this->config['config']['locale_all']);
2843  if ($locale) {
2844  // PHP fatals with uppercase I characters in method names with turkish locale LC_CTYPE
2845  // @see http://bugs.php.net/bug.php?id=35050
2846  if (substr($this->config['config']['locale_all'], 0, 2) != 'tr') {
2847  setlocale(LC_CTYPE, $this->config['config']['locale_all']);
2848  }
2849  setlocale(LC_MONETARY, $this->config['config']['locale_all']);
2850  setlocale(LC_TIME, $this->config['config']['locale_all']);
2851  $this->localeCharset = $this->csConvObj->get_locale_charset($this->config['config']['locale_all']);
2852  } else {
2853  $GLOBALS['TT']->setTSlogMessage('Locale "' . htmlspecialchars($this->config['config']['locale_all']) . '" not found.', 3);
2854  }
2855  }
2856  }
2857 
2867  protected function checkTranslatedShortcut() {
2868  if (!is_null($this->originalShortcutPage)) {
2869  $originalShortcutPageOverlay = $this->sys_page->getPageOverlay($this->originalShortcutPage['uid'], $this->sys_language_uid);
2870  if (!empty($originalShortcutPageOverlay['shortcut']) && $originalShortcutPageOverlay['shortcut'] != $this->id) {
2871  // the translation of the original shortcut page has a different shortcut target!
2872  // set the correct page and id
2873  $shortcut = $this->getPageShortcut($originalShortcutPageOverlay['shortcut'], $originalShortcutPageOverlay['shortcut_mode'], $originalShortcutPageOverlay['uid']);
2874  $this->id = ($this->contentPid = $shortcut['uid']);
2875  $this->page = $this->sys_page->getPage($this->id);
2876  // Fix various effects on things like menus f.e.
2877  $this->fetch_the_id();
2878  $this->tmpl->rootLine = array_reverse($this->rootLine);
2879  }
2880  }
2881  }
2882 
2888  public function handleDataSubmission() {
2889  // Check Submission of data.
2890  // This is done at this point, because we need the config values
2891  switch ($this->checkDataSubmission()) {
2892  case 'email':
2893  $this->sendFormmail();
2894  break;
2895  }
2896  }
2897 
2903  protected function checkDataSubmission() {
2904  $ret = '';
2905  $formtype_mail = isset($_POST['formtype_mail']) || isset($_POST['formtype_mail_x']);
2906  if ($formtype_mail) {
2907  $refInfo = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
2908  if (GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY') == $refInfo['host'] || $this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer']) {
2909  if ($this->locDataCheck($_POST['locationData'])) {
2910  if ($formtype_mail) {
2911  $ret = 'email';
2912  }
2913  $GLOBALS['TT']->setTSlogMessage('"Check Data Submission": Return value: ' . $ret, 0);
2914  return $ret;
2915  }
2916  } else {
2917  $GLOBALS['TT']->setTSlogMessage('"Check Data Submission": HTTP_HOST and REFERER HOST did not match when processing submitted formdata!', 3);
2918  }
2919  }
2920  // Hook for processing data submission to extensions:
2921  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'])) {
2922  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['checkDataSubmission'] as $_classRef) {
2923  $_procObj = GeneralUtility::getUserObj($_classRef);
2924  $_procObj->checkDataSubmission($this);
2925  }
2926  }
2927  return $ret;
2928  }
2929 
2939  public function locDataCheck($locationData) {
2940  $locData = explode(':', $locationData);
2941  if (!$locData[1] || $this->sys_page->checkRecord($locData[1], $locData[2], 1)) {
2942  // $locData[1] -check means that a record is checked only if the locationData has a value for a record else than the page.
2943  if (count($this->sys_page->getPage($locData[0]))) {
2944  return 1;
2945  } else {
2946  $GLOBALS['TT']->setTSlogMessage('LocationData Error: The page pointed to by location data (' . $locationData . ') was not accessible.', 2);
2947  }
2948  } else {
2949  $GLOBALS['TT']->setTSlogMessage('LocationData Error: Location data (' . $locationData . ') record pointed to was not accessible.', 2);
2950  }
2951  }
2952 
2959  protected function sendFormmail() {
2961  $formmail = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Controller\\DataSubmissionController');
2962  $EMAIL_VARS = GeneralUtility::_POST();
2963  $locationData = $EMAIL_VARS['locationData'];
2964  unset($EMAIL_VARS['locationData']);
2965  unset($EMAIL_VARS['formtype_mail'], $EMAIL_VARS['formtype_mail_x'], $EMAIL_VARS['formtype_mail_y']);
2966  $integrityCheck = $this->TYPO3_CONF_VARS['FE']['strictFormmail'];
2967  if (!$this->TYPO3_CONF_VARS['FE']['secureFormmail']) {
2968  // Check recipient field:
2969  // These two fields are the ones which contain recipient addresses that can be misused to send mail from foreign servers.
2970  $encodedFields = explode(',', 'recipient, recipient_copy');
2971  foreach ($encodedFields as $fieldKey) {
2972  if (strlen($EMAIL_VARS[$fieldKey])) {
2973  // Decode...
2974  if ($res = $this->codeString($EMAIL_VARS[$fieldKey], TRUE)) {
2975  $EMAIL_VARS[$fieldKey] = $res;
2976  } elseif ($integrityCheck) {
2977  // Otherwise abort:
2978  $GLOBALS['TT']->setTSlogMessage('"Formmail" discovered a field (' . $fieldKey . ') which could not be decoded to a valid string. Sending formmail aborted due to security reasons!', 3);
2979  return FALSE;
2980  } else {
2981  $GLOBALS['TT']->setTSlogMessage('"Formmail" discovered a field (' . $fieldKey . ') which could not be decoded to a valid string. The security level accepts this, but you should consider a correct coding though!', 2);
2982  }
2983  }
2984  }
2985  } else {
2986  $locData = explode(':', $locationData);
2987  $record = $this->sys_page->checkRecord($locData[1], $locData[2], 1);
2988  $EMAIL_VARS['recipient'] = $record['subheader'];
2989  $EMAIL_VARS['recipient_copy'] = $this->extractRecipientCopy($record['bodytext']);
2990  }
2991  // Hook for preprocessing of the content for formmails:
2992  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['sendFormmail-PreProcClass'])) {
2993  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['sendFormmail-PreProcClass'] as $_classRef) {
2994  $_procObj = GeneralUtility::getUserObj($_classRef);
2995  $EMAIL_VARS = $_procObj->sendFormmail_preProcessVariables($EMAIL_VARS, $this);
2996  }
2997  }
2998  $formmail->start($EMAIL_VARS);
2999  $formmail->sendtheMail();
3000  $GLOBALS['TT']->setTSlogMessage('"Formmail" invoked, sending mail to ' . $EMAIL_VARS['recipient'], 0);
3001  }
3002 
3010  public function extractRecipientCopy($bodytext) {
3011  $recipient_copy = '';
3012  $fdef = array();
3013  //|recipient_copy=hidden|karsten@localhost.localdomain
3014  preg_match('/^[\\s]*\\|[\\s]*recipient_copy[\\s]*=[\\s]*hidden[\\s]*\\|(.*)$/m', $bodytext, $fdef);
3015  $recipient_copy = $fdef[1] ?: '';
3016  return $recipient_copy;
3017  }
3018 
3024  public function setExternalJumpUrl() {
3025  if ($extUrl = $this->sys_page->getExtURL($this->page, $this->config['config']['disablePageExternalUrl'])) {
3026  $this->jumpurl = $extUrl;
3027  GeneralUtility::_GETset(GeneralUtility::hmac($this->jumpurl, 'jumpurl'), 'juHash');
3028  }
3029  }
3030 
3036  public function checkJumpUrlReferer() {
3037  if (strlen($this->jumpurl) && !$this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer']) {
3038  $referer = parse_url(GeneralUtility::getIndpEnv('HTTP_REFERER'));
3039  if (isset($referer['host']) && !($referer['host'] == GeneralUtility::getIndpEnv('TYPO3_HOST_ONLY'))) {
3040  unset($this->jumpurl);
3041  }
3042  }
3043  }
3044 
3054  public function jumpUrl() {
3055  if ($this->jumpurl) {
3056  if (GeneralUtility::_GP('juSecure')) {
3057  $locationData = (string) GeneralUtility::_GP('locationData');
3058  // Need a type cast here because mimeType is optional!
3059  $mimeType = (string) GeneralUtility::_GP('mimeType');
3060  $hArr = array(
3061  $this->jumpurl,
3062  $locationData,
3063  $mimeType
3064  );
3065  $calcJuHash = GeneralUtility::hmac(serialize($hArr));
3066  $juHash = (string) GeneralUtility::_GP('juHash');
3067  if ($juHash === $calcJuHash) {
3068  if ($this->locDataCheck($locationData)) {
3069  // 211002 - goes with cObj->filelink() rawurlencode() of filenames so spaces can be allowed.
3070  $this->jumpurl = rawurldecode($this->jumpurl);
3071  // Deny access to files that match TYPO3_CONF_VARS[SYS][fileDenyPattern] and whose parent directory is typo3conf/ (there could be a backup file in typo3conf/ which does not match against the fileDenyPattern)
3072  $absoluteFileName = GeneralUtility::getFileAbsFileName(GeneralUtility::resolveBackPath($this->jumpurl), FALSE);
3073  if (GeneralUtility::isAllowedAbsPath($absoluteFileName) && GeneralUtility::verifyFilenameAgainstDenyPattern($absoluteFileName) && !GeneralUtility::isFirstPartOfStr($absoluteFileName, (PATH_site . 'typo3conf'))) {
3074  if (@is_file($absoluteFileName)) {
3075  $mimeType = $mimeType ?: 'application/octet-stream';
3076  header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
3077  header('Content-Type: ' . $mimeType);
3078  header('Content-Disposition: attachment; filename="' . basename($absoluteFileName) . '"');
3079  header('Content-Length: ' . filesize($absoluteFileName));
3081  readfile($absoluteFileName);
3082  die;
3083  } else {
3084  throw new \Exception('jumpurl Secure: "' . $this->jumpurl . '" was not a valid file!', 1294585193);
3085  }
3086  } else {
3087  throw new \Exception('jumpurl Secure: The requested file was not allowed to be accessed through jumpUrl (path or file not allowed)!', 1294585194);
3088  }
3089  } else {
3090  throw new \Exception('jumpurl Secure: locationData, ' . $locationData . ', was not accessible.', 1294585195);
3091  }
3092  } else {
3093  throw new \Exception('jumpurl Secure: Calculated juHash did not match the submitted juHash.', 1294585196);
3094  }
3095  } else {
3096  $allowRedirect = FALSE;
3097  if (GeneralUtility::hmac($this->jumpurl, 'jumpurl') === (string)GeneralUtility::_GP('juHash')) {
3098  $allowRedirect = TRUE;
3099  } elseif (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['jumpurlRedirectHandler'])) {
3100  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['jumpurlRedirectHandler'] as $classReference) {
3101  $hookObject = GeneralUtility::getUserObj($classReference);
3102  $allowRedirectFromHook = FALSE;
3103  if (method_exists($hookObject, 'jumpurlRedirectHandler')) {
3104  $allowRedirectFromHook = $hookObject->jumpurlRedirectHandler($this->jumpurl, $this);
3105  }
3106  if ($allowRedirectFromHook === TRUE) {
3107  $allowRedirect = TRUE;
3108  break;
3109  }
3110  }
3111  }
3112  if ($allowRedirect) {
3113  $TSConf = $this->getPagesTSconfig();
3114  if ($TSConf['TSFE.']['jumpUrl_transferSession']) {
3115  $uParts = parse_url($this->jumpurl);
3116  $params = '&FE_SESSION_KEY=' . rawurlencode(($this->fe_user->id . '-' . md5(($this->fe_user->id . '/' . $this->TYPO3_CONF_VARS['SYS']['encryptionKey']))));
3117  // Add the session parameter ...
3118  $this->jumpurl .= ($uParts['query'] ? '' : '?') . $params;
3119  }
3120  $statusCode = HttpUtility::HTTP_STATUS_303;
3121  if ($TSConf['TSFE.']['jumpURL_HTTPStatusCode']) {
3122  switch ((int)$TSConf['TSFE.']['jumpURL_HTTPStatusCode']) {
3123  case 301:
3124  $statusCode = HttpUtility::HTTP_STATUS_301;
3125  break;
3126  case 302:
3127  $statusCode = HttpUtility::HTTP_STATUS_302;
3128  break;
3129  case 307:
3130  $statusCode = HttpUtility::HTTP_STATUS_307;
3131  break;
3132  }
3133  }
3134  HttpUtility::redirect($this->jumpurl, $statusCode);
3135  } else {
3136  throw new \Exception('jumpurl: Calculated juHash did not match the submitted juHash.', 1359987599);
3137  }
3138  }
3139  }
3140  }
3141 
3149  public function setUrlIdToken() {
3150  if ($this->config['config']['ftu']) {
3151  $this->getMethodUrlIdToken = $this->TYPO3_CONF_VARS['FE']['get_url_id_token'];
3152  } else {
3153  $this->getMethodUrlIdToken = '';
3154  }
3155  }
3156 
3163  public function calculateLinkVars() {
3164  $this->linkVars = '';
3165  $linkVars = GeneralUtility::trimExplode(',', (string) $this->config['config']['linkVars']);
3166  if (empty($linkVars)) {
3167  return;
3168  }
3169  $getData = GeneralUtility::_GET();
3170  foreach ($linkVars as $linkVar) {
3171  $test = ($value = '');
3172  if (preg_match('/^(.*)\\((.+)\\)$/', $linkVar, $match)) {
3173  $linkVar = trim($match[1]);
3174  $test = trim($match[2]);
3175  }
3176  if ($linkVar === '' || !isset($getData[$linkVar])) {
3177  continue;
3178  }
3179  if (!is_array($getData[$linkVar])) {
3180  $temp = rawurlencode($getData[$linkVar]);
3181  if ($test !== '' && !\TYPO3\CMS\Frontend\Page\PageGenerator::isAllowedLinkVarValue($temp, $test)) {
3182  // Error: This value was not allowed for this key
3183  continue;
3184  }
3185  $value = '&' . $linkVar . '=' . $temp;
3186  } else {
3187  if ($test !== '' && $test !== 'array') {
3188  // Error: This key must not be an array!
3189  continue;
3190  }
3191  $value = GeneralUtility::implodeArrayForUrl($linkVar, $getData[$linkVar]);
3192  }
3193  $this->linkVars .= $value;
3194  }
3195  }
3196 
3206  if (!empty($this->originalMountPointPage) && $this->originalMountPointPage['doktype'] == PageRepository::DOKTYPE_MOUNTPOINT) {
3207  $this->redirectToCurrentPage();
3208  }
3209  }
3210 
3219  public function checkPageForShortcutRedirect() {
3220  if (!empty($this->originalShortcutPage) && $this->originalShortcutPage['doktype'] == PageRepository::DOKTYPE_SHORTCUT) {
3221  $this->redirectToCurrentPage();
3222  }
3223  }
3224 
3231  protected function redirectToCurrentPage() {
3232  $this->calculateLinkVars();
3233  // instantiate tslib_content to generate the correct target URL
3235  $cObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
3236  $parameter = $this->page['uid'];
3237  $type = GeneralUtility::_GET('type');
3238  if ($type) {
3239  $parameter .= ',' . $type;
3240  }
3241  $redirectUrl = $cObj->typoLink_URL(array('parameter' => $parameter));
3242 
3243  // Prevent redirection loop
3244  if (!empty($redirectUrl)) {
3245  // redirect and exit
3247  }
3248  }
3249 
3250  /********************************************
3251  *
3252  * Page generation; cache handling
3253  *
3254  *******************************************/
3261  public function isGeneratePage() {
3262  return !$this->cacheContentFlag && !$this->jumpurl;
3263  }
3264 
3272  public function tempPageCacheContent() {
3273  $this->tempContent = FALSE;
3274  if (!$this->no_cache) {
3275  $seconds = 30;
3276  $title = htmlspecialchars($this->tmpl->printTitle($this->page['title']));
3277  $request_uri = htmlspecialchars(GeneralUtility::getIndpEnv('REQUEST_URI'));
3278  $stdMsg = '
3279  <strong>Page is being generated.</strong><br />
3280  If this message does not disappear within ' . $seconds . ' seconds, please reload.';
3281  $message = $this->config['config']['message_page_is_being_generated'];
3282  if ((string)$message !== '') {
3283  // This page is always encoded as UTF-8
3284  $message = $this->csConvObj->utf8_encode($message, $this->renderCharset);
3285  $message = str_replace('###TITLE###', $title, $message);
3286  $message = str_replace('###REQUEST_URI###', $request_uri, $message);
3287  } else {
3288  $message = $stdMsg;
3289  }
3290  $temp_content = '<?xml version="1.0" encoding="UTF-8"?>
3291 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
3292  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3293 <html xmlns="http://www.w3.org/1999/xhtml">
3294  <head>
3295  <title>' . $title . '</title>
3296  <meta http-equiv="refresh" content="10" />
3297  </head>
3298  <body style="background-color:white; font-family:Verdana,Arial,Helvetica,sans-serif; color:#cccccc; text-align:center;">' . $message . '
3299  </body>
3300 </html>';
3301  // Fix 'nice errors' feature in modern browsers
3302  $padSuffix = '<!--pad-->';
3303  // prevent any trims
3304  $padSize = 768 - strlen($padSuffix) - strlen($temp_content);
3305  if ($padSize > 0) {
3306  $temp_content = str_pad($temp_content, $padSize, LF) . $padSuffix;
3307  }
3308  if (!$this->headerNoCache() && ($cachedRow = $this->getFromCache_queryRow())) {
3309  // We are here because between checking for cached content earlier and now some other HTTP-process managed to store something in cache AND it was not due to a shift-reload by-pass.
3310  // This is either the "Page is being generated" screen or it can be the final result.
3311  // In any case we should not begin another rendering process also, so we silently disable caching and render the page ourselves and that's it.
3312  // Actually $cachedRow contains content that we could show instead of rendering. Maybe we should do that to gain more performance but then we should set all the stuff done in $this->getFromCache()... For now we stick to this...
3313  $this->set_no_cache('Another process wrote into the cache since the beginning of the render process', TRUE);
3314  } else {
3315  $this->tempContent = TRUE;
3316  // This flag shows that temporary content is put in the cache
3317  $this->setPageCacheContent($temp_content, $this->config, $GLOBALS['EXEC_TIME'] + $seconds);
3318  }
3319  }
3320  }
3321 
3328  public function realPageCacheContent() {
3329  // seconds until a cached page is too old
3330  $cacheTimeout = $this->get_cache_timeout();
3331  $timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;
3332  $this->tempContent = FALSE;
3333  $usePageCache = TRUE;
3334  // Hook for deciding whether page cache should be written to the cache backend or not
3335  // NOTE: as hooks are called in a loop, the last hook will have the final word (however each
3336  // hook receives the current status of the $usePageCache flag)
3337  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'])) {
3338  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['usePageCache'] as $_classRef) {
3339  $_procObj = GeneralUtility::getUserObj($_classRef);
3340  $usePageCache = $_procObj->usePageCache($this, $usePageCache);
3341  }
3342  }
3343  // Write the page to cache, if necessary
3344  if ($usePageCache) {
3345  $this->setPageCacheContent($this->content, $this->config, $timeOutTime);
3346  }
3347  // Hook for cache post processing (eg. writing static files!)
3348  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'])) {
3349  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['insertPageIncache'] as $_classRef) {
3350  $_procObj = GeneralUtility::getUserObj($_classRef);
3351  $_procObj->insertPageIncache($this, $timeOutTime);
3352  }
3353  }
3354  }
3355 
3366  public function setPageCacheContent($content, $data, $expirationTstamp) {
3367  $cacheData = array(
3368  'identifier' => $this->newHash,
3369  'page_id' => $this->id,
3370  'content' => $content,
3371  'temp_content' => $this->tempContent,
3372  'cache_data' => $data,
3373  'expires' => $expirationTstamp,
3374  'tstamp' => $GLOBALS['EXEC_TIME'],
3375  'pageTitleInfo' => array(
3376  'title' => $this->page['title'],
3377  'altPageTitle' => $this->altPageTitle,
3378  'indexedDocTitle' => $this->indexedDocTitle
3379  )
3380  );
3381  $this->cacheExpires = $expirationTstamp;
3382  $this->pageCacheTags[] = 'pageId_' . $cacheData['page_id'];
3383  if ($this->page_cache_reg1) {
3384  $reg1 = (int)$this->page_cache_reg1;
3385  $cacheData['reg1'] = $reg1;
3386  $this->pageCacheTags[] = 'reg1_' . $reg1;
3387  }
3388  if (!empty($this->page['cache_tags'])) {
3389  $tags = GeneralUtility::trimExplode(',', $this->page['cache_tags'], TRUE);
3390  $this->pageCacheTags = array_merge($this->pageCacheTags, $tags);
3391  }
3392  $this->pageCache->set($this->newHash, $cacheData, $this->pageCacheTags, $expirationTstamp - $GLOBALS['EXEC_TIME']);
3393  }
3394 
3401  public function clearPageCacheContent() {
3402  $this->pageCache->remove($this->newHash);
3403  }
3404 
3412  public function clearPageCacheContent_pidList($pidList) {
3413  $pageIds = GeneralUtility::trimExplode(',', $pidList);
3414  foreach ($pageIds as $pageId) {
3415  $this->pageCache->flushByTag('pageId_' . (int)$pageId);
3416  }
3417  }
3418 
3427  public function setSysLastChanged() {
3428  if ($this->page['SYS_LASTCHANGED'] < (int)$this->register['SYS_LASTCHANGED']) {
3429  $GLOBALS['TYPO3_DB']->exec_UPDATEquery('pages', 'uid=' . (int)$this->id, array('SYS_LASTCHANGED' => (int)$this->register['SYS_LASTCHANGED']));
3430  }
3431  }
3432 
3443  public function acquirePageGenerationLock(&$lockObj, $key) {
3444  if ($this->no_cache || $this->headerNoCache()) {
3445  GeneralUtility::sysLog('Locking: Page is not cached, no locking required', 'cms', GeneralUtility::SYSLOG_SEVERITY_INFO);
3446  // No locking is needed if caching is disabled
3447  return TRUE;
3448  }
3449  try {
3450  if (!is_object($lockObj)) {
3451  $lockObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Locking\\Locker', $key, $this->TYPO3_CONF_VARS['SYS']['lockingMode']);
3452  }
3453  $success = FALSE;
3454  if (strlen($key)) {
3455  // TRUE = Page could get locked without blocking
3456  // FALSE = Page could get locked but process was blocked before
3457  $success = $lockObj->acquire();
3458  if ($lockObj->getLockStatus()) {
3459  $lockObj->sysLog('Acquired lock');
3460  }
3461  }
3462  } catch (\Exception $e) {
3463  GeneralUtility::sysLog('Locking: Failed to acquire lock: ' . $e->getMessage(), 'cms', GeneralUtility::SYSLOG_SEVERITY_ERROR);
3464  // If locking fails, return with FALSE and continue without locking
3465  $success = FALSE;
3466  }
3467  return $success;
3468  }
3469 
3478  public function releasePageGenerationLock(&$lockObj) {
3479  $success = FALSE;
3480  // If lock object is set and was acquired (may also happen if no_cache was enabled during runtime), release it:
3481  if (is_object($lockObj) && $lockObj instanceof \TYPO3\CMS\Core\Locking\Locker && $lockObj->getLockStatus()) {
3482  $success = $lockObj->release();
3483  $lockObj->sysLog('Released lock');
3484  $lockObj = NULL;
3485  } elseif ($this->no_cache || $this->headerNoCache()) {
3486  $success = TRUE;
3487  }
3488  return $success;
3489  }
3490 
3498  public function addCacheTags(array $tags) {
3499  $this->pageCacheTags = array_merge($this->pageCacheTags, $tags);
3500  }
3501 
3502  /********************************************
3503  *
3504  * Page generation; rendering and inclusion
3505  *
3506  *******************************************/
3512  public function generatePage_preProcessing() {
3513  // Same codeline as in getFromCache(). But $this->all has been changed by
3514  // \TYPO3\CMS\Core\TypoScript\TemplateService::start() in the meantime, so this must be called again!
3515  $this->newHash = $this->getHash();
3516  if (!is_object($this->pages_lockObj) || $this->pages_lockObj->getLockStatus() == FALSE) {
3517  // Here we put some temporary stuff in the cache in order to let the first hit generate the page. The temporary cache will expire after a few seconds (typ. 30) or will be cleared by the rendered page, which will also clear and rewrite the cache.
3518  $this->tempPageCacheContent();
3519  }
3520  // Setting cache_timeout_default. May be overridden by PHP include scripts.
3521  $this->cacheTimeOutDefault = (int)$this->config['config']['cache_period'];
3522  // Page is generated
3523  $this->no_cacheBeforePageGen = $this->no_cache;
3524  }
3525 
3532  public function generatePage_whichScript() {
3533  if (!$this->TYPO3_CONF_VARS['FE']['noPHPscriptInclude'] && $this->config['config']['pageGenScript']) {
3534  return $this->tmpl->getFileName($this->config['config']['pageGenScript']);
3535  }
3536  }
3537 
3544  public function generatePage_postProcessing() {
3545  // This is to ensure, that the page is NOT cached if the no_cache parameter was set before the page was generated. This is a safety precaution, as it could have been unset by some script.
3546  if ($this->no_cacheBeforePageGen) {
3547  $this->set_no_cache('no_cache has been set before the page was generated - safety check', TRUE);
3548  }
3549  // XHTML-clean the code, if flag set
3550  if ($this->doXHTML_cleaning() == 'all') {
3551  $GLOBALS['TT']->push('XHTML clean, all', '');
3552  $XHTML_clean = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
3553  $this->content = $XHTML_clean->XHTML_clean($this->content);
3554  $GLOBALS['TT']->pull();
3555  }
3556  // Fix local anchors in links, if flag set
3557  if ($this->doLocalAnchorFix() == 'all') {
3558  $GLOBALS['TT']->push('Local anchor fix, all', '');
3560  $GLOBALS['TT']->pull();
3561  }
3562  // Hook for post-processing of page content cached/non-cached:
3563  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'])) {
3564  $_params = array('pObj' => &$this);
3565  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-all'] as $_funcRef) {
3566  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
3567  }
3568  }
3569  // Processing if caching is enabled:
3570  if (!$this->no_cache) {
3571  // XHTML-clean the code, if flag set
3572  if ($this->doXHTML_cleaning() == 'cached') {
3573  $GLOBALS['TT']->push('XHTML clean, cached', '');
3574  $XHTML_clean = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
3575  $this->content = $XHTML_clean->XHTML_clean($this->content);
3576  $GLOBALS['TT']->pull();
3577  }
3578  // Fix local anchors in links, if flag set
3579  if ($this->doLocalAnchorFix() == 'cached') {
3580  $GLOBALS['TT']->push('Local anchor fix, cached', '');
3582  $GLOBALS['TT']->pull();
3583  }
3584  // Hook for post-processing of page content before being cached:
3585  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'])) {
3586  $_params = array('pObj' => &$this);
3587  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-cached'] as $_funcRef) {
3588  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
3589  }
3590  }
3591  }
3592  // Convert char-set for output: (should be BEFORE indexing of the content (changed 22/4 2005)), because otherwise indexed search might convert from the wrong charset! One thing is that the charset mentioned in the HTML header would be wrong since the output charset (metaCharset) has not been converted to from renderCharset. And indexed search will internally convert from metaCharset to renderCharset so the content MUST be in metaCharset already!
3593  $this->content = $this->convOutputCharset($this->content, 'mainpage');
3594  // Hook for indexing pages
3595  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'])) {
3596  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['pageIndexing'] as $_classRef) {
3597  $_procObj = GeneralUtility::getUserObj($_classRef);
3598  $_procObj->hook_indexContent($this);
3599  }
3600  }
3601  // Storing for cache:
3602  if (!$this->no_cache) {
3603  $this->realPageCacheContent();
3604  } elseif ($this->tempContent) {
3605  // If there happens to be temporary content in the cache and the cache was not cleared due to new content, put it in... ($this->no_cache=0)
3606  $this->clearPageCacheContent();
3607  $this->tempContent = FALSE;
3608  }
3609  // Release open locks
3610  $this->releasePageGenerationLock($this->pagesection_lockObj);
3611  $this->releasePageGenerationLock($this->pages_lockObj);
3612  // Sets sys-last-change:
3613  $this->setSysLastChanged();
3614  }
3615 
3621  protected function regeneratePageTitle() {
3623  }
3624 
3630  public function INTincScript() {
3631  // Deprecated stuff:
3632  // @deprecated: annotation added TYPO3 4.6
3633  $this->additionalHeaderData = is_array($this->config['INTincScript_ext']['additionalHeaderData']) ? $this->config['INTincScript_ext']['additionalHeaderData'] : array();
3634  $this->additionalFooterData = is_array($this->config['INTincScript_ext']['additionalFooterData']) ? $this->config['INTincScript_ext']['additionalFooterData'] : array();
3635  $this->additionalJavaScript = $this->config['INTincScript_ext']['additionalJavaScript'];
3636  $this->additionalCSS = $this->config['INTincScript_ext']['additionalCSS'];
3637  $this->JSImgCode = $this->additionalHeaderData['JSImgCode'];
3638  $this->divSection = '';
3639  if (!empty($this->config['INTincScript_ext']['pageRenderer'])) {
3641  $pageRenderer = unserialize($this->config['INTincScript_ext']['pageRenderer']);
3642  $this->pageRenderer = $pageRenderer;
3643  GeneralUtility::setSingletonInstance('TYPO3\\CMS\\Core\\Page\\PageRenderer', $pageRenderer);
3644  }
3645 
3647  $GLOBALS['TT']->push('Substitute header section');
3648  $this->INTincScript_loadJSCode();
3649  $this->regeneratePageTitle();
3650 
3651  $this->content = str_replace(
3652  array(
3653  '<!--HD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
3654  '<!--FD_' . $this->config['INTincScript_ext']['divKey'] . '-->',
3655  '<!--TDS_' . $this->config['INTincScript_ext']['divKey'] . '-->'
3656  ),
3657  array(
3658  $this->convOutputCharset(implode(LF, $this->additionalHeaderData), 'HD'),
3659  $this->convOutputCharset(implode(LF, $this->additionalFooterData), 'FD'),
3660  $this->convOutputCharset($this->divSection, 'TDS'),
3661  ),
3662  $this->getPageRenderer()->renderJavaScriptAndCssForProcessingOfUncachedContentObjects($this->content, $this->config['INTincScript_ext']['divKey'])
3663  );
3664  // Replace again, because header and footer data and page renderer replacements may introduce additional placeholders (see #44825)
3666  $this->setAbsRefPrefix();
3667  $GLOBALS['TT']->pull();
3668  }
3669 
3676  do {
3677  $INTiS_config = $this->config['INTincScript'];
3678  $this->INTincScript_includeLibs($INTiS_config);
3679  $this->INTincScript_process($INTiS_config);
3680  // Check if there were new items added to INTincScript during the previous execution:
3681  $INTiS_config = array_diff_assoc($this->config['INTincScript'], $INTiS_config);
3682  $reprocess = count($INTiS_config) > 0;
3683  } while ($reprocess);
3684  }
3685 
3693  protected function INTincScript_includeLibs($INTiS_config) {
3694  foreach ($INTiS_config as $INTiS_cPart) {
3695  if (isset($INTiS_cPart['conf']['includeLibs']) && $INTiS_cPart['conf']['includeLibs']) {
3696  $INTiS_resourceList = GeneralUtility::trimExplode(',', $INTiS_cPart['conf']['includeLibs'], TRUE);
3697  $this->includeLibraries($INTiS_resourceList);
3698  }
3699  }
3700  }
3701 
3709  protected function INTincScript_process($INTiS_config) {
3710  $GLOBALS['TT']->push('Split content');
3711  // Splits content with the key.
3712  $INTiS_splitC = explode('<!--INT_SCRIPT.', $this->content);
3713  $this->content = '';
3714  $GLOBALS['TT']->setTSlogMessage('Parts: ' . count($INTiS_splitC));
3715  $GLOBALS['TT']->pull();
3716  foreach ($INTiS_splitC as $INTiS_c => $INTiS_cPart) {
3717  // If the split had a comment-end after 32 characters it's probably a split-string
3718  if (substr($INTiS_cPart, 32, 3) === '-->') {
3719  $INTiS_key = 'INT_SCRIPT.' . substr($INTiS_cPart, 0, 32);
3720  if (is_array($INTiS_config[$INTiS_key])) {
3721  $GLOBALS['TT']->push('Include ' . $INTiS_config[$INTiS_key]['file'], '');
3722  $incContent = '';
3723  $INTiS_cObj = unserialize($INTiS_config[$INTiS_key]['cObj']);
3724  /* @var $INTiS_cObj \TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer */
3725  $INTiS_cObj->INT_include = 1;
3726  switch ($INTiS_config[$INTiS_key]['type']) {
3727  case 'COA':
3728  $incContent = $INTiS_cObj->COBJ_ARRAY($INTiS_config[$INTiS_key]['conf']);
3729  break;
3730  case 'FUNC':
3731  $incContent = $INTiS_cObj->USER($INTiS_config[$INTiS_key]['conf']);
3732  break;
3733  case 'POSTUSERFUNC':
3734  $incContent = $INTiS_cObj->callUserFunction($INTiS_config[$INTiS_key]['postUserFunc'], $INTiS_config[$INTiS_key]['conf'], $INTiS_config[$INTiS_key]['content']);
3735  break;
3736  }
3737  $this->content .= $this->convOutputCharset($incContent, 'INC-' . $INTiS_c);
3738  $this->content .= substr($INTiS_cPart, 35);
3739  $GLOBALS['TT']->pull($incContent);
3740  } else {
3741  $this->content .= substr($INTiS_cPart, 35);
3742  }
3743  } else {
3744  $this->content .= ($INTiS_c ? '<!--INT_SCRIPT.' : '') . $INTiS_cPart;
3745  }
3746  }
3747  }
3748 
3755  public function INTincScript_loadJSCode() {
3756  // If any images added, then add them to the javascript section
3757  $jsImgCode = trim($this->JSImgCode);
3758  if ($jsImgCode !== '') {
3759  $this->additionalHeaderData['JSImgCode'] = '
3760 <script type="text/javascript">
3761  /*<![CDATA[*/
3762 <!--
3763 if (version == "n3") {
3764 ' . $jsImgCode . '
3765 }
3766 // -->
3767  /*]]>*/
3768 </script>';
3769  }
3770  // Add javascript
3771  $jsCode = trim($this->JSCode);
3772  $additionalJavaScript = is_array($this->additionalJavaScript)
3773  ? implode(LF, $this->additionalJavaScript)
3776  if ($jsCode !== '' || $additionalJavaScript !== '') {
3777  $this->additionalHeaderData['JSCode'] = '
3778 <script type="text/javascript">
3779  /*<![CDATA[*/
3780 <!--
3781 ' . $additionalJavaScript . '
3782 ' . $jsCode . '
3783 // -->
3784  /*]]>*/
3785 </script>';
3786  }
3787  // Add CSS
3788  $additionalCss = is_array($this->additionalCSS) ? implode(LF, $this->additionalCSS) : $this->additionalCSS;
3789  $additionalCss = trim($additionalCss);
3790  if ($additionalCss !== '') {
3791  $this->additionalHeaderData['_CSS'] = '
3792 <style type="text/css">
3793 ' . $additionalCss . '
3794 </style>';
3795  }
3796  }
3797 
3803  public function isINTincScript() {
3804  return is_array($this->config['INTincScript']) && !$this->jumpurl;
3805  }
3806 
3813  public function doXHTML_cleaning() {
3814  return $this->config['config']['xhtml_cleaning'];
3815  }
3816 
3823  public function doLocalAnchorFix() {
3824  return isset($this->config['config']['prefixLocalAnchors']) ? $this->config['config']['prefixLocalAnchors'] : NULL;
3825  }
3826 
3827  /********************************************
3828  *
3829  * Finished off; outputting, storing session data, statistics...
3830  *
3831  *******************************************/
3838  public function isOutputting() {
3839  // Initialize by status of jumpUrl:
3840  $enableOutput = !$this->jumpurl;
3841  // Call hook for possible disabling of output:
3842  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'])) {
3843  $_params = array('pObj' => &$this, 'enableOutput' => &$enableOutput);
3844  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['isOutputting'] as $_funcRef) {
3845  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
3846  }
3847  }
3848  return $enableOutput;
3849  }
3850 
3858  public function processOutput() {
3859  // Set header for charset-encoding unless disabled
3860  if (empty($this->config['config']['disableCharsetHeader'])) {
3861  $headLine = 'Content-Type: text/html; charset=' . trim($this->metaCharset);
3862  header($headLine);
3863  }
3864  // Set cache related headers to client (used to enable proxy / client caching!)
3865  if (!empty($this->config['config']['sendCacheHeaders'])) {
3866  $this->sendCacheHeaders();
3867  }
3868  // Set headers, if any
3869  if (!empty($this->config['config']['additionalHeaders'])) {
3870  $headerArray = explode('|', $this->config['config']['additionalHeaders']);
3871  foreach ($headerArray as $headLine) {
3872  $headLine = trim($headLine);
3873  header($headLine);
3874  }
3875  }
3876  // Send appropriate status code in case of temporary content
3877  if ($this->tempContent) {
3878  $this->addTempContentHttpHeaders();
3879  }
3880  // Make substitution of eg. username/uid in content only if cache-headers for client/proxy caching is NOT sent!
3881  if (!$this->isClientCachable) {
3882  $this->contentStrReplace();
3883  }
3884  // XHTML-clean the code, if flag set
3885  if ($this->doXHTML_cleaning() == 'output') {
3886  $GLOBALS['TT']->push('XHTML clean, output', '');
3887  $XHTML_clean = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Html\\HtmlParser');
3888  $this->content = $XHTML_clean->XHTML_clean($this->content);
3889  $GLOBALS['TT']->pull();
3890  }
3891  // Fix local anchors in links, if flag set
3892  if ($this->doLocalAnchorFix() == 'output') {
3893  $GLOBALS['TT']->push('Local anchor fix, output', '');
3895  $GLOBALS['TT']->pull();
3896  }
3897  // Hook for post-processing of page content before output:
3898  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'])) {
3899  $_params = array('pObj' => &$this);
3900  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['contentPostProc-output'] as $_funcRef) {
3901  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
3902  }
3903  }
3904  // Send content-length header.
3905  // Notice that all HTML content outside the length of the content-length header will be cut off!
3906  // Therefore content of unknown length from included PHP-scripts and if admin users are logged
3907  // in (admin panel might show...) or if debug mode is turned on, we disable it!
3908  if (
3909  (!isset($this->config['config']['enableContentLengthHeader']) || $this->config['config']['enableContentLengthHeader'])
3910  && !$this->beUserLogin && !$this->TYPO3_CONF_VARS['FE']['debug']
3911  && !$this->config['config']['debug'] && !$this->doWorkspacePreview()
3912  ) {
3913  header('Content-Length: ' . strlen($this->content));
3914  }
3915  }
3916 
3925  public function sendCacheHeaders() {
3926  // Getting status whether we can send cache control headers for proxy caching:
3927  $doCache = $this->isStaticCacheble();
3928  // This variable will be TRUE unless cache headers are configured to be sent ONLY if a branch does not allow logins and logins turns out to be allowed anyway...
3929  $loginsDeniedCfg = empty($this->config['config']['sendCacheHeaders_onlyWhenLoginDeniedInBranch']) || empty($this->loginAllowedInBranch);
3930  // Finally, when backend users are logged in, do not send cache headers at all (Admin Panel might be displayed for instance).
3931  if ($doCache && !$this->beUserLogin && !$this->doWorkspacePreview() && $loginsDeniedCfg) {
3932  // Build headers:
3933  $headers = array(
3934  'Expires: ' . gmdate('D, d M Y H:i:s T', $this->cacheExpires),
3935  'ETag: "' . md5($this->content) . '"',
3936  'Cache-Control: max-age=' . ($this->cacheExpires - $GLOBALS['EXEC_TIME']),
3937  // no-cache
3938  'Pragma: public'
3939  );
3940  $this->isClientCachable = TRUE;
3941  } else {
3942  // Build headers:
3943  $headers = array(
3944  'Cache-Control: private'
3945  );
3946  $this->isClientCachable = FALSE;
3947  // Now, if a backend user is logged in, tell him in the Admin Panel log what the caching status would have been:
3948  if ($this->beUserLogin) {
3949  if ($doCache) {
3950  $GLOBALS['TT']->setTSlogMessage('Cache-headers with max-age "' . ($this->cacheExpires - $GLOBALS['EXEC_TIME']) . '" would have been sent');
3951  } else {
3952  $reasonMsg = '';
3953  $reasonMsg .= !$this->no_cache ? '' : 'Caching disabled (no_cache). ';
3954  $reasonMsg .= !$this->isINTincScript() ? '' : '*_INT object(s) on page. ';
3955  $reasonMsg .= !is_array($this->fe_user->user) ? '' : 'Frontend user logged in. ';
3956  $GLOBALS['TT']->setTSlogMessage('Cache-headers would disable proxy caching! Reason(s): "' . $reasonMsg . '"', 1);
3957  }
3958  }
3959  }
3960  // Send headers:
3961  foreach ($headers as $hL) {
3962  header($hL);
3963  }
3964  }
3965 
3977  public function isStaticCacheble() {
3978  $doCache = !$this->no_cache && !$this->isINTincScript() && !$this->isUserOrGroupSet();
3979  return $doCache;
3980  }
3981 
3988  public function contentStrReplace() {
3989  $search = array();
3990  $replace = array();
3991  // Substitutes username mark with the username
3992  if (!empty($this->fe_user->user['uid'])) {
3993  // User name:
3994  $token = isset($this->config['config']['USERNAME_substToken']) ? trim($this->config['config']['USERNAME_substToken']) : '';
3995  $search[] = $token ? $token : '<!--###USERNAME###-->';
3996  $replace[] = $this->fe_user->user['username'];
3997  // User uid (if configured):
3998  $token = isset($this->config['config']['USERUID_substToken']) ? trim($this->config['config']['USERUID_substToken']) : '';
3999  if ($token) {
4000  $search[] = $token;
4001  $replace[] = $this->fe_user->user['uid'];
4002  }
4003  }
4004  // Substitutes get_URL_ID in case of GET-fallback
4005  if ($this->getMethodUrlIdToken) {
4006  $search[] = $this->getMethodUrlIdToken;
4007  $replace[] = $this->fe_user->get_URL_ID;
4008  }
4009  // Hook for supplying custom search/replace data
4010  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'])) {
4011  $contentStrReplaceHooks = &$this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['tslib_fe-contentStrReplace'];
4012  if (is_array($contentStrReplaceHooks)) {
4013  $_params = array(
4014  'search' => &$search,
4015  'replace' => &$replace
4016  );
4017  foreach ($contentStrReplaceHooks as $_funcRef) {
4018  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
4019  }
4020  }
4021  }
4022  if (count($search)) {
4023  $this->content = str_replace($search, $replace, $this->content);
4024  }
4025  }
4026 
4032  public function storeSessionData() {
4033  $this->fe_user->storeSessionData();
4034  }
4035 
4042  public function setParseTime() {
4043  // Compensates for the time consumed with Back end user initialization.
4044  $microtime_start = isset($GLOBALS['TYPO3_MISC']['microtime_start']) ? $GLOBALS['TYPO3_MISC']['microtime_start'] : NULL;
4045  $microtime_end = isset($GLOBALS['TYPO3_MISC']['microtime_end']) ? $GLOBALS['TYPO3_MISC']['microtime_end'] : NULL;
4046  $microtime_BE_USER_start = isset($GLOBALS['TYPO3_MISC']['microtime_BE_USER_start']) ? $GLOBALS['TYPO3_MISC']['microtime_BE_USER_start'] : NULL;
4047  $microtime_BE_USER_end = isset($GLOBALS['TYPO3_MISC']['microtime_BE_USER_end']) ? $GLOBALS['TYPO3_MISC']['microtime_BE_USER_end'] : NULL;
4048  $this->scriptParseTime = $GLOBALS['TT']->getMilliseconds($microtime_end) - $GLOBALS['TT']->getMilliseconds($microtime_start) - ($GLOBALS['TT']->getMilliseconds($microtime_BE_USER_end) - $GLOBALS['TT']->getMilliseconds($microtime_BE_USER_start));
4049  }
4050 
4056  public function previewInfo() {
4057  if ($this->fePreview !== 0) {
4058  $previewInfo = '';
4059  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'])) {
4060  $_params = array('pObj' => &$this);
4061  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_previewInfo'] as $_funcRef) {
4062  $previewInfo .= GeneralUtility::callUserFunction($_funcRef, $_params, $this);
4063  }
4064  }
4065  $this->content = str_ireplace('</body>', $previewInfo . '</body>', $this->content);
4066  }
4067  }
4068 
4074  public function hook_eofe() {
4075  // Call hook for end-of-frontend processing:
4076  if (isset($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe']) && is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'])) {
4077  $_params = array('pObj' => &$this);
4078  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['hook_eofe'] as $_funcRef) {
4079  GeneralUtility::callUserFunction($_funcRef, $_params, $this);
4080  }
4081  }
4082  }
4083 
4089  public function beLoginLinkIPList() {
4090  if (!empty($this->config['config']['beLoginLinkIPList'])) {
4091  if (GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $this->config['config']['beLoginLinkIPList'])) {
4092  $label = !$this->beUserLogin ? $this->config['config']['beLoginLinkIPList_login'] : $this->config['config']['beLoginLinkIPList_logout'];
4093  if ($label) {
4094  if (!$this->beUserLogin) {
4095  $link = '<a href="' . htmlspecialchars((TYPO3_mainDir . 'index.php?redirect_url=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI')))) . '">' . $label . '</a>';
4096  } else {
4097  $link = '<a href="' . htmlspecialchars((TYPO3_mainDir . 'index.php?L=OUT&redirect_url=' . rawurlencode(GeneralUtility::getIndpEnv('REQUEST_URI')))) . '">' . $label . '</a>';
4098  }
4099  return $link;
4100  }
4101  }
4102  }
4103  }
4104 
4111  public function addTempContentHttpHeaders() {
4112  header('HTTP/1.0 503 Service unavailable');
4113  header('Retry-after: 3600');
4114  header('Pragma: no-cache');
4115  header('Cache-control: no-cache');
4116  header('Expire: 0');
4117  }
4118 
4119  /********************************************
4120  *
4121  * Various internal API functions
4122  *
4123  *******************************************/
4135  public function encryptCharcode($n, $start, $end, $offset) {
4136  $n = $n + $offset;
4137  if ($offset > 0 && $n > $end) {
4138  $n = $start + ($n - $end - 1);
4139  } elseif ($offset < 0 && $n < $start) {
4140  $n = $end - ($start - $n - 1);
4141  }
4142  return chr($n);
4143  }
4144 
4153  public function encryptEmail($string, $back = FALSE) {
4154  $out = '';
4155  if ($this->spamProtectEmailAddresses === 'ascii') {
4156  $stringLength = strlen($string);
4157  for ($a = 0; $a < $stringLength; $a++) {
4158  $out .= '&#' . ord(substr($string, $a, 1)) . ';';
4159  }
4160  } else {
4161  // like str_rot13() but with a variable offset and a wider character range
4162  $len = strlen($string);
4163  $offset = (int)$this->spamProtectEmailAddresses * ($back ? -1 : 1);
4164  for ($i = 0; $i < $len; $i++) {
4165  $charValue = ord($string[$i]);
4166  // 0-9 . , - + / :
4167  if ($charValue >= 43 && $charValue <= 58) {
4168  $out .= $this->encryptCharcode($charValue, 43, 58, $offset);
4169  } elseif ($charValue >= 64 && $charValue <= 90) {
4170  // A-Z @
4171  $out .= $this->encryptCharcode($charValue, 64, 90, $offset);
4172  } elseif ($charValue >= 97 && $charValue <= 122) {
4173  // a-z
4174  $out .= $this->encryptCharcode($charValue, 97, 122, $offset);
4175  } else {
4176  $out .= $string[$i];
4177  }
4178  }
4179  }
4180  return $out;
4181  }
4182 
4193  public function codeString($string, $decode = FALSE) {
4194  if ($decode) {
4195  list($md5Hash, $str) = explode(':', $string, 2);
4196  $newHash = substr(md5($this->TYPO3_CONF_VARS['SYS']['encryptionKey'] . ':' . $str), 0, 10);
4197  if ($md5Hash === $newHash) {
4198  $str = base64_decode($str);
4199  $str = $this->roundTripCryptString($str);
4200  return $str;
4201  } else {
4202  return FALSE;
4203  }
4204  } else {
4205  $str = $string;
4206  $str = $this->roundTripCryptString($str);
4207  $str = base64_encode($str);
4208  $newHash = substr(md5($this->TYPO3_CONF_VARS['SYS']['encryptionKey'] . ':' . $str), 0, 10);
4209  return $newHash . ':' . $str;
4210  }
4211  }
4212 
4224  protected function roundTripCryptString($string) {
4225  $out = '';
4226  $cleartextLength = strlen($string);
4227  $key = sha1($this->TYPO3_CONF_VARS['SYS']['encryptionKey']);
4228  $keyLength = strlen($key);
4229  for ($a = 0; $a < $cleartextLength; $a++) {
4230  $xorVal = ord($key[$a % $keyLength]);
4231  $out .= chr(ord($string[$a]) ^ $xorVal);
4232  }
4233  return $out;
4234  }
4235 
4244  public function checkFileInclude($incFile) {
4245  return !$this->TYPO3_CONF_VARS['FE']['noPHPscriptInclude'] || substr($incFile, 0, 4 + strlen(TYPO3_mainDir)) == TYPO3_mainDir . 'ext/' || substr($incFile, 0, 7 + strlen(TYPO3_mainDir)) == TYPO3_mainDir . 'sysext/' || substr($incFile, 0, 14) == 'typo3conf/ext/';
4246  }
4247 
4255  public function newCObj() {
4256  $this->cObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
4257  $this->cObj->start($this->page, 'pages');
4258  }
4259 
4267  public function setAbsRefPrefix() {
4268  if (!$this->absRefPrefix) {
4269  return;
4270  }
4271  $search = array(
4272  '"typo3temp/',
4273  '"typo3conf/ext/',
4274  '"' . TYPO3_mainDir . 'contrib/',
4275  '"' . TYPO3_mainDir . 'ext/',
4276  '"' . TYPO3_mainDir . 'sysext/',
4277  '"' . $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_imageStorageDir']
4278  );
4279  $replace = array(
4280  '"' . $this->absRefPrefix . 'typo3temp/',
4281  '"' . $this->absRefPrefix . 'typo3conf/ext/',
4282  '"' . $this->absRefPrefix . TYPO3_mainDir . 'contrib/',
4283  '"' . $this->absRefPrefix . TYPO3_mainDir . 'ext/',
4284  '"' . $this->absRefPrefix . TYPO3_mainDir . 'sysext/',
4285  '"' . $this->absRefPrefix . $GLOBALS['TYPO3_CONF_VARS']['BE']['RTE_imageStorageDir']
4286  );
4288  $storageRepository = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\StorageRepository');
4289  $storages = $storageRepository->findAll();
4290  foreach ($storages as $storage) {
4291  if ($storage->getDriverType() === 'Local' && $storage->isPublic() && $storage->isOnline()) {
4292  $folder = $storage->getPublicUrl($storage->getRootLevelFolder(), TRUE);
4293  $search[] = '"' . $folder;
4294  $replace[] = '"' . $this->absRefPrefix . $folder;
4295  }
4296  }
4297  // Process additional directories
4298  $directories = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['FE']['additionalAbsRefPrefixDirectories'], TRUE);
4299  foreach ($directories as $directory) {
4300  $search[] = '"' . $directory;
4301  $replace[] = '"' . $this->absRefPrefix . $directory;
4302  }
4303  $this->content = str_replace(
4304  $search,
4305  $replace,
4306  $this->content
4307  );
4308  }
4309 
4318  public function baseUrlWrap($url) {
4319  if ($this->baseUrl) {
4320  $urlParts = parse_url($url);
4321  if (!strlen($urlParts['scheme']) && $url[0] !== '/') {
4322  $url = $this->baseUrl . $url;
4323  }
4324  }
4325  return $url;
4326  }
4327 
4339  public function logDeprecatedTyposcript($typoScriptProperty, $explanation = '') {
4340  $explanationText = strlen($explanation) ? ' - ' . $explanation : '';
4341  $GLOBALS['TT']->setTSlogMessage($typoScriptProperty . ' is deprecated.' . $explanationText, 2);
4342  GeneralUtility::deprecationLog('TypoScript ' . $typoScriptProperty . ' is deprecated' . $explanationText);
4343  }
4344 
4353  public function updateMD5paramsRecord($hash) {
4354  $GLOBALS['TYPO3_DB']->exec_UPDATEquery('cache_md5params', 'md5hash=' . $GLOBALS['TYPO3_DB']->fullQuoteStr($hash, 'cache_md5params'), array('tstamp' => $GLOBALS['EXEC_TIME']));
4355  }
4356 
4368  public function tidyHTML($content) {
4370  if ($this->TYPO3_CONF_VARS['FE']['tidy'] && $this->TYPO3_CONF_VARS['FE']['tidy_path']) {
4371  $oldContent = $content;
4372  // Create temporary name
4373  $fname = GeneralUtility::tempnam('typo3_tidydoc_');
4374  // Delete if exists, just to be safe.
4375  @unlink($fname);
4376  // Open for writing
4377  $fp = fopen($fname, 'wb');
4378  // Put $content
4379  fputs($fp, $content);
4380  // Close
4381  @fclose($fp);
4382  // run the $content through 'tidy', which formats the HTML to nice code.
4383  exec($this->TYPO3_CONF_VARS['FE']['tidy_path'] . ' ' . $fname, $output);
4384  // Delete the tempfile again
4385  @unlink($fname);
4386  $content = implode(LF, $output);
4387  if (!trim($content)) {
4388  // Restore old content due empty return value.
4389  $content = $oldContent;
4390  $GLOBALS['TT']->setTSlogMessage('"tidy" returned an empty value!', 2);
4391  }
4392  $GLOBALS['TT']->setTSlogMessage('"tidy" content length: ' . strlen($content), 0);
4393  }
4394  return $content;
4395  }
4396 
4403  public function prefixLocalAnchorsWithScript() {
4404  if (!$this->beUserLogin) {
4405  if (!is_object($this->cObj)) {
4406  $this->newCObj();
4407  }
4408  $scriptPath = $this->cObj->getUrlToCurrentLocation();
4409  } else {
4410  // To break less existing sites, we allow the REQUEST_URI to be used for the prefix
4411  $scriptPath = GeneralUtility::getIndpEnv('REQUEST_URI');
4412  // Disable the cache so that these URI will not be the ones to be cached
4413  $this->disableCache();
4414  }
4415  $originalContent = $this->content;
4416  $this->content = preg_replace('/(<(?:a|area).*?href=")(#[^"]*")/i', '${1}' . htmlspecialchars($scriptPath) . '${2}', $originalContent);
4417  // There was an error in the call to preg_replace, so keep the original content (behavior prior to PHP 5.2)
4418  if (preg_last_error() > 0) {
4419  GeneralUtility::sysLog('preg_replace returned error-code: ' . preg_last_error() . ' in function prefixLocalAnchorsWithScript. Replacement not done!', 'cms', GeneralUtility::SYSLOG_SEVERITY_FATAL);
4420  $this->content = $originalContent;
4421  }
4422  }
4423 
4424  /********************************************
4425  * PUBLIC ACCESSIBLE WORKSPACES FUNCTIONS
4426  *******************************************/
4427 
4433  public function doWorkspacePreview() {
4434  return $this->workspacePreview !== 0;
4435  }
4436 
4444  public function whichWorkspace($returnTitle = FALSE) {
4445  if ($this->doWorkspacePreview()) {
4446  $ws = (int)$this->workspacePreview;
4447  } elseif ($this->beUserLogin) {
4448  $ws = $GLOBALS['BE_USER']->workspace;
4449  } else {
4450  return FALSE;
4451  }
4452  if ($returnTitle) {
4453  if (\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::isLoaded('workspaces')) {
4454  $res = $GLOBALS['TYPO3_DB']->exec_SELECTquery('title', 'sys_workspace', 'uid=' . (int)$ws);
4455  if ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
4456  return $row['title'];
4457  }
4458  }
4459  } else {
4460  return $ws;
4461  }
4462  }
4463 
4470  public function includeLibraries(array $libraries) {
4471  global $TYPO3_CONF_VARS;
4472  $GLOBALS['TT']->push('Include libraries');
4473  $GLOBALS['TT']->setTSlogMessage('Files for inclusion: "' . implode(', ', $libraries) . '"');
4474  foreach ($libraries as $library) {
4475  $file = $GLOBALS['TSFE']->tmpl->getFileName($library);
4476  if ($file) {
4477  include_once './' . $file;
4478  } else {
4479  $GLOBALS['TT']->setTSlogMessage('Include file "' . $file . '" did not exist!', 2);
4480  }
4481  }
4482  $GLOBALS['TT']->pull();
4483  }
4484 
4485  /********************************************
4486  *
4487  * Various external API functions - for use in plugins etc.
4488  *
4489  *******************************************/
4496  public function getStorageSiterootPids() {
4497  $res = array();
4498  if (!is_array($this->rootLine)) {
4499  return array();
4500  }
4501  foreach ($this->rootLine as $rC) {
4502  if (!$res['_STORAGE_PID']) {
4503  $res['_STORAGE_PID'] = (int)$rC['storage_pid'];
4504  }
4505  if (!$res['_SITEROOT']) {
4506  $res['_SITEROOT'] = $rC['is_siteroot'] ? (int)$rC['uid'] : 0;
4507  }
4508  }
4509  return $res;
4510  }
4511 
4518  public function getPagesTSconfig() {
4519  if (!is_array($this->pagesTSconfig)) {
4520  $TSdataArray = array();
4521  // Setting default configuration:
4522  $TSdataArray[] = $this->TYPO3_CONF_VARS['BE']['defaultPageTSconfig'];
4523  foreach ($this->rootLine as $k => $v) {
4524  $TSdataArray[] = $v['TSconfig'];
4525  }
4526  // Parsing the user TS (or getting from cache)
4528  $userTS = implode(LF . '[GLOBAL]' . LF, $TSdataArray);
4529  $hash = md5('pageTS:' . $userTS);
4530  $cachedContent = $this->sys_page->getHash($hash);
4531  if (is_array($cachedContent)) {
4532  $this->pagesTSconfig = $cachedContent;
4533  } else {
4534  $parseObj = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\TypoScript\\Parser\\TypoScriptParser');
4535  $parseObj->parse($userTS);
4536  $this->pagesTSconfig = $parseObj->setup;
4537  $this->sys_page->storeHash($hash, $this->pagesTSconfig, 'PAGES_TSconfig');
4538  }
4539  }
4540  return $this->pagesTSconfig;
4541  }
4542 
4552  public function setJS($key, $content = '') {
4553  if ($key) {
4554  switch ($key) {
4555  case 'mouseOver':
4556  $this->additionalJavaScript[$key] = ' // JS function for mouse-over
4557  function over(name, imgObj) { //
4558  if (version == "n3" && document[name]) {document[name].src = eval(name+"_h.src");}
4559  else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
4560  else if (imgObj) {imgObj.src = eval(name+"_h.src");}
4561  }
4562  // JS function for mouse-out
4563  function out(name, imgObj) { //
4564  if (version == "n3" && document[name]) {document[name].src = eval(name+"_n.src");}
4565  else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
4566  else if (imgObj) {imgObj.src = eval(name+"_n.src");}
4567  }';
4568  break;
4569  case 'openPic':
4570  $this->additionalJavaScript[$key] = ' function openPic(url, winName, winParams) { //
4571  var theWindow = window.open(url, winName, winParams);
4572  if (theWindow) {theWindow.focus();}
4573  }';
4574  break;
4575  default:
4576  $this->additionalJavaScript[$key] = $content;
4577  }
4578  }
4579  }
4580 
4590  public function setCSS($key, $content) {
4591  if ($key) {
4592  $this->additionalCSS[$key] = $content;
4593  }
4594  }
4595 
4604  public function uniqueHash($str = '') {
4605  return md5($this->uniqueString . '_' . $str . $this->uniqueCounter++);
4606  }
4607 
4616  public function set_no_cache($reason = '', $internal = FALSE) {
4617  if ($internal && isset($GLOBALS['BE_USER'])) {
4619  } else {
4621  }
4622 
4623  if (strlen($reason)) {
4624  $warning = '$TSFE->set_no_cache() was triggered. Reason: ' . $reason . '.';
4625  } else {
4626  $trace = debug_backtrace();
4627  // This is a hack to work around ___FILE___ resolving symbolic links
4628  $PATH_site_real = dirname(realpath(PATH_site . 'typo3')) . '/';
4629  $file = $trace[0]['file'];
4630  if (GeneralUtility::isFirstPartOfStr($file, $PATH_site_real)) {
4631  $file = str_replace($PATH_site_real, '', $file);
4632  } else {
4633  $file = str_replace(PATH_site, '', $file);
4634  }
4635  $line = $trace[0]['line'];
4636  $trigger = $file . ' on line ' . $line;
4637  $warning = '$GLOBALS[\'TSFE\']->set_no_cache() was triggered by ' . $trigger . '.';
4638  }
4639  if ($this->TYPO3_CONF_VARS['FE']['disableNoCacheParameter']) {
4640  $warning .= ' However, $TYPO3_CONF_VARS[\'FE\'][\'disableNoCacheParameter\'] is set, so it will be ignored!';
4641  $GLOBALS['TT']->setTSlogMessage($warning, 2);
4642  } else {
4643  $warning .= ' Caching is disabled!';
4644  $this->disableCache();
4645  }
4646  GeneralUtility::sysLog($warning, 'cms', $severity);
4647  }
4648 
4655  protected function disableCache() {
4656  $this->no_cache = TRUE;
4657  }
4658 
4666  public function set_cache_timeout_default($seconds) {
4667  $this->cacheTimeOutDefault = (int)$seconds;
4668  }
4669 
4676  public function get_cache_timeout() {
4678  $runtimeCache = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_runtime');
4679  $cachedCacheLifetimeIdentifier = 'core-tslib_fe-get_cache_timeout';
4680  $cachedCacheLifetime = $runtimeCache->get($cachedCacheLifetimeIdentifier);
4681  if ($cachedCacheLifetime === FALSE) {
4682  if ($this->page['cache_timeout']) {
4683  // Cache period was set for the page:
4684  $cacheTimeout = $this->page['cache_timeout'];
4685  } elseif ($this->cacheTimeOutDefault) {
4686  // Cache period was set for the whole site:
4687  $cacheTimeout = $this->cacheTimeOutDefault;
4688  } else {
4689  // No cache period set at all, so we take one day (60*60*24 seconds = 86400 seconds):
4690  $cacheTimeout = 86400;
4691  }
4692  if ($this->config['config']['cache_clearAtMidnight']) {
4693  $timeOutTime = $GLOBALS['EXEC_TIME'] + $cacheTimeout;
4694  $midnightTime = mktime(0, 0, 0, date('m', $timeOutTime), date('d', $timeOutTime), date('Y', $timeOutTime));
4695  // If the midnight time of the expire-day is greater than the current time,
4696  // we may set the timeOutTime to the new midnighttime.
4697  if ($midnightTime > $GLOBALS['EXEC_TIME']) {
4698  $cacheTimeout = $midnightTime - $GLOBALS['EXEC_TIME'];
4699  }
4700  }
4701 
4702  // Calculate the timeout time for records on the page and adjust cache timeout if necessary
4703  $cacheTimeout = min($this->calculatePageCacheTimeout(), $cacheTimeout);
4704 
4705  if (is_array($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'])) {
4706  foreach ($this->TYPO3_CONF_VARS['SC_OPTIONS']['tslib/class.tslib_fe.php']['get_cache_timeout'] as $_funcRef) {
4707  $params = array('cacheTimeout' => $cacheTimeout);
4708  $cacheTimeout = GeneralUtility::callUserFunction($_funcRef, $params, $this);
4709  }
4710  }
4711  $runtimeCache->set($cachedCacheLifetimeIdentifier, $cacheTimeout);
4712  $cachedCacheLifetime = $cacheTimeout;
4713  }
4714  return $cachedCacheLifetime;
4715  }
4716 
4731  public function plainMailEncoded($email, $subject, $message, $headers = '') {
4733  // '76', 'all', ''
4734  $urlmode = $this->config['config']['notification_email_urlmode'];
4735  if ($urlmode) {
4736  $message = GeneralUtility::substUrlsInPlainText($message, $urlmode);
4737  }
4738  $encoding = $this->config['config']['notification_email_encoding'] ?: '';
4739  $charset = $this->renderCharset;
4740  $convCharset = FALSE;
4741  // do we need to convert mail data?
4742  // Respect config.notification_email_charset if it was set
4743  if ($this->config['config']['notification_email_charset']) {
4744  $charset = $this->csConvObj->parse_charset($this->config['config']['notification_email_charset']);
4745  if ($charset != $this->renderCharset) {
4746  $convCharset = TRUE;
4747  }
4748  } elseif ($this->metaCharset != $this->renderCharset) {
4749  // Use metaCharset for mail if different from renderCharset
4750  $charset = $this->metaCharset;
4751  $convCharset = TRUE;
4752  }
4753  if ($convCharset) {
4754  $email = $this->csConvObj->conv($email, $this->renderCharset, $charset);
4755  $subject = $this->csConvObj->conv($subject, $this->renderCharset, $charset);
4756  $message = $this->csConvObj->conv($message, $this->renderCharset, $charset);
4757  $headers = $this->csConvObj->conv($headers, $this->renderCharset, $charset);
4758  }
4759  GeneralUtility::plainMailEncoded($email, $subject, $message, $headers, $encoding, $charset);
4760  }
4761 
4768  public function getUniqueId($desired = '') {
4769  if ($desired === '') {
4770  // id has to start with a letter to reach XHTML compliance
4771  $uniqueId = 'a' . $this->uniqueHash();
4772  } else {
4773  $uniqueId = $desired;
4774  for ($i = 1; isset($this->usedUniqueIds[$uniqueId]); $i++) {
4775  $uniqueId = $desired . '_' . $i;
4776  }
4777  }
4778  $this->usedUniqueIds[$uniqueId] = TRUE;
4779  return $uniqueId;
4780  }
4781 
4782  /*********************************************
4783  *
4784  * Localization and character set conversion
4785  *
4786  *********************************************/
4794  public function sL($input) {
4795  if (substr($input, 0, 4) !== 'LLL:') {
4796  // Not a label, return the key as this
4797  return $input;
4798  }
4799  // If cached label
4800  if (!isset($this->LL_labels_cache[$this->lang][$input])) {
4801  $restStr = trim(substr($input, 4));
4802  $extPrfx = '';
4803  if (substr($restStr, 0, 4) === 'EXT:') {
4804  $restStr = trim(substr($restStr, 4));
4805  $extPrfx = 'EXT:';
4806  }
4807  $parts = explode(':', $restStr);
4808  $parts[0] = $extPrfx . $parts[0];
4809  // Getting data if not cached
4810  if (!isset($this->LL_files_cache[$parts[0]])) {
4811  $this->LL_files_cache[$parts[0]] = $this->readLLfile($parts[0]);
4812  }
4813  $this->LL_labels_cache[$this->lang][$input] = $this->getLLL($parts[1], $this->LL_files_cache[$parts[0]]);
4814  }
4815  return $this->LL_labels_cache[$this->lang][$input];
4816  }
4817 
4825  public function readLLfile($fileRef) {
4826  if ($this->lang !== 'default') {
4827  $languages = array_reverse($this->languageDependencies);
4828  // At least we need to have English
4829  if (empty($languages)) {
4830  $languages[] = 'default';
4831  }
4832  } else {
4833  $languages = array('default');
4834  }
4835 
4836  $localLanguage = array();
4837  foreach ($languages as $language) {
4838  $tempLL = GeneralUtility::readLLfile($fileRef, $language, $this->renderCharset);
4839  $localLanguage['default'] = $tempLL['default'];
4840  if (!isset($localLanguage[$this->lang])) {
4841  $localLanguage[$this->lang] = $localLanguage['default'];
4842  }
4843  if ($this->lang !== 'default' && isset($tempLL[$language])) {
4844  // Merge current language labels onto labels from previous language
4845  // This way we have a label with fall back applied
4846  ArrayUtility::mergeRecursiveWithOverrule($localLanguage[$this->lang], $tempLL[$language], TRUE, FALSE);
4847  }
4848  }
4849 
4850  return $localLanguage;
4851  }
4852 
4861  public function getLLL($index, $LOCAL_LANG) {
4862  if (isset($LOCAL_LANG[$this->lang][$index][0]['target'])) {
4863  return $LOCAL_LANG[$this->lang][$index][0]['target'];
4864  } elseif (isset($LOCAL_LANG['default'][$index][0]['target'])) {
4865  return $LOCAL_LANG['default'][$index][0]['target'];
4866  }
4867  return FALSE;
4868  }
4869 
4876  public function initLLvars() {
4877  // Init languageDependencies list
4878  $this->languageDependencies = array();
4879  // Setting language key and split index:
4880  $this->lang = $this->config['config']['language'] ?: 'default';
4881  $this->getPageRenderer()->setLanguage($this->lang);
4882 
4883  // Finding the requested language in this list based
4884  // on the $lang key being inputted to this function.
4886  $locales = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Localization\\Locales');
4887  $locales->initialize();
4888 
4889  // Language is found. Configure it:
4890  if (in_array($this->lang, $locales->getLocales())) {
4891  $this->languageDependencies[] = $this->lang;
4892  foreach ($locales->getLocaleDependencies($this->lang) as $language) {
4893  $this->languageDependencies[] = $language;
4894  }
4895  }
4896 
4897  // Setting charsets:
4898  $this->renderCharset = $this->csConvObj->parse_charset($this->config['config']['renderCharset'] ? $this->config['config']['renderCharset'] : 'utf-8');
4899  // Rendering charset of HTML page.
4900  $this->metaCharset = $this->csConvObj->parse_charset($this->config['config']['metaCharset'] ? $this->config['config']['metaCharset'] : $this->renderCharset);
4901  }
4902 
4915  public function csConv($str, $from = '') {
4916  if ($from) {
4917  $output = $this->csConvObj->conv($str, $this->csConvObj->parse_charset($from), $this->renderCharset, 1);
4918  return $output ?: $str;
4919  } else {
4920  return $str;
4921  }
4922  }
4923 
4932  public function convOutputCharset($content, $label = '') {
4933  if ($this->renderCharset != $this->metaCharset) {
4934  $content = $this->csConvObj->conv($content, $this->renderCharset, $this->metaCharset, TRUE);
4935  }
4936  return $content;
4937  }
4938 
4944  public function convPOSTCharset() {
4945  if ($this->renderCharset != $this->metaCharset && is_array($_POST) && count($_POST)) {
4946  $this->csConvObj->convArray($_POST, $this->metaCharset, $this->renderCharset);
4947  $GLOBALS['HTTP_POST_VARS'] = $_POST;
4948  }
4949  }
4950 
4956  protected function calculatePageCacheTimeout() {
4957  $result = PHP_INT_MAX;
4958  // Get the configuration
4959  $tablesToConsider = $this->getCurrentPageCacheConfiguration();
4960  // Get the time, rounded to the minute (do not polute MySQL cache!)
4961  // It is ok that we do not take seconds into account here because this
4962  // value will be substracted later. So we never get the time "before"
4963  // the cache change.
4964  $now = $GLOBALS['ACCESS_TIME'];
4965  // Find timeout by checking every table
4966  foreach ($tablesToConsider as $tableDef) {
4967  $result = min($result, $this->getFirstTimeValueForRecord($tableDef, $now));
4968  }
4969  // We return + 1 second just to ensure that cache is definitely regenerated
4970  return $result == PHP_INT_MAX ? PHP_INT_MAX : $result - $now + 1;
4971  }
4972 
4987  protected function getCurrentPageCacheConfiguration() {
4988  $result = array('tt_content:' . $this->id);
4989  if (isset($this->config['config']['cache.'][$this->id])) {
4990  $result = array_merge($result, GeneralUtility::trimExplode(',', $this->config['config']['cache.'][$this->id]));
4991  }
4992  if (isset($this->config['config']['cache.']['all'])) {
4993  $result = array_merge($result, GeneralUtility::trimExplode(',', $this->config['config']['cache.']['all']));
4994  }
4995  return array_unique($result);
4996  }
4997 
5007  protected function getFirstTimeValueForRecord($tableDef, $now) {
5008  $result = PHP_INT_MAX;
5009  list($tableName, $pid) = GeneralUtility::trimExplode(':', $tableDef);
5010  if (empty($tableName) || empty($pid)) {
5011  throw new \InvalidArgumentException('Unexpected value for parameter $tableDef. Expected <tablename>:<pid>, got \'' . htmlspecialchars($tableDef) . '\'.', 1307190365);
5012  }
5013  // Additional fields
5014  $showHidden = $tableName === 'pages' ? $this->showHiddenPage : $this->showHiddenRecords;
5015  $enableFields = $this->sys_page->enableFields($tableName, $showHidden, array('starttime' => TRUE, 'endtime' => TRUE));
5016  // For each start or end time field, get the minimum value
5017  foreach (array('starttime', 'endtime') as $field) {
5018  if (isset($GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field])) {
5019  $timeField = $GLOBALS['TCA'][$tableName]['ctrl']['enablecolumns'][$field];
5020  $selectField = 'MIN(' . $timeField . ') AS ' . $field;
5021  $whereCondition = $timeField . ' > ' . $now;
5022  // Find the smallest timestamp which could influence the cache duration (but is larger than 0)
5023  $row = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow($selectField, $tableName, 'pid = ' . (int)$pid . ' AND ' . $whereCondition . $enableFields);
5024  if ($row && !is_null($row[$field])) {
5025  $result = min($result, $row[$field]);
5026  }
5027  }
5028  }
5029  return $result;
5030  }
5031 
5032 
5038  protected function getSysDomainCache() {
5039  $entryIdentifier = 'core-database-sys_domain-complete';
5041  $runtimeCache = GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Cache\\CacheManager')->getCache('cache_runtime');
5042 
5043  $sysDomainData = array();
5044  if ($runtimeCache->has($entryIdentifier)) {
5045  $sysDomainData = $runtimeCache->get($entryIdentifier);
5046  } else {
5047  $domainRecords = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
5048  'pid, domainName, forced',
5049  'sys_domain',
5050  'redirectTo=\'\' ' . $this->sys_page->enableFields('sys_domain', 0),
5051  '',
5052  'sorting ASC'
5053  );
5054 
5055  foreach ($domainRecords as $row) {
5056  // if there is already an entry for this pid, check if we should overwrite it
5057  if (isset($sysDomainData[$row['pid']])) {
5058  // There is already a "forced" entry, which must not be overwritten
5059  if ($sysDomainData[$row['pid']]['forced']) {
5060  continue;
5061  }
5062 
5063  // The current domain record is also NOT-forced, keep the old unless the new one matches the current request
5064  if (!$row['forced'] && !$this->domainNameMatchesCurrentRequest($row['domainName'])) {
5065  continue;
5066  }
5067  }
5068 
5069  // as we passed all previous checks, we save this domain for the current pid
5070  $sysDomainData[$row['pid']] = array(
5071  'pid' => $row['pid'],
5072  'domainName' => rtrim($row['domainName'], '/'),
5073  'forced' => $row['forced'],
5074  );
5075  }
5076  $runtimeCache->set($entryIdentifier, $sysDomainData);
5077  }
5078  return $sysDomainData;
5079  }
5080 
5088  public function domainNameMatchesCurrentRequest($domainName) {
5089  $currentDomain = GeneralUtility::getIndpEnv('HTTP_HOST');
5090  $currentPathSegment = trim(preg_replace('|/[^/]*$|', '', GeneralUtility::getIndpEnv('SCRIPT_NAME')));
5091  return $currentDomain === $domainName || $currentDomain . $currentPathSegment === $domainName;
5092  }
5093 
5102  public function getDomainDataForPid($targetPid) {
5103  // Using array_key_exists() here, nice $result can be NULL
5104  // (happens, if there's no domain records defined)
5105  if (!array_key_exists($targetPid, $this->domainDataCache)) {
5106  $result = NULL;
5107  $sysDomainData = $this->getSysDomainCache();
5108  $rootline = $this->sys_page->getRootLine($targetPid);
5109  // walk the rootline downwards from the target page
5110  // to the root page, until a domain record is found
5111  foreach ($rootline as $pageInRootline) {
5112  $pidInRootline = $pageInRootline['uid'];
5113  if (isset($sysDomainData[$pidInRootline])) {
5114  $result = $sysDomainData[$pidInRootline];
5115  break;
5116  }
5117  }
5118  $this->domainDataCache[$targetPid] = $result;
5119  }
5120 
5121  return $this->domainDataCache[$targetPid];
5122  }
5123 
5131  public function getDomainNameForPid($targetPid) {
5132  $domainData = $this->getDomainDataForPid($targetPid);
5133  return $domainData ? $domainData['domainName'] : NULL;
5134  }
5135 }
static mergeRecursiveWithOverrule(array &$original, array $overrule, $addKeys=TRUE, $includeEmptyValues=TRUE, $enableUnsetFeature=TRUE)
static setSingletonInstance($className, \TYPO3\CMS\Core\SingletonInterface $instance)
static substUrlsInPlainText($message, $urlmode='76', $index_script_url='')
$parameters
Definition: FileDumpEID.php:15
static devLog($msg, $extKey, $severity=0, $dataVar=FALSE)
static isFirstPartOfStr($str, $partStr)
static intExplode($delimiter, $string, $removeEmptyValues=FALSE, $limit=0)
static getUserObj($classRef, $checkPrefix='', $silent=FALSE)
static hmac($input, $additionalSecret='')
die
Definition: index.php:6
static hideIfDefaultLanguage($localizationConfiguration)
static trimExplode($delim, $string, $removeEmptyValues=FALSE, $limit=0)
static verifyFilenameAgainstDenyPattern($filename)
static callUserFunction($funcName, &$params, &$ref, $checkPrefix='', $errorMode=0)
static hideIfNotTranslated($l18n_cfg_fieldValue)
static _GETset($inputGet, $key='')
if($list_of_literals) if(!empty($literals)) if(!empty($literals)) $result
Analyse literals to prepend the N char to them if their contents aren&#39;t numeric.
static getUrl($url, $includeHeader=0, $requestHeaders=FALSE, &$report=NULL)
static tempnam($filePrefix, $fileSuffix='')
$host
Definition: server.php:35
static implodeArrayForUrl($name, array $theArray, $str='', $skipBlank=FALSE, $rawurlencodeParamName=FALSE)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
static plainMailEncoded($email, $subject, $message, $headers='', $encoding='quoted-printable', $charset='', $dontEncodeHeader=FALSE)
if(!defined('TYPO3_MODE')) $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_userauth.php']['logoff_pre_processing'][]
static getFileAbsFileName($filename, $onlyRelative=TRUE, $relToTYPO3_mainDir=FALSE)
$BE_USER
Definition: index_ts.php:114
__construct($TYPO3_CONF_VARS, $id, $type, $no_cache='', $cHash='', $jumpurl='', $MP='', $RDCT='')
$locales
Definition: be_users.php:6
getPageShortcut($SC, $mode, $thisUid, $itera=20, $pageLog=array(), $disableGroupCheck=FALSE)