git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2471 709f56b5-9817-0410-a4d7...
[Packages/TYPO3.CMS.git] / typo3 / sysext / cms / tslib / class.tslib_fe.php
index c09d946..eb39175 100755 (executable)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 1999-2005 Kasper Skaarhoj (kasperYYYY@typo3.com)
+*  (c) 1999-2007 Kasper Skaarhoj (kasperYYYY@typo3.com)
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
        var $rootLine='';                                       // The rootLine (all the way to tree root, not only the current site!) (array)
        var $page='';                                           // The pagerecord (array)
        var $contentPid=0;                                      // This will normally point to the same value as id, but can be changed to point to another page from which content will then be displayed instead.
-       var $sys_page='';                                       // The object with pagefunctions (object)
+
+       /**
+        * sys_page-object, pagefunctions
+        *
+        * @var t3lib_pageSelect
+        */
+       var $sys_page='';
        var $jumpurl='';
        var $pageNotFound=0;                            // Is set to 1 if a pageNotFound handler could have been called.
        var $domainStartPage=0;                         // Domain start page
        var $siteScript='';                                     // Contains the value of the current script path that activated the frontend. Typically "index.php" but by rewrite rules it could be something else! Used for Speaking Urls / Simulate Static Documents.
 
                // USER
-       var $fe_user='';                                        // The user (object)
+
+       /**
+        * The FE user
+        *
+        * @var tslib_feUserAuth
+        */
+       var $fe_user='';
        var $loginUser='';                                      // Global flag indicating that a front-end user is logged in. This is set only if a user really IS logged in. The group-list may show other groups (like added by IP filter or so) even though there is no user.
        var $gr_list='';                                        // (RO=readonly) The group list, sorted numerically. Group '0,-1' is the default group, but other groups may be added by other means than a user being logged in though...
        var $beUserLogin='';                            // Flag that indicates if a Backend user is logged in!
        var $TCAcachedExtras=array();           // Array of cached information from TCA. This is NOT TCA itself!
 
                // TEMPLATE / CACHE
-       var $tmpl='';                                           // The TypoScript template object. Used to parse the TypoScript template
+
+       /**
+        * The TypoScript template object. Used to parse the TypoScript template
+        *
+        * @var t3lib_TStemplate
+        */
+       var $tmpl='';
        var $cacheTimeOutDefault='';            // Is set to the time-to-live time of cached pages. If false, default is 60*60*24, which is 24 hours.
        var $cacheContentFlag='';                       // Set internally if cached content is fetched from the database
        var $cacheExpires=0;                            // Set to the expire time of cached content
                        JSCode : reserved
                        JSImgCode : reserved
        */
-       var $defaultBodyTag='<body>';           // Default bodytag, if nothing else is set. This can be overridden by applications like TemplaVoila.
        var $additionalHeaderData=array();      // used to accumulate additional HTML-code for the header-section, <head>...</head>. Insert either associative keys (like additionalHeaderData['myStyleSheet'], see reserved keys above) or num-keys (like additionalHeaderData[] = '...')
        var $additionalJavaScript=array();      // used to accumulate additional JavaScript-code. Works like additionalHeaderData. Reserved keys at 'openPic' and 'mouseOver'
        var $additionalCSS=array();                     // used to accumulate additional Style code. Works like additionalHeaderData.
        var $JSeventFuncCalls = array(          // you can add JavaScript functions to each entry in these arrays. Please see how this is done in the GMENU_LAYERS script. The point is that many applications on a page can set handlers for onload, onmouseover and onmouseup
                'onmousemove' => array(),
                'onmouseup' => array(),
+               'onmousemove' => array(),
+               'onkeydown' => array(),
+               'onkeyup' => array(),
+               'onkeypress' => array(),
                'onload' => array(),
+               'onunload' => array(),
        );
        var $JSCode='';                                         // Deprecated, use additionalJavaScript instead.
        var $JSImgCode='';                                      // Used to accumulate JavaScript loaded images (by menus)
        var $divSection='';                                     // Used to accumulate DHTML-layers.
+       var $defaultBodyTag='<body>';           // Default bodytag, if nothing else is set. This can be overridden by applications like TemplaVoila.
 
                // RENDERING configuration, settings from TypoScript is loaded into these vars. See pagegen.php
        var $debug='';                                          // Debug flag, may output special debug html-code.
        var $indexedDocTitle='';                        // This value will be used as the title for the page in the indexer (if indexing happens)
        var $altPageTitle='';                           // Alternative page title (normally the title of the page record). Can be set from applications you make.
        var $pEncAllowedParamNames=array();     // An array that holds parameter names (keys) of GET parameters which MAY be MD5/base64 encoded with simulate_static_documents method.
-       var $baseUrl='';                                        // The Base url set for the page header.
+       var $baseUrl='';                                        // The base URL set for the page header.
        var $anchorPrefix='';                           // The proper anchor prefix needed when using speaking urls. (only set if baseUrl is set)
 
-               // Page content render object
-       var $cObj ='';                                          // is instantiated object of tslib_cObj
+       /**
+        * Page content render object
+        *
+        * @var tslib_cObj
+        */
+       var $cObj ='';
 
                // CONTENT accumulation
        var $content='';                                        // All page content is accumulated in this variable. See pagegen.php
        var $TCAloaded = 0;                                     // Set ONLY if the full TCA is loaded
 
                // Character set (charset) conversion object:
-       var $csConvObj;                                         // An instance of the "t3lib_cs" class. May be used by any application.
+
+       /**
+        * charset conversion class. May be used by any application.
+        *
+        * @var t3lib_cs
+        */
+       var $csConvObj;
        var $defaultCharSet = 'iso-8859-1';     // The default charset used in the frontend if nothing else is set.
        var $renderCharset='';                          // Internal charset of the frontend during rendering: Defaults to "forceCharset" and if that is not set, to ->defaultCharSet
        var $metaCharset='';                            // Output charset of the websites content. This is the charset found in the header, meta tag etc. If different from $renderCharset a conversion happens before output to browser. Defaults to ->renderCharset if not set.
                                        </script>';
                                exit;
                        } elseif (!$GLOBALS['TYPO3_DB']->sql_select_db(TYPO3_db))       {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
                                $this->printError('Cannot connect to the current database, "'.TYPO3_db.'"','Database Error');
                                exit;
                        }
                                        </script>';
                                exit;
                        }
