Index: t3lib/class.t3lib_tsparser.php =================================================================== --- t3lib/class.t3lib_tsparser.php (revision 9236) +++ t3lib/class.t3lib_tsparser.php (working copy) @@ -514,7 +514,7 @@ 'files' => $includedFiles, ); } - return ''; + return "\n###\n### ERROR: Recursion!\n###\n"; } $splitStr=' + */ + function extractIncludes($string, $cycle_counter=1, $extractedFileNames=array()) { + + if ($cycle_counter>10) { + t3lib_div::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags','Core',2); + return "\n###\n### ERROR: Recursion!\n###\n"; + } + + $fileContent = array(); + $restContent = array(); + $fileName = NULL; + $inIncludePart = false; + $lines = explode("\n", $string); + $skipNextLineIfEmpty = false; + $openingCommentedIncludeStatement = NULL; + foreach ($lines as $line) { + + // t3lib_TSparser::checkIncludeLines inserts an additional empty line, remove this again + if ($skipNextLineIfEmpty) { + if (trim($line) == '') { + continue; + } + $skipNextLineIfEmpty = false; + } + + if (!$inIncludePart) { // outside commented include statements + + // search for beginning commented include statements + $matches = array(); + if (preg_match('/###\s*\s*BEGIN/i', $line, $matches)) { + + // save this line in case there is no ending tag + $openingCommentedIncludeStatement = trim($line); + $openingCommentedIncludeStatement = trim(preg_replace('/### Warning: .*###/', '', $openingCommentedIncludeStatement)); + + // found a commented include statement + $fileName = trim($matches[1]); + $inIncludePart = true; + + $expectedEndTag = '### END'; + // strip all whitespace characters to make comparision safer + $expectedEndTag = strtolower(preg_replace('/\s/', '', $expectedEndTag)); + } else { + // if this is not a beginning commented include statement this line goes into the rest content + $restContent[] = $line; + } + + } else { // inside commented include statements + + // search for the matching ending commented include statement + $strippedLine = strtolower(preg_replace('/\s/', '', $line)); + if (strpos($strippedLine, $expectedEndTag) !== false) { + + // found the matching ending include statement + $fileContentString = implode("\n", $fileContent); + + // write the content to the file + $realFileName = t3lib_div::getFileAbsFileName($fileName); + + // some file checks + if (empty($realFileName)) { + throw new Exception(sprintf('"%s" is not a valid file location.', $fileName)); + } + + if (!is_writable($realFileName)) { + throw new Exception(sprintf('"%s" is not writable.', $fileName)); + } + + if (in_array($realFileName, $extractedFileNames)) { + throw new Exception(sprintf('Recursive/multiple inclusion of file "%s"', $realFileName)); + } + $extractedFileNames[] = $realFileName; + + // recursive call to detected nested commented include statements + $fileContentString = self::extractIncludes($fileContentString, ++$cycle_counter, $extractedFileNames); + + if (!t3lib_div::writeFile($realFileName, $fileContentString)) { + throw new Exception(sprintf('Could not write file "%s"', $realFileName)); + } + + // insert reference to the file in the rest content + $restContent[] = ""; + + // reset variables (preparing for the next commented include statement) + $fileContent = array(); + $fileName = NULL; + $inIncludePart = false; + $openingCommentedIncludeStatement = NULL; + // t3lib_TSparser::checkIncludeLines inserts an additional empty line, remove this again + $skipNextLineIfEmpty = true; + } else { + // if this is not a ending commented include statement this line goes into the file content + $fileContent[] = $line; + } + + } + + } + + // if we're still inside commented include statements copy the lines back to the rest content + if ($inIncludePart) { + $restContent[] = $openingCommentedIncludeStatement . ' ### Warning: Corresponding end line missing! ###'; + $restContent = array_merge($restContent, $fileContent); + } + + $restContentString = implode("\n", $restContent); + return $restContentString; + } + /** + * Processes the string in each value of the input array with extractIncludes + * + * @param array Array with TypoScript in each value + * @return array Same array but where the values has been processed with extractIncludes + * @author Fabrizio Branca + */ + function extractIncludes_array($array) { + foreach ($array as $k => $v) { + $array[$k]=t3lib_TSparser::extractIncludes($array[$k]); + } + return $array; + } Index: typo3/sysext/t3editor/classes/class.tx_t3editor_hooks_tstemplateinfo.php =================================================================== --- typo3/sysext/t3editor/classes/class.tx_t3editor_hooks_tstemplateinfo.php (revision 9236) +++ typo3/sysext/t3editor/classes/class.tx_t3editor_hooks_tstemplateinfo.php (working copy) @@ -168,6 +168,12 @@ } } if (count($recData)) { + + // process template row before saving + require_once t3lib_extMgm::extPath('tstemplate_info').'class.tx_tstemplateinfo.php'; + $tstemplateinfo = t3lib_div::makeInstance('tx_tstemplateinfo'); /* @var $tstemplateinfo tx_tstemplateinfo */ + $recData['sys_template'][$saveId] = $tstemplateinfo->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]); + // Create new tce-object $tce = t3lib_div::makeInstance('t3lib_TCEmain'); $tce->stripslashes_values = 0; Index: typo3/sysext/tstemplate_info/class.tx_tstemplateinfo.php =================================================================== --- typo3/sysext/tstemplate_info/class.tx_tstemplateinfo.php (revision 9236) +++ typo3/sysext/tstemplate_info/class.tx_tstemplateinfo.php (working copy) @@ -152,8 +152,40 @@ $tmpl->init(); $tplRow = $tmpl->ext_getFirstTemplate($pageId, $template_uid); // Get the row of the first VISIBLE template of the page. whereclause like the frontend. + $tplRow = $this->processTemplateRowAfterLoading($tplRow); return (is_array($tplRow) ? true : false); } + + /** + * Process template row after loading + * + * @param array $tplRow: template row + * @return array preprocessed template row + * @author Fabrizio Branca + */ + function processTemplateRowAfterLoading(array $tplRow) { + if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) { + // Let the recursion detection counter start at 91, so that only 10 recursive calls will be resolved + // Otherwise the editor will be bloated with way to many lines making it hard the break the cyclic recursion. + $tplRow['config'] = t3lib_TSparser::checkIncludeLines($tplRow['config'], 91); + $tplRow['constants'] = t3lib_TSparser::checkIncludeLines($tplRow['constants'], 91); + } + return $tplRow; + } + + /** + * Process template row before saving + * + * @param array $tplRow: template row + * @return array preprocessed template row + * @author Fabrizio Branca + */ + function processTemplateRowBeforeSaving(array $tplRow) { + if ($this->pObj->MOD_SETTINGS['includeTypoScriptFileContent']) { + $tplRow = t3lib_TSparser::extractIncludes_array($tplRow); + } + return $tplRow; + } /** * The main processing method if this class @@ -163,6 +195,8 @@ function main() { global $SOBE,$BE_USER,$LANG,$BACK_PATH,$TCA_DESCR,$TCA,$CLIENT,$TYPO3_CONF_VARS; global $tmpl,$tplRow,$theConstants; + + $this->pObj->MOD_MENU['includeTypoScriptFileContent'] = true; $edit = $this->pObj->edit; $e = $this->pObj->e; @@ -274,6 +308,9 @@ $recData['sys_template'][$saveId]['resources'] = $resList; } if (count($recData)) { + + $recData['sys_template'][$saveId] = $this->processTemplateRowBeforeSaving($recData['sys_template'][$saveId]); + // Create new tce-object $tce = t3lib_div::makeInstance('t3lib_TCEmain'); $tce->stripslashes_values=0; @@ -413,6 +450,19 @@ if ($e['constants']) { $outCode = ''; $outCode.= ''; + + // Display "Include TypoScript file content?" checkbox + $outCode .= t3lib_BEfunc::getFuncCheck( + $this->pObj->id, + 'SET[includeTypoScriptFileContent]', + $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], + 'index.php', + '&e[constants]=1', + 'id="checkIncludeTypoScriptFileContent"' + ); + $outCode .= '
'; + + $theOutput.= $this->pObj->doc->spacer(15); $theOutput.= $this->pObj->doc->section($GLOBALS['LANG']->getLL('constants'), ''); $theOutput.= $this->pObj->doc->sectionEnd().$outCode; @@ -445,6 +495,18 @@ } if ($e['config']) { $outCode=''; + $outCode.= ''; + + // Display "Include TypoScript file content?" checkbox + $outCode .= t3lib_BEfunc::getFuncCheck( + $this->pObj->id, + 'SET[includeTypoScriptFileContent]', + $this->pObj->MOD_SETTINGS['includeTypoScriptFileContent'], + 'index.php', + '&e[config]=1', + 'id="checkIncludeTypoScriptFileContent"' + ); + $outCode .= '
'; if (t3lib_extMgm::isLoaded('tsconfig_help')) { $url = $BACK_PATH.'wizard_tsconfig.php?mode=tsref'; @@ -455,12 +517,11 @@ $outCode.= ''.t3lib_iconWorks::getSpriteIcon('actions-system-typoscript-documentation-open', array('title'=> $GLOBALS['LANG']->sL('LLL:EXT:lang/locallang_common.xml:tsRef', true))) . ''; } - $outCode.= ''; $theOutput.= $this->pObj->doc->spacer(15); $theOutput.= $this->pObj->doc->section($GLOBALS['LANG']->getLL('setup'), ''); $theOutput.= $this->pObj->doc->sectionEnd().$outCode; } - + // Processing: $outCode = ''; $outCode.= $this->tableRow( Index: typo3/sysext/tstemplate_info/locallang.xml =================================================================== --- typo3/sysext/tstemplate_info/locallang.xml (revision 9236) +++ typo3/sysext/tstemplate_info/locallang.xml (working copy) @@ -29,6 +29,7 @@ + \ No newline at end of file