‪TYPO3CMS  ‪main
ResourceCompressor.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
24 
30 {
34  protected ‪$targetDirectory = 'typo3temp/assets/compressed/';
35 
39  protected ‪$rootPath = '';
40 
46  protected ‪$createGzipped = false;
47 
48  protected string ‪$gzipFileExtension = '.gz';
49 
53  protected ‪$gzipCompressionLevel = -1;
54 
58  protected ‪$htaccessTemplate = '<FilesMatch "\\.(js|css)(\\.gz)?$">
59  <IfModule mod_expires.c>
60  ExpiresActive on
61  ExpiresDefault "access plus 7 days"
62  </IfModule>
63  FileETag MTime Size
64 </FilesMatch>';
65 
66  protected bool ‪$initialized = false;
67 
68  protected function ‪initialize(): void
69  {
70  if ($this->initialized) {
71  return;
72  }
73  // we check for existence of our targetDirectory
74  if (!is_dir(‪Environment::getPublicPath() . '/' . $this->targetDirectory)) {
75  ‪GeneralUtility::mkdir_deep(‪Environment::getPublicPath() . '/' . $this->targetDirectory);
76  }
77  // if enabled, we check whether we should auto-create the .htaccess file
78  if (‪$GLOBALS['TYPO3_CONF_VARS']['SYS']['generateApacheHtaccess']) {
79  // check whether .htaccess exists
80  $htaccessPath = ‪Environment::getPublicPath() . '/' . $this->targetDirectory . '.htaccess';
81  if (!file_exists($htaccessPath)) {
82  ‪GeneralUtility::writeFile($htaccessPath, $this->htaccessTemplate);
83  }
84  }
85  // decide whether we should create gzipped versions or not
86  $compressionLevel = ‪$GLOBALS['TYPO3_CONF_VARS']['FE']['compressionLevel'];
87  // we need zlib for gzencode()
88  if (extension_loaded('zlib') && $compressionLevel) {
89  $this->createGzipped = true;
90  // $compressionLevel can also be TRUE
91  if (‪MathUtility::canBeInterpretedAsInteger($compressionLevel)) {
92  $this->gzipCompressionLevel = (int)$compressionLevel;
93  }
94  }
95  $this->rootPath = ‪Environment::getPublicPath() . '/';
96  $this->initialized = true;
97  }
98 
105  public function ‪concatenateCssFiles(array $cssFiles)
106  {
107  $this->‪initialize();
108  $filesToIncludeByType = ['all' => []];
109  foreach ($cssFiles as $key => $fileOptions) {
110  // no concatenation allowed for this file, so continue
111  if (!empty($fileOptions['excludeFromConcatenation'])) {
112  continue;
113  }
114  $filenameFromMainDir = $this->‪getFilenameFromMainDir($fileOptions['file']);
115  $type = isset($fileOptions['media']) ? strtolower($fileOptions['media']) : 'all';
116  if (!isset($filesToIncludeByType[$type])) {
117  $filesToIncludeByType[$type] = [];
118  }
119  if (!empty($fileOptions['forceOnTop'])) {
120  array_unshift($filesToIncludeByType[$type], $filenameFromMainDir);
121  } else {
122  $filesToIncludeByType[$type][] = $filenameFromMainDir;
123  }
124  // remove the file from the incoming file array
125  unset($cssFiles[$key]);
126  }
127  foreach ($filesToIncludeByType as $mediaOption => $filesToInclude) {
128  if (empty($filesToInclude)) {
129  continue;
130  }
131  $targetFile = $this->‪createMergedCssFile($filesToInclude);
132  $concatenatedOptions = [
133  'file' => $targetFile,
134  'rel' => 'stylesheet',
135  'media' => $mediaOption,
136  'compress' => true,
137  'excludeFromConcatenation' => true,
138  'forceOnTop' => false,
139  'allWrap' => '',
140  ];
141  // place the merged stylesheet on top of the stylesheets
142  $cssFiles = array_merge($cssFiles, [$targetFile => $concatenatedOptions]);
143  }
144  return $cssFiles;
145  }
146 
153  public function ‪concatenateJsFiles(array $jsFiles)
154  {
155  $this->‪initialize();
156  $concatenatedJsFileIsAsync = false;
157  $allFilesToConcatenateAreAsync = true;
158  $filesToInclude = [];
159  foreach ($jsFiles as $key => $fileOptions) {
160  // invalid section found or no concatenation allowed, so continue
161  if (empty($fileOptions['section']) || !empty($fileOptions['excludeFromConcatenation']) || !empty($fileOptions['nomodule']) || !empty($fileOptions['defer'])) {
162  continue;
163  }
164  if (!isset($filesToInclude[$fileOptions['section']])) {
165  $filesToInclude[$fileOptions['section']] = [];
166  }
167  $filenameFromMainDir = $this->‪getFilenameFromMainDir($fileOptions['file']);
168  if (!empty($fileOptions['forceOnTop'])) {
169  array_unshift($filesToInclude[$fileOptions['section']], $filenameFromMainDir);
170  } else {
171  $filesToInclude[$fileOptions['section']][] = $filenameFromMainDir;
172  }
173  if ($fileOptions['async'] ?? false) {
174  $concatenatedJsFileIsAsync = true;
175  } else {
176  $allFilesToConcatenateAreAsync = false;
177  }
178  // remove the file from the incoming file array
179  unset($jsFiles[$key]);
180  }
181  if (!empty($filesToInclude)) {
182  $defaultTypeAttributeForJavaScript = $this->‪getJavaScriptFileType();
183  foreach ($filesToInclude as $section => $files) {
184  $targetFile = $this->‪createMergedJsFile($files);
185  $concatenatedOptions = [
186  'file' => $targetFile,
187  'type' => $defaultTypeAttributeForJavaScript,
188  'section' => $section,
189  'compress' => true,
190  'excludeFromConcatenation' => true,
191  'forceOnTop' => false,
192  'allWrap' => '',
193  'async' => $concatenatedJsFileIsAsync && $allFilesToConcatenateAreAsync,
194  ];
195  // place the merged javascript on top of the JS files
196  $jsFiles = array_merge([$targetFile => $concatenatedOptions], $jsFiles);
197  }
198  }
199  return $jsFiles;
200  }
201 
208  protected function ‪createMergedCssFile(array $filesToInclude)
209  {
210  return $this->‪createMergedFile($filesToInclude, 'css');
211  }
212 
219  protected function ‪createMergedJsFile(array $filesToInclude)
220  {
221  return $this->‪createMergedFile($filesToInclude, 'js');
222  }
223 
233  protected function ‪createMergedFile(array $filesToInclude, $type = 'css')
234  {
235  // Get file type
236  $type = strtolower(trim($type, '. '));
237  if (empty($type)) {
238  throw new \InvalidArgumentException('No valid file type given for files to be merged.', 1308957498);
239  }
240  // we add up the filenames, filemtimes and filesizes to later build a checksum over
241  // it and include it in the temporary file name
242  $unique = '';
243  foreach ($filesToInclude as $key => $filename) {
244  if (‪GeneralUtility::isValidUrl($filename)) {
245  // check if it is possibly a local file with fully qualified URL
246  if (‪GeneralUtility::isOnCurrentHost($filename) &&
247  str_starts_with(
248  $filename,
249  ‪$GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams')->getSiteUrl()
250  )
251  ) {
252  // attempt to turn it into a local file path
253  $localFilename = substr($filename, strlen(‪$GLOBALS['TYPO3_REQUEST']->getAttribute('normalizedParams')->getSiteUrl()));
254  if (@is_file(GeneralUtility::resolveBackPath($this->rootPath . $localFilename))) {
255  $filesToInclude[$key] = $localFilename;
256  } else {
257  $filesToInclude[$key] = $this->‪retrieveExternalFile($filename);
258  }
259  } else {
260  $filesToInclude[$key] = $this->‪retrieveExternalFile($filename);
261  }
262  $filename = $filesToInclude[$key];
263  }
264  $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $filename);
265  if (@file_exists($filenameAbsolute)) {
266  $fileStatus = stat($filenameAbsolute);
267  $unique .= $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size'];
268  } else {
269  $unique .= $filenameAbsolute;
270  }
271  }
272  $targetFile = $this->targetDirectory . 'merged-' . md5($unique) . '.' . $type;
273  // if the file doesn't already exist, we create it
274  if (!file_exists(‪Environment::getPublicPath() . '/' . $targetFile)) {
275  $concatenated = '';
276  // concatenate all the files together
277  foreach ($filesToInclude as $filename) {
278  $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $filename);
279  $filename = ‪PathUtility::stripPathSitePrefix($filenameAbsolute);
280  $contents = (string)file_get_contents($filenameAbsolute);
281  // remove any UTF-8 byte order mark (BOM) from files
282  if (str_starts_with($contents, "\xEF\xBB\xBF")) {
283  $contents = substr($contents, 3);
284  }
285  // only fix paths if files aren't already in typo3temp (already processed)
286  if ($type === 'css' && !str_starts_with($filename, $this->targetDirectory)) {
287  $contents = $this->‪cssFixRelativeUrlPaths($contents, $filename);
288  }
289  $concatenated .= LF . $contents;
290  }
291  // move @charset, @import and @namespace statements to top of new file
292  if ($type === 'css') {
293  $concatenated = $this->‪cssFixStatements($concatenated);
294  }
295  ‪GeneralUtility::writeFile(‪Environment::getPublicPath() . '/' . $targetFile, $concatenated);
296  }
297  return $targetFile;
298  }
299 
306  public function ‪compressCssFiles(array $cssFiles)
307  {
308  $this->‪initialize();
309  $filesAfterCompression = [];
310  foreach ($cssFiles as $key => $fileOptions) {
311  // if compression is enabled
312  if ($fileOptions['compress']) {
313  $filename = $this->‪compressCssFile($fileOptions['file']);
314  $fileOptions['compress'] = false;
315  $fileOptions['file'] = $filename;
316  $filesAfterCompression[$filename] = $fileOptions;
317  } else {
318  $filesAfterCompression[$key] = $fileOptions;
319  }
320  }
321  return $filesAfterCompression;
322  }
323 
336  public function ‪compressCssFile($filename)
337  {
338  $this->‪initialize();
339  // generate the unique name of the file
340  $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $this->‪getFilenameFromMainDir($filename));
341  if (@file_exists($filenameAbsolute)) {
342  $fileStatus = stat($filenameAbsolute);
343  $unique = $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size'];
344  } else {
345  $unique = $filenameAbsolute;
346  }
347  // make sure it is again the full filename
348  $filename = ‪PathUtility::stripPathSitePrefix($filenameAbsolute);
349 
350  $pathinfo = ‪PathUtility::pathinfo($filenameAbsolute);
351  $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.css';
352  // only create it, if it doesn't exist, yet
353  if (!file_exists(‪Environment::getPublicPath() . '/' . $targetFile) || $this->createGzipped && !file_exists(‪Environment::getPublicPath() . '/' . $targetFile . $this->gzipFileExtension)) {
354  $contents = $this->‪compressCssString((string)file_get_contents($filenameAbsolute));
355  if (!str_contains($filename, $this->targetDirectory)) {
356  $contents = $this->‪cssFixRelativeUrlPaths($contents, $filename);
357  }
358  $this->‪writeFileAndCompressed($targetFile, $contents);
359  }
360  return $this->‪returnFileReference($targetFile);
361  }
362 
369  public function ‪compressJsFiles(array $jsFiles)
370  {
371  $this->‪initialize();
372  $filesAfterCompression = [];
373  foreach ($jsFiles as $fileName => $fileOptions) {
374  // If compression is enabled
375  if ($fileOptions['compress']) {
376  $compressedFilename = $this->‪compressJsFile($fileOptions['file']);
377  $fileOptions['compress'] = false;
378  $fileOptions['file'] = $compressedFilename;
379  $filesAfterCompression[$compressedFilename] = $fileOptions;
380  } else {
381  $filesAfterCompression[$fileName] = $fileOptions;
382  }
383  }
384  return $filesAfterCompression;
385  }
386 
393  public function ‪compressJsFile($filename)
394  {
395  $this->‪initialize();
396  // generate the unique name of the file
397  $filenameAbsolute = GeneralUtility::resolveBackPath($this->rootPath . $this->‪getFilenameFromMainDir($filename));
398  if (@file_exists($filenameAbsolute)) {
399  $fileStatus = stat($filenameAbsolute);
400  $unique = $filenameAbsolute . $fileStatus['mtime'] . $fileStatus['size'];
401  } else {
402  $unique = $filenameAbsolute;
403  }
404  $pathinfo = ‪PathUtility::pathinfo($filename);
405  $targetFile = $this->targetDirectory . $pathinfo['filename'] . '-' . md5($unique) . '.js';
406  // only create it, if it doesn't exist, yet
407  if (!file_exists(‪Environment::getPublicPath() . '/' . $targetFile) || $this->createGzipped && !file_exists(‪Environment::getPublicPath() . '/' . $targetFile . $this->gzipFileExtension)) {
408  $contents = (string)file_get_contents($filenameAbsolute);
409  $this->‪writeFileAndCompressed($targetFile, $contents);
410  }
411  return $this->‪returnFileReference($targetFile);
412  }
413 
420  protected function ‪getFilenameFromMainDir($filename)
421  {
422  /*
423  * The various paths may have those values (e.g. if TYPO3 is installed in a subdir)
424  * - docRoot = /var/www/html/
425  * - Environment::getPublicPath() = /var/www/html/sites/site1/
426  * - $this->rootPath = /var/www/html/sites/site1/typo3
427  *
428  * The file names passed into this function may be either:
429  * - relative to $this->rootPath
430  * - relative to Environment::getPublicPath()
431  * - relative to docRoot
432  */
433  $docRoot = GeneralUtility::getIndpEnv('TYPO3_DOCUMENT_ROOT');
434  $fileNameWithoutSlash = ltrim($filename, '/');
435 
436  // if the file is an absolute reference within the docRoot
437  $absolutePath = $docRoot . '/' . $fileNameWithoutSlash;
438  // If the $filename stems from a call to PathUtility::getAbsoluteWebPath() it has a leading slash,
439  // hence isAbsolutePath() results in true, which is obviously wrong. Check file existence to be sure.
440  // Calling is_file without @ for a path starting with '../' causes a PHP Warning when using open_basedir restriction
441  if (‪PathUtility::isAbsolutePath($filename) && @is_file($filename)) {
442  $absolutePath = $filename;
443  }
444  if (@is_file($absolutePath)) {
445  $absolutePath = ‪Environment::getPublicPath() . '/' . ‪PathUtility::getAbsoluteWebPath($absolutePath, false);
446  if (str_starts_with($absolutePath, $this->rootPath)) {
447  // the path is within the current root path, simply strip rootPath off
448  return substr($absolutePath, strlen($this->rootPath));
449  }
450  // the path is not within the root path, strip off the site path, the remaining logic below
451  // takes care about adjusting the path correctly.
452  $filename = substr($absolutePath, strlen(‪Environment::getPublicPath() . '/'));
453  }
454  // if the file exists in the root path, just return the $filename
455  if (is_file($this->rootPath . $fileNameWithoutSlash)) {
456  return $fileNameWithoutSlash;
457  }
458  // build the file path relative to the public web path
459  if (‪PathUtility::isExtensionPath($filename)) {
461  } else {
462  $file = ‪Environment::getPublicPath() . '/' . $filename;
463  }
464 
465  // check if the file exists, and if so, return the path relative to current PHP script
466  if (is_file($file)) {
467  return rtrim((string)‪PathUtility::getRelativePathTo($file), '/');
468  }
469  // none of above conditions were met, fallback to default behaviour
470  return $filename;
471  }
472 
480  protected function ‪checkBaseDirectory($filename, array $baseDirectories)
481  {
482  foreach ($baseDirectories as ‪$baseDirectory) {
483  // check, if $filename starts with base directory
484  if (str_starts_with($filename, ‪$baseDirectory)) {
485  return true;
486  }
487  }
488  return false;
489  }
490 
491  protected function ‪cssFixRelativeUrlPaths(string $contents, string $filename): string
492  {
493  $newDir = '../../../' . ‪PathUtility::dirname($filename) . '/';
494  return $this->‪getPathFixer()->fixRelativeUrlPaths($contents, $newDir);
495  }
496 
504  protected function ‪cssFixStatements($contents)
505  {
506  $matches = [];
507  $comment = LF . '/* moved by compressor */' . LF;
508  // nothing to do, so just return contents
509  if (stripos($contents, '@charset') === false && stripos($contents, '@import') === false && stripos($contents, '@namespace') === false) {
510  return $contents;
511  }
512  $regex = '/@(charset|import|namespace)\\s*(url)?\\s*\\(?\\s*["\']?[^"\'\\)]+["\']?\\s*\\)?\\s*;/i';
513  preg_match_all($regex, $contents, $matches);
514  if (!empty($matches[0])) {
515  // Ensure correct order of @charset, @namespace and @import
516  $charset = '';
517  $namespaces = [];
518  $imports = [];
519  foreach ($matches[1] as $index => $keyword) {
520  switch ($keyword) {
521  case 'charset':
522  if (empty($charset)) {
523  $charset = $matches[0][$index];
524  }
525  break;
526  case 'namespace':
527  $namespaces[] = $matches[0][$index];
528  break;
529  case 'import':
530  $imports[] = $matches[0][$index];
531  break;
532  }
533  }
534 
535  $namespaces = !empty($namespaces) ? implode('', $namespaces) . $comment : '';
536  $imports = !empty($imports) ? implode('', $imports) . $comment : '';
537  // remove existing statements
538  $contents = str_replace($matches[0], '', $contents);
539  // add statements to the top of contents in the order they occur in original file
540  $contents =
541  $charset
542  . $comment
543  . $namespaces
544  . $imports
545  . trim($contents);
546  }
547  return $contents;
548  }
549 
556  protected function ‪writeFileAndCompressed($filename, $contents)
557  {
558  // write uncompressed file
559  ‪GeneralUtility::writeFile(‪Environment::getPublicPath() . '/' . $filename, $contents);
560  if ($this->createGzipped) {
561  // create compressed version
562  ‪GeneralUtility::writeFile(‪Environment::getPublicPath() . '/' . $filename . $this->gzipFileExtension, (string)gzencode($contents, $this->gzipCompressionLevel));
563  }
564  }
565 
573  protected function ‪returnFileReference($filename)
574  {
575  // if the client accepts gzip and we can create gzipped files, we give him compressed versions
576  if ($this->createGzipped && str_contains(GeneralUtility::getIndpEnv('HTTP_ACCEPT_ENCODING'), 'gzip')) {
577  $filename .= ‪$this->gzipFileExtension;
578  }
579  return ‪PathUtility::getRelativePath($this->rootPath, ‪Environment::getPublicPath() . '/') . $filename;
580  }
581 
588  protected function ‪retrieveExternalFile(‪$url)
589  {
590  $externalContent = ‪GeneralUtility::getUrl(‪$url);
591  $filename = $this->targetDirectory . 'external-' . md5(‪$url);
592  // Write only if file does not exist OR md5 of the content is not the same as fetched one
593  if (!file_exists(‪Environment::getPublicPath() . '/' . $filename)
594  || !hash_equals(md5((string)file_get_contents(‪Environment::getPublicPath() . '/' . $filename)), md5($externalContent))
595  ) {
596  ‪GeneralUtility::writeFile(‪Environment::getPublicPath() . '/' . $filename, $externalContent);
597  }
598  return $filename;
599  }
600 
601  public function ‪compressJavaScriptSource(string $javaScriptSourceCode): string
602  {
603  $this->‪initialize();
604  $fakeThis = null;
605  foreach (‪$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_div.php']['minifyJavaScript'] ?? [] as $hookMethod) {
606  try {
607  $parameters = ['script' => $javaScriptSourceCode];
608  $javaScriptSourceCode = GeneralUtility::callUserFunction($hookMethod, $parameters, $fakeThis);
609  } catch (\Exception $e) {
610  GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__)->warning('Error minifying Javascript: {file}, hook: {hook}', [
611  'file' => $javaScriptSourceCode,
612  'hook' => $hookMethod,
613  'exception' => $e,
614  ]);
615  }
616  }
617  return $javaScriptSourceCode;
618  }
619 
626  protected function ‪compressCssString($contents)
627  {
628  // Perform some safe CSS optimizations.
629  // Regexp to match comment blocks.
630  $comment = '/\*[^*]*\*+(?:[^/*][^*]*\*+)*/';
631  // Regexp to match double quoted strings.
632  $double_quot = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"';
633  // Regexp to match single quoted strings.
634  $single_quot = "'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'";
635  // Strip all comment blocks, but keep double/single quoted strings.
636  $contents = (string)preg_replace(
637  "<($double_quot|$single_quot)|$comment>Ss",
638  '$1',
639  $contents
640  );
641  // Remove certain whitespace.
642  // There are different conditions for removing leading and trailing
643  // whitespace.
644  // @see https://php.net/manual/regexp.reference.subpatterns.php
645  $contents = (string)preg_replace(
646  '<
647  # Strip leading and trailing whitespace.
648  \s*([@{};,])\s*
649  # Strip only leading whitespace from:
650  # - Closing parenthesis: Retain "@media (bar) and foo".
651  | \s+([\‍)])
652  # Strip only trailing whitespace from:
653  # - Opening parenthesis: Retain "@media (bar) and foo".
654  # - Colon: Retain :pseudo-selectors.
655  | ([\‍(:])\s+
656  >xS',
657  // Only one of the three capturing groups will match, so its reference
658  // will contain the wanted value and the references for the
659  // two non-matching groups will be replaced with empty strings.
660  '$1$2$3',
661  $contents
662  );
663  // End the file with a new line.
664  $contents = trim($contents);
665  // Ensure file ends in newline.
666  $contents .= LF;
667  return $contents;
668  }
669 
676  protected function ‪getJavaScriptFileType(): string
677  {
678  if (!isset(‪$GLOBALS['TSFE'])
679  || !(‪$GLOBALS['TSFE'] instanceof TypoScriptFrontendController)
680  || (‪$GLOBALS['TSFE']->config['config']['doctype'] ?? 'html5') === 'html5'
681  ) {
682  // no TSFE, or doctype set to html5
683  return '';
684  }
685  return 'text/javascript';
686  }
687 
688  protected function ‪getPathFixer(): RelativeCssPathFixer
689  {
690  return GeneralUtility::makeInstance(RelativeCssPathFixer::class);
691  }
692 }
‪TYPO3\CMS\Core\Resource\ResourceCompressor\getFilenameFromMainDir
‪string getFilenameFromMainDir($filename)
Definition: ResourceCompressor.php:415
‪TYPO3\CMS\Core\Utility\PathUtility\stripPathSitePrefix
‪static stripPathSitePrefix(string $path)
Definition: PathUtility.php:428
‪TYPO3\CMS\Core\Utility\PathUtility\isExtensionPath
‪static isExtensionPath(string $path)
Definition: PathUtility.php:117
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:27
‪TYPO3\CMS\Core\Utility\PathUtility\isAbsolutePath
‪static isAbsolutePath(string $path)
Definition: PathUtility.php:286
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$targetDirectory
‪string $targetDirectory
Definition: ResourceCompressor.php:33
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressJavaScriptSource
‪compressJavaScriptSource(string $javaScriptSourceCode)
Definition: ResourceCompressor.php:596
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static getPublicPath()
Definition: Environment.php:187
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$rootPath
‪string $rootPath
Definition: ResourceCompressor.php:37
‪TYPO3\CMS\Core\Utility\PathUtility\getRelativePathTo
‪static getRelativePathTo(string $absolutePath)
Definition: PathUtility.php:33
‪$baseDirectory
‪$baseDirectory
Definition: updateIsoDatabase.php:98
‪TYPO3\CMS\Core\Resource\ResourceCompressor\cssFixRelativeUrlPaths
‪cssFixRelativeUrlPaths(string $contents, string $filename)
Definition: ResourceCompressor.php:486
‪TYPO3\CMS\Core\Resource\ResourceCompressor
Definition: ResourceCompressor.php:30
‪TYPO3\CMS\Core\Resource\ResourceCompressor\retrieveExternalFile
‪string retrieveExternalFile($url)
Definition: ResourceCompressor.php:583
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$htaccessTemplate
‪string $htaccessTemplate
Definition: ResourceCompressor.php:53
‪TYPO3\CMS\Core\Resource\ResourceCompressor\createMergedJsFile
‪mixed createMergedJsFile(array $filesToInclude)
Definition: ResourceCompressor.php:214
‪TYPO3\CMS\Core\Resource\ResourceCompressor\createMergedCssFile
‪mixed createMergedCssFile(array $filesToInclude)
Definition: ResourceCompressor.php:203
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$createGzipped
‪bool $createGzipped
Definition: ResourceCompressor.php:43
‪TYPO3\CMS\Core\Resource\ResourceCompressor\cssFixStatements
‪string cssFixStatements($contents)
Definition: ResourceCompressor.php:499
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressCssFiles
‪array compressCssFiles(array $cssFiles)
Definition: ResourceCompressor.php:301
‪TYPO3\CMS\Core\Utility\PathUtility\getAbsoluteWebPath
‪static string getAbsoluteWebPath(string $targetPath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:52
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Core\Utility\PathUtility\dirname
‪static dirname(string $path)
Definition: PathUtility.php:243
‪TYPO3\CMS\Core\Resource\ResourceCompressor\returnFileReference
‪string returnFileReference($filename)
Definition: ResourceCompressor.php:568
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$gzipFileExtension
‪string $gzipFileExtension
Definition: ResourceCompressor.php:45
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressJsFile
‪string compressJsFile($filename)
Definition: ResourceCompressor.php:388
‪TYPO3\CMS\Core\Utility\PathUtility\getPublicResourceWebPath
‪static getPublicResourceWebPath(string $resourcePath, bool $prefixWithSitePath=true)
Definition: PathUtility.php:97
‪TYPO3\CMS\Core\Utility\GeneralUtility\getUrl
‪static string false getUrl(string $url)
Definition: GeneralUtility.php:1427
‪TYPO3\CMS\Core\Utility\GeneralUtility\mkdir_deep
‪static mkdir_deep($directory)
Definition: GeneralUtility.php:1638
‪TYPO3\CMS\Core\Resource\ResourceCompressor\getPathFixer
‪getPathFixer()
Definition: ResourceCompressor.php:683
‪TYPO3\CMS\Core\Utility\PathUtility\getRelativePath
‪static getRelativePath(string $sourcePath, string $targetPath)
Definition: PathUtility.php:129
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$initialized
‪bool $initialized
Definition: ResourceCompressor.php:61
‪TYPO3\CMS\Core\Resource\ResourceCompressor\concatenateCssFiles
‪array concatenateCssFiles(array $cssFiles)
Definition: ResourceCompressor.php:100
‪TYPO3\CMS\Core\Resource\ResourceCompressor\writeFileAndCompressed
‪writeFileAndCompressed($filename, $contents)
Definition: ResourceCompressor.php:551
‪TYPO3\CMS\Core\Resource
Definition: generateMimeTypes.php:52
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:22
‪TYPO3\CMS\Webhooks\Message\$url
‪identifier readonly UriInterface $url
Definition: LoginErrorOccurredMessage.php:36
‪TYPO3\CMS\Core\Resource\ResourceCompressor\getJavaScriptFileType
‪getJavaScriptFileType()
Definition: ResourceCompressor.php:671
‪TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
Definition: TypoScriptFrontendController.php:102
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Log\LogManager
Definition: LogManager.php:33
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:41
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressCssFile
‪string compressCssFile($filename)
Definition: ResourceCompressor.php:331
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Core\Utility\GeneralUtility\isValidUrl
‪static bool isValidUrl(string $url)
Definition: GeneralUtility.php:691
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressCssString
‪string compressCssString($contents)
Definition: ResourceCompressor.php:621
‪TYPO3\CMS\Core\Resource\ResourceCompressor\createMergedFile
‪mixed createMergedFile(array $filesToInclude, $type='css')
Definition: ResourceCompressor.php:228
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:51
‪TYPO3\CMS\Core\Resource\ResourceCompressor\compressJsFiles
‪array compressJsFiles(array $jsFiles)
Definition: ResourceCompressor.php:364
‪TYPO3\CMS\Core\Resource\ResourceCompressor\checkBaseDirectory
‪bool checkBaseDirectory($filename, array $baseDirectories)
Definition: ResourceCompressor.php:475
‪TYPO3\CMS\Core\Resource\ResourceCompressor\$gzipCompressionLevel
‪int $gzipCompressionLevel
Definition: ResourceCompressor.php:49
‪TYPO3\CMS\Core\Utility\GeneralUtility\writeFile
‪static bool writeFile($file, $content, $changePermissions=false)
Definition: GeneralUtility.php:1452
‪TYPO3\CMS\Core\Resource\ResourceCompressor\initialize
‪initialize()
Definition: ResourceCompressor.php:63
‪TYPO3\CMS\Core\Utility\GeneralUtility\isOnCurrentHost
‪static bool isOnCurrentHost(string $url)
Definition: GeneralUtility.php:410
‪TYPO3\CMS\Core\Utility\PathUtility\pathinfo
‪static string string[] pathinfo(string $path, int $options=PATHINFO_ALL)
Definition: PathUtility.php:270
‪TYPO3\CMS\Core\Resource\ResourceCompressor\concatenateJsFiles
‪array concatenateJsFiles(array $jsFiles)
Definition: ResourceCompressor.php:148
‪TYPO3\CMS\Core\Resource\RelativeCssPathFixer
Definition: RelativeCssPathFixer.php:29