+                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
                        $this->printError('The current username, password or host was not accepted when the connection to the database was attempted to be established!','Database Error');
                        exit;
                }
                                                // Initialize the page-select functions to check rootline:
                                        $temp_sys_page = t3lib_div::makeInstance('t3lib_pageSelect');
                                        $temp_sys_page->init($this->showHiddenPage);
-
                                                // If root line contained NO records and ->error_getRootLine_failPid tells us that it was because of a pid=-1 (indicating a "version" record)...:
                                        if (!count($temp_sys_page->getRootLine($this->id,$this->MP)) && $temp_sys_page->error_getRootLine_failPid==-1)  {
 
                                if ($theFirstPage)      {
                                        $this->id = $theFirstPage['uid'];
                                } else {
+                                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                                       t3lib_div::sysLog('No pages are found on the rootlevel!', 'cms', 3);
                                        $this->printError('No pages are found on the rootlevel!');
                                        exit;
                                }
                                        $c--;
                                        $this->id = $this->rootLine[$c]['uid'];
                                        $this->page = $this->sys_page->getPage($this->id);
-                                       if (count($this->page)){ break; }
+                                       if (count($this->page)) { break; }
                                }
                        }
                                // If still no page...
                                if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'])      {
                                        $this->pageNotFoundAndExit('The requested page does not exist!');
                                } else {
+                                       header( 'HTTP/1.0 404 Page Not Found' );
+                                       t3lib_div::sysLog('The requested page does not exist!', 'cms', 3);
                                        $this->printError('The requested page does not exist!');
                                        exit;
                                }
                        }
                }
 
