2 namespace TYPO3\CMS\Core\Resource;
60 <IfModule mod_expires.c>
62 ExpiresDefault "access plus 7 days"
73 if (!is_dir(PATH_site . $this->targetDirectory)) {
77 if (
$GLOBALS[
'TYPO3_CONF_VARS'][
'SYS'][
'generateApacheHtaccess']) {
79 $htaccessPath = PATH_site . $this->targetDirectory .
'.htaccess';
80 if (!file_exists($htaccessPath)) {
85 $compressionLevel =
$GLOBALS[
'TYPO3_CONF_VARS'][TYPO3_MODE][
'compressionLevel'];
87 if (extension_loaded(
'zlib') && $compressionLevel) {
88 $this->createGzipped =
true;
91 $this->gzipCompressionLevel = (int)$compressionLevel;
127 $rootPath = TYPO3_MODE ===
'BE' ? PATH_typo3 : PATH_site;
193 $filesToIncludeByType = array(
'all' => array());
194 foreach ($cssFiles as $key => $fileOptions) {
196 if (!empty($fileOptions[
'excludeFromConcatenation'])) {
203 !isset($options[
'baseDirectories'])
205 $filenameFromMainDir, array_merge($options[
'baseDirectories'], array($this->targetDirectory))
208 $type = isset($fileOptions[
'media']) ? strtolower($fileOptions[
'media']) :
'all';
209 if (!isset($filesToIncludeByType[$type])) {
210 $filesToIncludeByType[$type] = array();
212 if ($fileOptions[
'forceOnTop']) {
213 array_unshift($filesToIncludeByType[$type], $filenameFromMainDir);
215 $filesToIncludeByType[$type][] = $filenameFromMainDir;
218 unset($cssFiles[$key]);
221 if (!empty($filesToIncludeByType)) {
222 foreach ($filesToIncludeByType as $mediaOption => $filesToInclude) {
223 if (empty($filesToInclude)) {
227 $targetFileRelative = $this->relativePath . $targetFile;
228 $concatenatedOptions = array(
229 'file' => $targetFileRelative,
230 'rel' =>
'stylesheet',
231 'media' => $mediaOption,
233 'excludeFromConcatenation' =>
true,
234 'forceOnTop' =>
false,
238 $cssFiles = array_merge($cssFiles, array($targetFileRelative => $concatenatedOptions));
252 $filesToInclude = array();
253 foreach ($jsFiles as $key => $fileOptions) {
255 if (empty($fileOptions[
'section']) || !empty($fileOptions[
'excludeFromConcatenation'])) {
258 if (!isset($filesToInclude[$fileOptions[
'section']])) {
259 $filesToInclude[$fileOptions[
'section']] = array();
263 if ($fileOptions[
'forceOnTop']) {
264 array_unshift($filesToInclude[$fileOptions[
'section']], $filenameFromMainDir);
266 $filesToInclude[$fileOptions[
'section']][] = $filenameFromMainDir;
269 unset($jsFiles[$key]);
271 if (!empty($filesToInclude)) {
272 foreach ($filesToInclude as $section => $files) {
274 $targetFileRelative = $this->relativePath . $targetFile;
275 $concatenatedOptions = array(
276 'file' => $targetFileRelative,
277 'type' =>
'text/javascript',
278 'section' => $section,
280 'excludeFromConcatenation' =>
true,
281 'forceOnTop' =>
false,
285 $jsFiles = array_merge(array($targetFileRelative => $concatenatedOptions), $jsFiles);
325 $type = strtolower(trim($type,
'. '));
327 throw new \InvalidArgumentException(
'No valid file type given for files to be merged.', 1308957498);
332 foreach ($filesToInclude as $key =>
$filename) {
344 $filesToInclude[$key] = $localFilename;
354 if (@file_exists($filenameAbsolute)) {
355 $fileStatus = stat($filenameAbsolute);
356 $unique .= $filenameAbsolute . $fileStatus[
'mtime'] . $fileStatus[
'size'];
358 $unique .= $filenameAbsolute;
361 $targetFile = $this->targetDirectory .
'merged-' . md5($unique) .
'.' . $type;
363 if (!file_exists((PATH_site . $targetFile))) {
372 $concatenated .= LF . $contents;
375 if ($type ===
'css') {
391 $filesAfterCompression = array();
392 foreach ($cssFiles as $key => $fileOptions) {
394 if ($fileOptions[
'compress']) {
396 $fileOptions[
'compress'] =
false;
398 $filesAfterCompression[
$filename] = $fileOptions;
400 $filesAfterCompression[$key] = $fileOptions;
403 return $filesAfterCompression;
422 if (@file_exists($filenameAbsolute)) {
423 $fileStatus = stat($filenameAbsolute);
424 $unique = $filenameAbsolute . $fileStatus[
'mtime'] . $fileStatus[
'size'];
426 $unique = $filenameAbsolute;
430 $targetFile = $this->targetDirectory . $pathinfo[
'filename'] .
'-' . md5($unique) .
'.css';
432 if (!file_exists((PATH_site . $targetFile)) || $this->createGzipped && !file_exists((PATH_site . $targetFile .
'.gzip'))) {
434 if (strpos(
$filename, $this->targetDirectory) ===
false) {
470 $matches[6] = preg_replace(
'/\\s++([+>{};,)])/S',
'$1', $matches[6]);
472 $matches[6] = preg_replace(
'/([+>{}:;,(])\\s++/S',
'$1', $matches[6]);
474 $matches[6] = preg_replace(
'/;?\\}/S',
'}
478 /*T2\\*/' . $matches[6] .
'
483 return 'calc' . $matches[8];
484 }
elseif (isset($matches[9])) {
486 $matches[9] = preg_replace(
'/^\\s++/',
'', $matches[9]);
488 $matches[9] = preg_replace(
'/\\s++$/',
'', $matches[9]);
490 $matches[9] = preg_replace(
'/\\s{2,}+/',
' ', $matches[9]);
492 $matches[9] = preg_replace(
'/\\s++([+>{};,)])/S',
'$1', $matches[9]);
494 $matches[9] = preg_replace(
'/([+>{}:;,(])\\s++/S',
'$1', $matches[9]);
496 $matches[9] = preg_replace(
'/;?\\}/S',
'}
501 return $matches[0] .
'
502 /* ERROR! Unexpected _proccess_css_minify() parameter */
514 $filesAfterCompression = array();
515 foreach ($jsFiles as $fileName => $fileOptions) {
517 if ($fileOptions[
'compress']) {
518 $compressedFilename = $this->
compressJsFile($fileOptions[
'file']);
519 $fileOptions[
'compress'] =
false;
520 $fileOptions[
'file'] = $compressedFilename;
521 $filesAfterCompression[$compressedFilename] = $fileOptions;
523 $filesAfterCompression[$fileName] = $fileOptions;
526 return $filesAfterCompression;
539 if (@file_exists($filenameAbsolute)) {
540 $fileStatus = stat($filenameAbsolute);
541 $unique = $filenameAbsolute . $fileStatus[
'mtime'] . $fileStatus[
'size'];
543 $unique = $filenameAbsolute;
546 $targetFile = $this->targetDirectory . $pathinfo[
'filename'] .
'-' . md5($unique) .
'.js';
548 if (!file_exists((PATH_site . $targetFile)) || $this->createGzipped && !file_exists((PATH_site . $targetFile .
'.gzip'))) {
564 if (empty($this->backPath)) {
568 if (strpos(
$filename, $this->backPath) === 0) {
569 $file = str_replace($this->backPath,
'',
$filename);
575 if (is_file(realpath(PATH_site . TYPO3_mainDir .
$filename))) {
579 $backPath = str_replace(TYPO3_mainDir,
'', $this->backPath);
580 $file = str_replace(
$backPath,
'', $filename);
581 if (substr($file, 0, 3) ===
'../') {
584 $file = PATH_site . $file;
587 if (is_file($file)) {
588 $mainDirDepth = substr_count(TYPO3_mainDir,
'/');
589 return str_repeat(
'../', $mainDirDepth) . str_replace(PATH_site,
'', $file);
592 return substr($filename, strlen($this->backPath));
604 foreach ($baseDirectories as $baseDirectory) {
622 $mainDir = TYPO3_MODE ===
'BE' ? TYPO3_mainDir :
'';
623 $newDir =
'../../' . $mainDir . $oldDir;
625 if (stripos($contents,
'url') !==
false) {
626 $regex =
'/url(\\(\\s*["\']?(?!\\/)([^"\']+)["\']?\\s*\\))/iU';
630 if (stripos($contents,
'@import') !==
false) {
631 $regex =
'/@import\\s*(["\']?(?!\\/)([^"\']+)["\']?)/i';
649 $replacements = array();
650 $wrap = explode(
'|', $wrap);
651 preg_match_all($regex, $contents, $matches);
652 foreach ($matches[2] as $matchCount => $match) {
654 $match = trim($match,
'\'" ');
655 // we must not rewrite paths containing ":
" or "url(
", e.g. data URIs (see RFC 2397)
656 if (strpos($match, ':') === false && !preg_match('/url\\s*\\(/i', $match)) {
657 $newPath = GeneralUtility::resolveBackPath($newDir . $match);
658 $replacements[$matches[1][$matchCount]] = $wrap[0] . $newPath . $wrap[1];
661 // replace URL paths in content
662 if (!empty($replacements)) {
663 $contents = str_replace(array_keys($replacements), array_values($replacements), $contents);
675 protected function cssFixStatements($contents)
678 $comment = LF . '/* moved by compressor */' . LF;
679 // nothing to do, so just return contents
680 if (stripos($contents, '@charset') === false && stripos($contents, '@import') === false && stripos($contents, '@namespace') === false) {
683 $regex = '/@(charset|import|namespace)\\s*(url)?\\s*\\(?\\s*["\
']?[^"\'\\)]+["\']?\\s*\\)?\\s*;/i';
684 preg_match_all($regex, $contents, $matches);
685 if (!empty($matches[0])) {
687 $contents = str_replace($matches[0],
'', $contents);
689 $contents = $comment . implode($comment, $matches[0]) . LF . trim($contents);
705 if ($this->createGzipped) {
737 $filename = $this->targetDirectory .
'external-' . md5(
$url);
756 $contents = preg_replace(
'/^@charset\s+[\'"](\S*?)\b[\'"];/i',
'', $contents);
759 $comment =
'/\*[^*]*\*+(?:[^/*][^*]*\*+)*/';
761 $double_quot =
'"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
763 $single_quot =
"'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'";
765 $contents = preg_replace(
766 "<($double_quot|$single_quot)|$comment>Ss",
774 $contents = preg_replace(
'<
775 # Strip leading and trailing whitespace.
777 # Strip only leading whitespace from:
778 # - Closing parenthesis: Retain "@media (bar) and foo".
780 # Strip only trailing whitespace from:
781 # - Opening parenthesis: Retain "@media (bar) and foo".
782 # - Colon: Retain :pseudo-selectors.
792 $contents = trim($contents);