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