-               // spacer is not accessible in frontend
+                       // Spacer is not accessible in frontend
                if ($this->page['doktype'] == 199)      {
                        if ($this->TYPO3_CONF_VARS['FE']['pageNotFound_handling'])      {
                                $this->pageNotFoundAndExit('The requested page does not exist!');
                        } else {
+                               header( 'HTTP/1.0 404 Page Not Found' );
+                               t3lib_div::sysLog('The requested page does not exist!', 'cms', 3);
                                $this->printError('The requested page does not exist!');
                                exit;
                        }
 
                        // If not rootline we're off...
                if (!count($this->rootLine))    {
-                       $this->printError('The requested page didn\'t have a proper connection to the tree-root! <br /><br />('.$this->sys_page->error_getRootLine.')');
-                       exit;
+                       $ws = $this->whichWorkspace();
+                       if ($this->sys_page->error_getRootLine_failPid==-1 && $ws) {
+                               $this->sys_page->versioningPreview = TRUE;
+                               $this->versioningWorkspaceId = $ws;
+                               $this->rootLine = $this->sys_page->getRootLine($this->id,$this->MP);
+                       }
+                       if (!count($this->rootLine))    {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('The requested page didn\'t have a proper connection to the tree-root! ('.$this->sys_page->error_getRootLine.')', 'cms', 3);
+                               $this->printError('The requested page didn\'t have a proper connection to the tree-root! <br /><br />('.$this->sys_page->error_getRootLine.')');
+                               exit;
+                       }
+                       $this->fePreview = 1;
                }
 
                        // Checking for include section regarding the hidden/starttime/endtime/fe_user (that is access control of a whole subbranch!)
                if ($this->checkRootlineForIncludeSection())    {
                        if (!count($this->rootLine))    {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('The requested page was not accessible!', 'cms', 3);
                                $this->printError('The requested page was not accessible!');
                                exit;
                        } else {
                                $page = $this->getPageShortcut($page['shortcut'],$page['shortcut_mode'],$page['uid'],$itera-1,$pageLog);
                        } else {
                                $pageLog[] = $page['uid'];
+                               header( 'HTTP/1.0 500 Internal Server Error' );
+                               t3lib_div::sysLog('Page shortcuts were looping in uids '.implode(',',$pageLog).'...!', 'cms', 3);
                                $this->printError('Page shortcuts were looping in uids '.implode(',',$pageLog).'...!');
                                exit;
                        }
                if (!$this->id) {
                        list($theAlias) = explode('&',t3lib_div::getIndpEnv('QUERY_STRING'));
                        $theAlias = trim($theAlias);
-                       $this->id = $theAlias ? $theAlias : 0;
+                       $this->id = ($theAlias != '' && strpos($theAlias, '=') === false) ? $theAlias : 0;
                }
        }
 
         * Page not found handler.
         * Exits.
         *
-        * @param       mixed           Which type of handling; If a true PHP-boolean and TRUE then a ->printError message is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
+        * @param       mixed           Which type of handling; If a true PHP-boolean or TRUE then a ->printError message is outputted. If integer an error message with that number is shown. Otherwise the $code value is expected to be a "Location:" header value.
         * @param       string          If set, this is passed directly to the PHP function, header()
         * @param       string          If set, error messages will also mention this as the reason for the page-not-found.
         * @return      void            (The function exits!)
         */
        function pageNotFoundHandler($code, $header='', $reason='')     {
+
                        // Issue header in any case:
-               if ($header)    {header($header);}
+               if ($header)    {
+                       $headerArr = preg_split('/\r|\n/',$header,-1,PREG_SPLIT_NO_EMPTY);
+                       foreach ($headerArr as $header) {
+                               header ($header);
+                       }
+               }
 
                        // Create response:
                if (gettype($code)=='boolean' || !strcmp($code,1))      {       // Simply boolean; Just shows TYPO3 error page with reason:
                        $this->printError('The page did not exist or was inaccessible.'.($reason ? ' Reason: '.htmlspecialchars($reason) : ''));
-                       exit;
                } elseif (t3lib_div::isFirstPartOfStr($code,'USER_FUNCTION:')) {
                        $funcRef = trim(substr($code,14));
                        $params = array(
                                'pageAccessFailureReasons' => $this->getPageAccessFailureReasons()
                        );
                        echo t3lib_div::callUserFunction($funcRef,$params,$this);
-                       exit;
                } elseif (t3lib_div::isFirstPartOfStr($code,'READFILE:')) {
                        $readFile = t3lib_div::getFileAbsFileName(trim(substr($code,9)));
                        if (@is_file($readFile))        {
                        } else {
                                $this->printError('Configuration Error: 404 page "'.$readFile.'" could not be found.');
                        }
+               } elseif (t3lib_div::isFirstPartOfStr($code,'REDIRECT:')) {
+                       header('Location: '.t3lib_div::locationHeaderUrl(substr($code,9)));
                        exit;
-               } elseif (strlen($code)) {
-                       header('Location: '.t3lib_div::locationHeaderUrl($code));
-                       exit;
+               } elseif (strlen($code))        {
+                               // Check if URL is relative
+                       $url_parts = parse_url($code);
+                       if ($url_parts['host'] == '')   {
+                               $url_parts['host'] = t3lib_div::getIndpEnv('HTTP_HOST');
+                               $code = t3lib_div::getIndpEnv('TYPO3_REQUEST_HOST') . $code;
+                               $checkBaseTag = false;
+                       } else {
+                               $checkBaseTag = true;
+                       }
+
+                               // Check recursion
+                       if ($code == t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')) {
+                               if ($reason == '') {
+                                       $reason = 'Page cannot be found.';
+                               }
+                               $reason.= chr(10) . chr(10) . 'Additionally, ' . $code . ' was not found while trying to retrieve the error document.';
+                               $this->printError('Reason: '.nl2br(htmlspecialchars($reason)));
+                               exit();
+                       }
+
+                               // Prepare headers
+                       $headerArr = array(
+                               'User-agent: ' . t3lib_div::getIndpEnv('HTTP_USER_AGENT'),
+                               'Referer: ' . t3lib_div::getIndpEnv('TYPO3_REQUEST_URL')
+                       );
+                       $res = t3lib_div::getURL($code, 1, $headerArr);
+
+                               // Header and content are separated by an empty line
+                       list($header,$content) = split("\r\n\r\n", $res, 2);
+                       $content.= "\r\n";
+
+                       if (false === $content) {
+                                       // Last chance -- redirect
+                               header('Location: '.t3lib_div::locationHeaderUrl($code));
+                       } else {
+
+                               $forwardHeaders = array(        // Forward these response headers to the client
+                                       'Content-Type:',
+                               );
+                               $headerArr = preg_split('/\r|\n/',$header,-1,PREG_SPLIT_NO_EMPTY);
+                               foreach ($headerArr as $header) {
+                                       foreach ($forwardHeaders as $h) {
+                                               if (preg_match('/^'.$h.'/', $header))   {
+                                                       header ($header);
+                                               }
+                                       }
+                               }
+                                       // Put <base> if necesary
+                               if ($checkBaseTag)      {
+
+                                               // If content already has <base> tag, we do not need to do anything
+                                       if (false === stristr($content, '<base '))      {
+
+                                                       // Generate href for base tag
+                                               $base = $url_parts['scheme'] . '://';
+                                               if ($url_parts['user'] != '')   {
+                                                       $base.= $url_parts['user'];
+                                                       if ($url_parts['pass'] != '')   {
+                                                               $base.= ':' . $url_parts['pass'];
+                                                       }
+                                                       $base.= '@';
+                                               }
+                                               $base.= $url_parts['host'];
+
+                                                       // Add path portion skipping possible file name
+                                               $base.= preg_replace('/(.*\/)[^\/]*/', '${1}', $url_parts['path']);
+
+                                                       // Put it into content (generate also <head> if necessary)
+                                               $replacement = chr(10) . '<base href="' . htmlentities($base) . '" />' . chr(10);
+                                               if (stristr($content, '<head>'))        {
+                                                       $content = preg_replace('/(<head>)/i', '\1' . $replacement, $content);
+                                               } else {
+                                                       $content = preg_replace('/(<html[^>]*>)/i', '\1<head>' . $replacement . '</head>', $content);
+                                               }
+                                       }
+                               }
+                               echo $content;  // Output the content
+                       }
                } else {
-                       $this->printError('Error.'.($reason ? ' Reason: '.htmlspecialchars($reason) : ''));
-                       exit;
+                       $this->printError($reason ? 'Reason: '.htmlspecialchars($reason) : 'Page cannot be found.');
                }
+               exit();
        }
 
        /**
        /**
         * Looking for a ADMCMD_prev code, looks it up if found and returns configuration data.
         * Background: From the backend a request to the frontend to show a page, possibly with workspace preview can be "recorded" and associated with a keyword. When the frontend is requested with this keyword the associated request parameters are restored from the database AND the backend user is loaded - only for that request.
-        * The main point is that a special URL valid for a limited time, eg. http://localhost/typo3site/?ADMCMD_prev=035d9bf938bd23cb657735f68a8cedbf will open up for a preview that doesn't require login. Thus its useful for sending an email.
+        * The main point is that a special URL valid for a limited time, eg. http://localhost/typo3site/index.php?ADMCMD_prev=035d9bf938bd23cb657735f68a8cedbf will open up for a preview that doesn't require login. Thus its useful for sending an email.
         * This can also be used to generate previews of hidden pages, start/endtimes, usergroups and those other settings from the Admin Panel - just not implemented yet.
         *
         * @return      array           Preview configuration array from sys_preview record.
         */
        function ADMCMD_preview(){
                $inputCode = t3lib_div::_GP('ADMCMD_prev');
+               $cookieTTL = 60*60;
+
+                       // If cookie is set, see what to do:
+               if ($_COOKIE['ADMCMD_prev'])    {
+                       
+                               // If no input code is given by GET method, lets look it up in a cookie (for workspace previews not only tied to the page) and update the cookie time:
+                       if (!$inputCode)        {
+                               $inputCode = $_COOKIE['ADMCMD_prev'];
+                               SetCookie('ADMCMD_prev', $inputCode, time()+$cookieTTL);
+                       } else {        // Otherwise "log out":
+                               SetCookie('ADMCMD_prev', '', 0);
+                               die("You logged out from Workspace preview mode. Reload the browser to log in again.");
+                       }
+               }
 
+                       // If inputcode now, look up the settings:
                if ($inputCode) {
 
                                // Look for keyword configuration record:
                                // - Make sure to remove fe/be cookies (temporarily); BE already done in ADMCMD_preview_postInit()
                        if (is_array($previewData))     {
                                if (!count(t3lib_div::_POST())) {
-                                       if (t3lib_div::getIndpEnv('TYPO3_SITE_URL').'?ADMCMD_prev='.$inputCode === t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'))  {
-
-                                                       // Unserialize configuration:
-                                               $previewConfig = unserialize($previewData['config']);
+                                               // Unserialize configuration:
+                                       $previewConfig = unserialize($previewData['config']);
+
+                                       if ($previewConfig['fullWorkspace']) {  // For full workspace preview we only ADD a get variable to set the preview of the workspace - so all other Get vars are accepted. Hope this is not a security problem. Still posting is not allowed and even if a backend user get initialized it shouldn't lead to situations where users can use those credentials.
+                                       
+                                                       // Set the workspace preview value:
+                                               t3lib_div::_GETset($previewConfig['fullWorkspace'],'ADMCMD_previewWS');
+                                               
+                                                       // If ADMCMD_prev is set the $inputCode value cannot come from a cookie and we set that cookie here. Next time it will be found from the cookie if ADMCMD_prev is not set again...
+                                               if (t3lib_div::_GP('ADMCMD_prev'))      {
+                                                       SetCookie('ADMCMD_prev', t3lib_div::_GP('ADMCMD_prev'), time()+$cookieTTL);     // Lifetime is 1 hour, does it matter much? Requires the user to click the link from their email again if it expires.
+                                               }
+                                               return $previewConfig;
+                                       } elseif (t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.$inputCode === t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'))   {
 
                                                        // Set GET variables:
                                                $GET_VARS = '';
 
                                                        // Return preview keyword configuration:
                                                return $previewConfig;
-                                       } else die(htmlspecialchars('Request URL did not match "'.t3lib_div::getIndpEnv('TYPO3_SITE_URL').'?ADMCMD_prev='.$inputCode.'"'));     // This check is to prevent people from setting additional GET vars via realurl or other URL path based ways of passing parameters.
+                                       } else die(htmlspecialchars('Request URL did not match "'.t3lib_div::getIndpEnv('TYPO3_SITE_URL').'index.php?ADMCMD_prev='.$inputCode.'"'));    // This check is to prevent people from setting additional GET vars via realurl or other URL path based ways of passing parameters.
                                } else die('POST requests are incompatible with keyword preview.');
                        } else die('ADMCMD command could not be executed! (No keyword configuration found)');
                }
         * @return      void
         */
        function getFromCache() {
-               $this->tmpl->getCurrentPageData();
-               $cc = Array();
-               if (is_array($this->tmpl->currentPageData))     {
-                               // BE CAREFULL 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.
-                               // If this hash is not the same in here in this section and after page-generation the page will not be properly cached!
-
-                       $cc['all'] = $this->tmpl->currentPageData['all'];
-                       $cc['rowSum'] = $this->tmpl->currentPageData['rowSum'];
-                       $cc['rootLine'] = $this->tmpl->currentPageData['rootLine'];             // This rootline is used with templates only (matching()-function)
-                       $this->all = $this->tmpl->matching($cc);        // 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.
-                       ksort($this->all);
+               if (!$this->no_cache)   {
+                       $this->tmpl->getCurrentPageData();
+
+                       $cc = Array();
+                       if (is_array($this->tmpl->currentPageData))     {
+                                       // BE CAREFULL 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.
+                                       // If this hash is not the same in here in this section and after page-generation the page will not be properly cached!
+
+                               $cc['all'] = $this->tmpl->currentPageData['all'];
+                               $cc['rowSum'] = $this->tmpl->currentPageData['rowSum'];
+                               $cc['rootLine'] = $this->tmpl->currentPageData['rootLine'];             // This rootline is used with templates only (matching()-function)
+                               $this->all = $this->tmpl->matching($cc);        // 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.
+                               ksort($this->all);
+                       }
                }
 
                $this->content='';      // clearing the content-variable, which will hold the pagecontent
                                        $this->cacheExpires = $row['expires'];
 
                                        if ($this->TYPO3_CONF_VARS['FE']['debug'] || $this->config['config']['debug'])  {
-                                               $this->content.=chr(10).'<!-- Cached page generated '.Date('d/m Y H:i', $row['tstamp']).'. Expires '.Date('d/m Y H:i', $row['expires']).' -->';
+                                               $dateFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'];
+                                               $timeFormat = $GLOBALS['TYPO3_CONF_VARS']['SYS']['hhmm'];
+
+                                               $this->content.=chr(10).'<!-- Cached page generated '.date($dateFormat.' '.$timeFormat, $row['tstamp']).'. Expires '.Date($dateFormat.' '.$timeFormat, $row['expires']).' -->';
                                        }
 
                                }
        }
 
        /**
-        * Returning the cached version of page with hash ->newHash
+        * Returning the cached version of page with hash newHash
         *
         * @return      array           Cached row, if any. Otherwise void.
         */
                                $this->pSetup = $this->tmpl->setup[$this->sPre.'.'];
 
                                if (!is_array($this->pSetup))   {
+                                       header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                                       t3lib_div::sysLog('The page is not configured! [type= '.$this->type.']['.$this->sPre.']', 'cms', 3);
                                        $this->printError('The page is not configured! [type= '.$this->type.']['.$this->sPre.']');
                                        exit;
                                } else {
                                                $this->setSimulReplacementChar();
                                        }
 
-                                               // set default values for removeDefaultJS and inlineStyle2TempFile so CSS and JS are externalized if compatversion is higher than 4.0
-                                       if(!isset($this->config['config']['removeDefaultJS']) && t3lib_div::compat_version('4.0.0')) {
+                                               // Set default values for removeDefaultJS and inlineStyle2TempFile so CSS and JS are externalized if compatversion is higher than 4.0
+                                       if (!isset($this->config['config']['removeDefaultJS']) && t3lib_div::compat_version('4.0'))     {
                                                $this->config['config']['removeDefaultJS'] = 'external';
                                        }
-                                       if(!isset($this->config['config']['inlineStyle2TempFile']) && t3lib_div::compat_version('4.0.0')) {
+                                       if (!isset($this->config['config']['inlineStyle2TempFile']) && t3lib_div::compat_version('4.0'))        {
                                                $this->config['config']['inlineStyle2TempFile'] = 1;
                                        }
 
                                        $this->config['mainScript'] = trim($this->config['config']['mainScript']) ? trim($this->config['config']['mainScript']) : 'index.php';
 
                                                // STAT:
-                                       $theLogFile = $this->TYPO3_CONF_VARS['FE']['logfile_dir'].$this->config['config']['stat_apache_logfile'];
+                                       $theLogFile = $this->TYPO3_CONF_VARS['FE']['logfile_dir'].strftime($this->config['config']['stat_apache_logfile']);
                                                // Add PATH_site left to $theLogFile if the path is not absolute yet
                                        if (!t3lib_div::isAbsPath($theLogFile)) $theLogFile = PATH_site.$theLogFile;
 
                                }
                                $GLOBALS['TT']->pull();
                        } else {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('No template found!', 'cms', 3);
                                $this->printError('No template found!');
                                exit;
                        }
                        // Initialize charset settings etc.
                $this->initLLvars();
 
-                       // We want nice names, so we need to know the charset
+                       // We want nice names, so we need to handle the charset
                if ($setStatPageName)   {
-                       if ($this->config['config']['stat_apache_niceTitle'])   {
+                               // Make life easier and accept variants for utf-8
+                       if (preg_match('/utf-?8/i', $this->config['config']['stat_apache_niceTitle']))  {
+                               $this->config['config']['stat_apache_niceTitle'] = 'utf-8';
+                       }
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $shortTitle = $this->csConvObj->utf8_encode($this->page['title'],$this->renderCharset);
+                       } elseif ($this->config['config']['stat_apache_niceTitle'])     {
                                $shortTitle = $this->csConvObj->specCharsToASCII($this->renderCharset,$this->page['title']);
                        } else {
                                $shortTitle = $this->page['title'];
                        }
-                       $shortTitle = substr(preg_replace('/[^.[:alnum:]_-]/','_',$shortTitle),0,30);
+                       $len = t3lib_div::intInRange($this->config['config']['stat_apache_pageLen'],1,100,30);
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $shortTitle = rawurlencode($this->csConvObj->substr('utf-8',$shortTitle,0,$len));
+                       } else {
+                               $shortTitle = substr(preg_replace('/[^.[:alnum:]_-]/','_',$shortTitle),0,$len);
+                       }
                        $pageName = $this->config['config']['stat_apache_pagenames'] ? $this->config['config']['stat_apache_pagenames'] : '[path][title]--[uid].html';
                        $pageName = str_replace('[title]', $shortTitle ,$pageName);
                        $pageName = str_replace('[uid]',$this->page['uid'],$pageName);
                                array_shift($temp);
                        }
                        $len = t3lib_div::intInRange($this->config['config']['stat_titleLen'],1,100,20);
-                       if ($this->config['config']['stat_apache_niceTitle'])   {
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $path = '';
+                               $c = count($temp);
+                               for ($i=0; $i<$c; $i++) {
+                                       if ($temp[$i]['uid'])   {
+                                               $p = $this->csConvObj->crop('utf-8',$this->csConvObj->utf8_encode($temp[$i]['title'],$this->renderCharset),$len,"\xE2\x80\xA6");        // U+2026; HORIZONTAL ELLIPSIS
+                                               $path .= '/' . rawurlencode($p);
+                                       }
+                               }
+                       } elseif ($this->config['config']['stat_apache_niceTitle'])     {
                                $path = $this->csConvObj->specCharsToASCII($this->renderCharset,$this->sys_page->getPathFromRootline($temp,$len));
                        } else {
                                $path = $this->sys_page->getPathFromRootline($temp,$len);
                        }
-                       $this->config['stat_vars']['pageName'] = str_replace('[path]', preg_replace('/[^.[:alnum:]\/_-]/','_',$path.'/'), $pageName);
+                       if ($this->config['config']['stat_apache_niceTitle'] == 'utf-8')        {
+                               $this->config['stat_vars']['pageName'] = str_replace('[path]', $path.'/', $pageName);
+                       } else {
+                               $this->config['stat_vars']['pageName'] = str_replace('[path]', preg_replace('/[^.[:alnum:]\/_-]/','_',$path.'/'), $pageName);
+                       }
                }
 
                        // No cache
                if ($this->absRefPrefix_force && strcmp($this->config['config']['simulateStaticDocuments'],'PATH_INFO'))        {
                        $redirectUrl = t3lib_div::getIndpEnv('TYPO3_REQUEST_DIR').'index.php?id='.$this->id.'&type='.$this->type;
                        if ($this->config['config']['simulateStaticDocuments_dontRedirectPathInfoError'])       {
+                               header( 'HTTP/1.0 503 Service Temporarily Unavailable' );
+                               t3lib_div::sysLog('PATH_INFO was not configured for this website, and the URL tries to find the page by PATH_INFO!', 'cms', 3);
                                $this->printError('PATH_INFO was not configured for this website, and the URL tries to find the page by PATH_INFO!<br /><br /><a href="'.htmlspecialchars($redirectUrl).'">Click here to get to the right page.</a>','Error: PATH_INFO not configured');
                        } else {
                                header('Location: '.t3lib_div::locationHeaderUrl($redirectUrl));
                        list($tN,$fN) = explode(':',$TF);
                        $this->TCAcachedExtras[$tN]['l10n_mode'][$fN] = 'mergeIfNotBlank';
                }
+
+                       // Setting softExclude:
+               $table_fields = t3lib_div::trimExplode(',', $this->config['config']['sys_language_softExclude'],1);
+               foreach($table_fields as $TF)   {
+                       list($tN,$fN) = explode(':',$TF);
+                       $this->TCAcachedExtras[$tN]['l10n_mode'][$fN] = 'exclude';
+               }
        }
 
        /**
        /**
         * Checks if any email-submissions or submission via the fe_tce
         *
-        * @return      string          'email' if a formmail has been sent, 'fe_tce' if front-end data submission (like forums, guestbooks) is sent. '' if none.
+        * @return      string          "email" if a formmail has been sent, "fe_tce" if front-end data submission (like forums, guestbooks) is sent. "" if none.
         */
        function checkDataSubmission()  {
                $ret = '';
-               if ($_POST['formtype_db'] || $_POST['formtype_mail'])   {
+               $formtype_db = isset($_POST['formtype_db']) || isset($_POST['formtype_db_x']);
+               $formtype_mail = isset($_POST['formtype_mail']) || isset($_POST['formtype_mail_x']);
+               if ($formtype_db || $formtype_mail)     {
                        $refInfo = parse_url(t3lib_div::getIndpEnv('HTTP_REFERER'));
                        if (t3lib_div::getIndpEnv('TYPO3_HOST_ONLY')==$refInfo['host'] || $this->TYPO3_CONF_VARS['SYS']['doNotCheckReferer'])   {
                                if ($this->locDataCheck($_POST['locationData']))        {
-                                       if ($_POST['formtype_mail'])    {
+                                       if ($formtype_mail)     {
                                                $ret = 'email';
-                                       } elseif ($_POST['formtype_db'] && is_array($_POST['data']))    {
+                                       } elseif ($formtype_db && is_array($_POST['data']))     {
                                                $ret = 'fe_tce';
                                        }
                                        $GLOBALS['TT']->setTSlogMessage('"Check Data Submission": Return value: '.$ret,0);
                $EMAIL_VARS = t3lib_div::_POST();
                $locationData = $EMAIL_VARS['locationData'];
                unset($EMAIL_VARS['locationData']);
-               unset($EMAIL_VARS['formtype_mail']);
+               unset($EMAIL_VARS['formtype_mail'], $EMAIL_VARS['formtype_mail_x'], $EMAIL_VARS['formtype_mail_y']);
 
                $integrityCheck = $this->TYPO3_CONF_VARS['FE']['strictFormmail'];
 
-               if(!$this->TYPO3_CONF_VARS['FE']['secureFormmail']) {
+               if (!$this->TYPO3_CONF_VARS['FE']['secureFormmail'])    {
                                // Check recipient field:
                        $encodedFields = explode(',','recipient,recipient_copy');       // These two fields are the ones which contain recipient addresses that can be misused to send mail from foreign servers.
-                       foreach($encodedFields as $fieldKey)    {
+                       foreach ($encodedFields as $fieldKey)   {
                                if (strlen($EMAIL_VARS[$fieldKey]))     {
                                        if ($res = $this->codeString($EMAIL_VARS[$fieldKey], TRUE))     {       // Decode...
                                                $EMAIL_VARS[$fieldKey] = $res;  // Set value if OK
                                                if (@is_file($this->jumpurl))   {
                                                        $mimeType = t3lib_div::_GP('mimeType');
                                                        $mimeType = $mimeType ? $mimeType : 'application/octet-stream';
-                                                       Header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
-                                                       Header('Content-Type: '.$mimeType);
-                                                       Header('Content-Disposition: attachment; filename='.basename($this->jumpurl));
+                                                       header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
+                                                       header('Content-Type: '.$mimeType);
+                                                       header('Content-Disposition: attachment; filename='.basename($this->jumpurl));
                                                        readfile($this->jumpurl);
                                                        exit;
                                                } else die('jumpurl Secure: "'.$this->jumpurl.'" was not a valid file!');
                                if ($TSConf['TSFE.']['jumpUrl_transferSession'])        {
                                        $uParts = parse_url($this->jumpurl);
                                        $params = '&FE_SESSION_KEY='.rawurlencode($this->fe_user->id.'-'.md5($this->fe_user->id.'/'.$this->TYPO3_CONF_VARS['SYS']['encryptionKey']));
-                                       $this->jumpurl.=($uParts['query']?'':'?').$params;      // Add the session parameter ...
+                                       $this->jumpurl.= ($uParts['query']?'':'?').$params;     // Add the session parameter ...
                                }
-                               Header('Location: '.$this->jumpurl);
+                               header('Location: '.$this->jumpurl);
                                exit;
                        }
                }
         * @return      void
         */
        function realPageCacheContent() {
-               $cache_timeout = $this->page['cache_timeout'] ? $this->page['cache_timeout'] : ($this->cacheTimeOutDefault ? $this->cacheTimeOutDefault : 60*60*24);            // seconds until a cached page is too old
+               $cache_timeout = $this->get_cache_timeout();            // seconds until a cached page is too old
                $timeOutTime = $GLOBALS['EXEC_TIME']+$cache_timeout;
                if ($this->config['config']['cache_clearAtMidnight'])   {
                        $midnightTime = mktime (0,0,0,date('m',$timeOutTime),date('d',$timeOutTime),date('Y',$timeOutTime));
                        $this->realPageCacheContent();
                } elseif ($this->tempContent)   {               // If there happens to be temporary content in the cache and the cache was not cleared due to new content put in it... ($this->no_cache=0)
                        $this->clearPageCacheContent();
-            $this->tempContent = false;
+                       $this->tempContent = false;
                }
 
                        // Sets sys-last-change:
@@ -3077,7 +3284,7 @@ if (version == "n3") {
                                $stdMsg = '
                                <br />
                                <div align="center">
-                                       <table border="3" bordercolor="black" cellpadding="2" bgcolor="red">
+                                       <table border="3" bordercolor="black" cellpadding="2" bgcolor="red" summary="">
                                                <tr>
                                                        <td>&nbsp;&nbsp;<font face="Verdana" size="1"><b>'.htmlspecialchars($text).'</b></font>&nbsp;&nbsp;</td>
                                                </tr>
@@ -3122,9 +3329,9 @@ if (version == "n3") {
                                $label = !$this->beUserLogin ? $this->config['config']['beLoginLinkIPList_login'] : $this->config['config']['beLoginLinkIPList_logout'];
                                if ($label)     {
                                        if (!$this->beUserLogin)        {
-                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?redirect_url='.rawurlencode(t3lib_div::getIndpEnv("REQUEST_URI"))).'">'.$label.'</a>';
+                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?redirect_url='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.$label.'</a>';
                                        } else {
-                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?L=OUT&redirect_url='.rawurlencode(t3lib_div::getIndpEnv("REQUEST_URI"))).'">'.$label.'</a>';
+                                               $link = '<a href="'.htmlspecialchars(TYPO3_mainDir.'index.php?L=OUT&redirect_url='.rawurlencode(t3lib_div::getIndpEnv('REQUEST_URI'))).'">'.$label.'</a>';
                                        }
                                        return $link;
                                }
@@ -3183,7 +3390,7 @@ if (version == "n3") {
         * @return      string          The body of the filename.
         * @see getSimulFileName(), t3lib_tstemplate::linkData(), tslib_frameset::frameParams()
         */
-       function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache='')     {
+       function makeSimulFileName($inTitle,$page,$type,$addParams='',$no_cache=false)  {
                $titleChars = intval($this->config['config']['simulateStaticDocuments_addTitle']);
                        // Default value is 30 but values > 1 will be override this
                if($titleChars==1)      { $titleChars = 30; }
@@ -3260,8 +3467,8 @@ if (version == "n3") {
         * @see makeSimulFileName(), publish.php
         */
        function getSimulFileName()     {
-               $url='';
-               $url.=$this->makeSimulFileName($this->page['title'], $this->page['alias']?$this->page['alias']:$this->id, $this->type).'.html';
+               $url = '';
+               $url.= $this->makeSimulFileName($this->page['title'], $this->page['alias']?$this->page['alias']:$this->id, $this->type).'.html';
                return $url;
        }
 
@@ -3271,7 +3478,7 @@ if (version == "n3") {
         * @return      void
         */
        function setSimulReplacementChar() {
-               $replacement = $defChar = t3lib_div::compat_version('4.0.0') ? '-' : '_';
+               $replacement = $defChar = t3lib_div::compat_version('4.0') ? '-' : '_';
                if (isset($this->config['config']['simulateStaticDocuments_replacementChar'])) {
                        $replacement = trim($this->config['config']['simulateStaticDocuments_replacementChar']);
                        if (urlencode($replacement) != $replacement) {
@@ -3293,20 +3500,40 @@ if (version == "n3") {
        function fileNameASCIIPrefix($inTitle,$titleChars,$mergeChar='.')       {
                $out = $this->csConvObj->specCharsToASCII($this->renderCharset, $inTitle);
                        // Get replacement character
-               $replacementChar = &$this->config['config']['simulateStaticDocuments_replacementChar'];
+               $replacementChar = $this->config['config']['simulateStaticDocuments_replacementChar'];
                $replacementChars = '_\-' . ($replacementChar != '_' && $replacementChar != '-' ? $replacementChar : '');
                $out = preg_replace('/[^A-Za-z0-9_-]/', $replacementChar, trim(substr($out, 0, $titleChars)));
                $out = preg_replace('/([' . $replacementChars . ']){2,}/', '\1', $out);
                $out = preg_replace('/[' . $replacementChars . ']?$/', '', $out);
                $out = preg_replace('/^[' . $replacementChars . ']?/', '', $out);
                if (strlen($out)) {
-                       $out .= $mergeChar;
+                       $out.= $mergeChar;
                }
 
                return $out;
        }
 
        /**
+        * Encryption (or decryption) of a single character.
+        * Within the given range the character is shifted with the supplied offset.
+        *
+        * @param       int             Ordinal of input character
+        * @param       int             Start of range
+        * @param       int             End of range
+        * @param       int             Offset
+        * @return      string          encoded/decoded version of character
+        */
+       function encryptCharcode($n,$start,$end,$offset)        {
+               $n = $n + $offset;
+               if ($offset > 0 && $n > $end)   {
+                       $n = $start + ($n - $end - 1);
+               } else if ($offset < 0 && $n < $start)  {
+                       $n = $end - ($start - $n - 1);
+               }
+               return chr($n);
+       }
+
+       /**
         * Encryption of email addresses for <A>-tags See the spam protection setup in TS 'config.'
         *
         * @param       string          Input string to en/decode: "mailto:blabla@bla.com"
@@ -3321,10 +3548,20 @@ if (version == "n3") {
                                $out .= '&#'.ord(substr($string, $a, 1)).';';
                        }
                } else  {
-                       for ($a=0; $a<strlen($string); $a++)    {
-                               $charValue = ord(substr($string,$a,1));
-                               $charValue+= intval($this->spamProtectEmailAddresses)*($back?-1:1);
-                               $out.= chr($charValue);
+                               // like str_rot13() but with a variable offset and a wider character range
+                       $len = strlen($string);
+                       $offset = intval($this->spamProtectEmailAddresses)*($back?-1:1);
+                       for ($i=0; $i<$len; $i++)       {
+                               $charValue = ord($string{$i});
+                               if ($charValue >= 0x2B && $charValue <= 0x3A)   {       // 0-9 . , - + / :
+                                       $out .= $this->encryptCharcode($charValue,0x2B,0x3A,$offset);
+                               } elseif ($charValue >= 0x40 && $charValue <= 0x5A)     {       // A-Z @
+                                       $out .= $this->encryptCharcode($charValue,0x40,0x5A,$offset);
+                               } else if ($charValue >= 0x61 && $charValue <= 0x7A)    {       // a-z
+                                       $out .= $this->encryptCharcode($charValue,0x61,0x7A,$offset);
+                               } else {
+                                       $out .= $string{$i};
+                               }
                        }
                }
                return $out;
@@ -3341,7 +3578,7 @@ if (version == "n3") {
         */
        function codeString($string, $decode=FALSE)     {
 
-               if ($decode) {
+               if ($decode)    {
                        list($md5Hash, $str) = explode(':',$string,2);
                        $newHash = substr(md5($this->TYPO3_CONF_VARS['SYS']['encryptionKey'].':'.$str),0,10);
                        if (!strcmp($md5Hash, $newHash))        {
@@ -3496,7 +3733,7 @@ if (version == "n3") {
         */
        function prefixLocalAnchorsWithScript() {
                $scriptPath = substr(t3lib_div::getIndpEnv('TYPO3_REQUEST_URL'),strlen(t3lib_div::getIndpEnv('TYPO3_SITE_URL')));
-               $this->content = preg_replace('/(<(a|area).*?href=")(#[^"]*")/i','$1' . htmlspecialchars($scriptPath) . '$3',$this->content);
+               $this->content = preg_replace('/(<(a|area).*?href=")(#[^"]*")/i','${1}' . htmlspecialchars($scriptPath) . '${3}',$this->content);
        }
 
        /**
@@ -3644,13 +3881,13 @@ if (version == "n3") {
 '              // JS function for mouse-over
        function over(name,imgObj)      {       //
                if (version == "n3" && document[name]) {document[name].src = eval(name+"_h.src");}
-               else if (typeof(document.getElementById)=="function" && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
+               else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_h.src");}
                else if (imgObj)        {imgObj.src = eval(name+"_h.src");}
        }
                // JS function for mouse-out
        function out(name,imgObj)       {       //
                if (version == "n3" && document[name]) {document[name].src = eval(name+"_n.src");}
-               else if (typeof(document.getElementById)=="function" && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
+               else if (document.getElementById && document.getElementById(name)) {document.getElementById(name).src = eval(name+"_n.src");}
                else if (imgObj)        {imgObj.src = eval(name+"_n.src");}
        }';
                                break;
@@ -3728,6 +3965,25 @@ if (version == "n3") {
        }
 
        /**
+        * Get the cache timeout for the current page.
+        *
+        * @return      integer         The cache timeout for the current page.
+        */
+       function get_cache_timeout() {
+                       // Cache period was set for the page:
+               if ($this->page['cache_timeout']) {
+                       $cacheTimeout = $this->page['cache_timeout'];
+                       // Cache period was set for the whole site:
+               } elseif ($this->cacheTimeOutDefault) {
+                       $cacheTimeout = $this->cacheTimeOutDefault;
+                       // No cache period set at all, so we take one day (60*60*24 seconds = 86400 seconds):
+               } else {
+                       $cacheTimeout = 86400;
+               }
+               return $cacheTimeout;
+       }
+
+       /**
         * Substitute function for the PHP mail() function.
         * It will encode the email with the setting of TS 'config.notification_email_encoding' (base64 or none)
         * It will also find all links to http:// in the text and substitute with a shorter link using the redirect feature which stores the long link in the database. Depends on configuration in TS 'config.notification_email_urlmode'
@@ -3740,14 +3996,33 @@ if (version == "n3") {
         * @see t3lib_div::plainMailEncoded()
         */
        function plainMailEncoded($email,$subject,$message,$headers='') {
-               $urlmode=$this->config['config']['notification_email_urlmode']; // '76', 'all', ''
+               $urlmode = $this->config['config']['notification_email_urlmode'];       // '76', 'all', ''
 
                if ($urlmode)   {
-                       $message=t3lib_div::substUrlsInPlainText($message,$urlmode);
+                       $message = t3lib_div::substUrlsInPlainText($message,$urlmode);
                }
 
-               $encoding = $this->config['config']['notification_email_encoding'] ? $this->config['config']['notification_email_encoding'] : 'quoted-printable';
-               $charset = $this->config['config']['notification_email_charset'] ? $this->config['config']['notification_email_charset'] : ($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] ? $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'] : 'ISO-8859-1');
+               $encoding = $this->config['config']['notification_email_encoding'] ? $this->config['config']['notification_email_encoding'] : '';
+               $charset = $this->renderCharset;
+
+               $convCharset = FALSE;   // do we need to convert mail data?
+               if ($this->config['config']['notification_email_charset'])      {       // Respect config.notification_email_charset if it was set
+                       $charset = $this->csConvObj->parse_charset($this->config['config']['notification_email_charset']);
+                       if ($charset != $this->renderCharset)   {
+                               $convCharset = TRUE;
+                       }
+
+               } elseif ($this->metaCharset != $this->renderCharset)   {       // Use metaCharset for mail if different from renderCharset
+                       $charset = $this->metaCharset;
+                       $convCharset = TRUE;
+               }
+
+               if ($convCharset)       {
+                       $email = $this->csConvObj->conv($email,$this->renderCharset,$charset);
+                       $subject = $this->csConvObj->conv($subject,$this->renderCharset,$charset);
+                       $message = $this->csConvObj->conv($message,$this->renderCharset,$charset);
+                       $headers = $this->csConvObj->conv($headers,$this->renderCharset,$charset);
+               }
 
                t3lib_div::plainMailEncoded(
                        $email,