Example #1
0
    /**
     * Search for commented INCLUDE_TYPOSCRIPT statements
     * and save the content between the BEGIN and the END line to the specified file
     *
     * @param string  $string Template content
     * @param int $cycle_counter Counter for detecting endless loops
     * @param array   $extractedFileNames
     * @param string  $parentFilenameOrPath
     *
     * @throws \RuntimeException
     * @throws \UnexpectedValueException
     * @return string Template content with uncommented include statements
     */
    public static function extractIncludes($string, $cycle_counter = 1, array $extractedFileNames = array(), $parentFilenameOrPath = '')
    {
        if ($cycle_counter > 10) {
            GeneralUtility::sysLog('It appears like TypoScript code is looping over itself. Check your templates for "<INCLUDE_TYPOSCRIPT: ..." tags', 'Core', GeneralUtility::SYSLOG_SEVERITY_WARNING);
            return '
###
### ERROR: Recursion!
###
';
        }
        $expectedEndTag = '';
        $fileContent = array();
        $restContent = array();
        $fileName = NULL;
        $inIncludePart = FALSE;
        $lines = preg_split("/\r\n|\n|\r/", $string);
        $skipNextLineIfEmpty = FALSE;
        $openingCommentedIncludeStatement = NULL;
        $optionalProperties = '';
        foreach ($lines as $line) {
            // \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::checkIncludeLines inserts
            // an additional empty line, remove this again
            if ($skipNextLineIfEmpty) {
                if (trim($line) === '') {
                    continue;
                }
                $skipNextLineIfEmpty = FALSE;
            }
            // Outside commented include statements
            if (!$inIncludePart) {
                // Search for beginning commented include statements
                if (preg_match('/###\\s*<INCLUDE_TYPOSCRIPT:\\s*source\\s*=\\s*"\\s*((?i)file|dir)\\s*:\\s*([^"]*)"(.*)>\\s*BEGIN/i', $line, $matches)) {
                    // Found a commented include statement
                    // Save this line in case there is no ending tag
                    $openingCommentedIncludeStatement = trim($line);
                    $openingCommentedIncludeStatement = preg_replace('/\\s*### Warning: .*###\\s*/', '', $openingCommentedIncludeStatement);
                    // type of match: FILE or DIR
                    $inIncludePart = strtoupper($matches[1]);
                    $fileName = $matches[2];
                    $optionalProperties = $matches[3];
                    $expectedEndTag = '### <INCLUDE_TYPOSCRIPT: source="' . $inIncludePart . ':' . $fileName . '"' . $optionalProperties . '> END';
                    // Strip all whitespace characters to make comparison 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;
                }
                //if (is_array($matches)) GeneralUtility::devLog('matches', 'TypoScriptParser', 0, $matches);
            } else {
                // Inside commented include statements
                // Search for the matching ending commented include statement
                $strippedLine = preg_replace('/\\s/', '', $line);
                if (stripos($strippedLine, $expectedEndTag) !== FALSE) {
                    // Found the matching ending include statement
                    $fileContentString = implode(PHP_EOL, $fileContent);
                    // Write the content to the file
                    // Resolve a possible relative paths if a parent file is given
                    if ($parentFilenameOrPath !== '' && $fileName[0] === '.') {
                        $realFileName = PathUtility::getAbsolutePathOfRelativeReferencedFileOrPath($parentFilenameOrPath, $fileName);
                    } else {
                        $realFileName = $fileName;
                    }
                    $realFileName = GeneralUtility::getFileAbsFileName($realFileName);
                    if ($inIncludePart === 'FILE') {
                        // Some file checks
                        if (!GeneralUtility::verifyFilenameAgainstDenyPattern($realFileName)) {
                            throw new \UnexpectedValueException(sprintf('File "%s" was not included since it is not allowed due to fileDenyPattern.', $fileName), 1382651858);
                        }
                        if (empty($realFileName)) {
                            throw new \UnexpectedValueException(sprintf('"%s" is not a valid file location.', $fileName), 1294586441);
                        }
                        if (!is_writable($realFileName)) {
                            throw new \RuntimeException(sprintf('"%s" is not writable.', $fileName), 1294586442);
                        }
                        if (in_array($realFileName, $extractedFileNames)) {
                            throw new \RuntimeException(sprintf('Recursive/multiple inclusion of file "%s"', $realFileName), 1294586443);
                        }
                        $extractedFileNames[] = $realFileName;
                        // Recursive call to detected nested commented include statements
                        $fileContentString = self::extractIncludes($fileContentString, $cycle_counter + 1, $extractedFileNames, $realFileName);
                        // Write the content to the file
                        if (!GeneralUtility::writeFile($realFileName, $fileContentString)) {
                            throw new \RuntimeException(sprintf('Could not write file "%s"', $realFileName), 1294586444);
                        }
                        // Insert reference to the file in the rest content
                        $restContent[] = '<INCLUDE_TYPOSCRIPT: source="FILE:' . $fileName . '"' . $optionalProperties . '>';
                    } else {
                        // must be DIR
                        // Some file checks
                        if (empty($realFileName)) {
                            throw new \UnexpectedValueException(sprintf('"%s" is not a valid location.', $fileName), 1366493602);
                        }
                        if (!is_dir($realFileName)) {
                            throw new \RuntimeException(sprintf('"%s" is not a directory.', $fileName), 1366493603);
                        }
                        if (in_array($realFileName, $extractedFileNames)) {
                            throw new \RuntimeException(sprintf('Recursive/multiple inclusion of directory "%s"', $realFileName), 1366493604);
                        }
                        $extractedFileNames[] = $realFileName;
                        // Recursive call to detected nested commented include statements
                        self::extractIncludes($fileContentString, $cycle_counter + 1, $extractedFileNames, $realFileName);
                        // just drop content between tags since it should usually just contain individual files from that dir
                        // Insert reference to the dir in the rest content
                        $restContent[] = '<INCLUDE_TYPOSCRIPT: source="DIR:' . $fileName . '"' . $optionalProperties . '>';
                    }
                    // Reset variables (preparing for the next commented include statement)
                    $fileContent = array();
                    $fileName = NULL;
                    $inIncludePart = FALSE;
                    $openingCommentedIncludeStatement = NULL;
                    // \TYPO3\CMS\Core\TypoScript\Parser\TypoScriptParser::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(PHP_EOL, $restContent);
        return $restContentString;
    }
 /**
  * @param $baseFileName
  * @param $includeFileName
  * @param $expectedFileName
  * @test
  * @dataProvider getAbsolutePathOfRelativeReferencedFileOrPathResolvesFileCorrectlyDataProvider
  */
 public function getAbsolutePathOfRelativeReferencedFileOrPathResolvesFileCorrectly($baseFileName, $includeFileName, $expectedFileName)
 {
     $resolvedFilename = \TYPO3\CMS\Core\Utility\PathUtility::getAbsolutePathOfRelativeReferencedFileOrPath($baseFileName, $includeFileName);
     $this->assertEquals($expectedFileName, $resolvedFilename);
 }