Bug #79572

Fix relative URL Path in CSS may fail if svg data inside url()

Added by René Rossi over 2 years ago. Updated 4 months ago.

Status:
Accepted
Priority:
Must have
Assignee:
-
Category:
Backend API
Target version:
-
Start date:
2017-01-31
Due date:
% Done:

0%

Estimated time:
1.00 h
TYPO3 Version:
9
PHP Version:
Tags:
compressor, data,
Complexity:
medium
Is Regression:
No
Sprint Focus:

Description

Hi,

if there is some SVG Date inside of an background the regexp in line 631 on ResourceCompressor.php seems to fail.

So if there are some thing like:

background-image:url("data:image/svg+xml;charset=utf8,%3Csvg
width='396' height='348' viewBox='0 0 396 348'
xmlns='http://www.w3.org/2000/svg'
xmlns:xlink='http://www.w3.org/1999/xlink'%3E%3Csvg
id='application_avi' data-name='Layer 1' viewBox='0 0 48 48'
width='48' height='48' x='348'
y='144'%3E%3Cdefs%3E%3Cstyle%3E.aacls-1%7Bfill:none%7D.aacls-2%7Bclip-path:url('%23aaclip-path')%7D.aacls-3%7Bfill:%23f6f6f6%7D.aacls-4%7Bfill:%23e0e0e0%7D.aacls-5%7Bclip-path:url('%23aaclip-path-2')%7D.aacls-6%7Bfill:%234c8fc3%7D.aacls-7%7Bclip-path:url('%23aaclip-path-3')");

the regular expression only returns the inner urls and prepends them.
compare here http://www.phpliveregex.com/p/iLr

i think something like this should work better here: http://www.phpliveregex.com/p/iMl

test.css View (393 Bytes) Riccardo De Contardi, 2018-07-21 21:46

History

#1 Updated by René Rossi over 2 years ago

  • Assignee set to Benni Mack

#2 Updated by Riccardo De Contardi about 1 year ago

This issue is still present in 9.4-dev (latest master);

My test procedure:

- include the css attached in TS Setup:

page.includeCSS{
 file1 = fileadmin/test.css
}

Results:

1) with


config{
 config.concatenateCss = 0
 config.compressCss = 0
}

the svg background is visible

2) Using either config.concatenateCss = 1 or config.compressCss = 1 the background svg is altered in this way and becomes invisible:

data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><linearGradient id='gradient'><stop offset='10%' stop-color='%23F00'/><stop offset='90%' stop-color='%23fcc'/> </linearGradient><rect fill='url('../../../fileadmin/%23gradient')' x='0' y='0' width='100%' height='100%'/></svg>

the problem is the "transformation" of url('../../../fileadmin/%23gradient')

#3 Updated by Riccardo De Contardi about 1 year ago

  • Assignee deleted (Benni Mack)

#4 Updated by Markus Klein about 1 year ago

The suggested regex is way too greedy.

The current regex /url(\\(\\s*["']?(?!\\/)([^"']+)["']?\\s*\\))/iU is tailored to detect non-absolute paths.

It has never been constructed for data-values and even less for "recursive" usage of "url()".

#5 Updated by Markus Klein about 1 year ago

  • Category changed from Caching to Backend API
  • Status changed from New to Accepted
  • Priority changed from Must have to Should have
  • Complexity set to medium

#6 Updated by René Rossi about 1 year ago

Sure it´s to greedy?

i think it is applied to the data url only.

At the moment i use this little override to fix the problem.

class ResourceCompressor extends \TYPO3\CMS\Core\Resource\ResourceCompressor {

    /**
     * PIX: Fixes the relative paths inside of url() references in CSS files
     * respecting inner data of url()
     * 
     * @author René Rossi<rossi@pixelproduction.de>
     * @param string $contents Data to process
     * @param string $oldDir Directory of the original file, relative to TYPO3_mainDir
     * @return string Processed data
     */
    protected function cssFixRelativeUrlPaths($contents, $oldDir)
    {
        $mainDir = TYPO3_MODE === 'BE' ? TYPO3_mainDir : '';
        $newDir = '../../' . $mainDir . $oldDir;
        // Replace "url()" paths
        if (stripos($contents, 'url') !== false) {
            $regex = "/[\s:]?url\(\s*([\"']?(.*)[\"']?)\s*\)/i";
            $contents = $this->findAndReplaceUrlPathsByRegex($contents, $regex, $newDir, '(\'|\')');
        }
        // Replace "@import" paths
        if (stripos($contents, '@import') !== false) {
            $regex = '/@import\\s*(["\']?(?!\\/)([^"\']+)["\']?)/i';
            $contents = $this->findAndReplaceUrlPathsByRegex($contents, $regex, $newDir, '"|"');
        }

        return $contents;
    }
}

#7 Updated by Markus Timtner 4 months ago

  • Priority changed from Should have to Must have
  • Estimated time set to 1.00 h
  • TYPO3 Version changed from 7 to 9

THe problem ist still present in v9.5.5,
it also affects inline anchors in the clip-path property like:

.clip-me { 
  /* referencing path from an inline SVG <clipPath> */
  clip-path: url(#c1); 
}

(see https://css-tricks.com/almanac/properties/c/clip/ for details)

#8 Updated by Markus Klein 4 months ago

René Rossi wrote:

Sure it´s to greedy?

i think it is applied to the data url only.

At the moment i use this little override to fix the problem.

[...]

The regex is applied on the complete CSS content. So you dot-star in the middle is the greedy point, where the regex extends way beyond its scope.
One example: Try this single line with your regex background-image: url("https://mdn.mozillademos.org/files/11991/startransparent.gif"),url("https://mdn.mozillademos.org/files/7693/catfront.png");
The regex swallows the second url() of course.

#9 Updated by René Rossi 4 months ago

Markus Klein wrote:

René Rossi wrote:

Sure it´s to greedy?

i think it is applied to the data url only.

At the moment i use this little override to fix the problem.

[...]

The regex is applied on the complete CSS content. So you dot-star in the middle is the greedy point, where the regex extends way beyond its scope.
One example: Try this single line with your regex background-image: url("https://mdn.mozillademos.org/files/11991/startransparent.gif"),url("https://mdn.mozillademos.org/files/7693/catfront.png");
The regex swallows the second url() of course.

Wow, this bug report is over 2 years old and original applied to T3 V7.6.

Im sure the provided solution is not the optimal solution at all, but...

Your example above does'nt work with the current expression also, as only the first url seems to be noticed.
array(3
0 => url("https://mdn.mozillademos.org/files/11991/startransparent.gif")
1 => ("https://mdn.mozillademos.org/files/11991/startransparent.gif")
2 => https://mdn.mozillademos.org/files/11991/startransparent.gif
)

But i'm sure you be able to replace the .* by a [^\)]+ to get the same as before but that does'nt fit to the whole needs.

If I had the time to solve this problem with all its variants, then I would have done it.

So it's a bug report to (may be the author of the functionality) to see what we get.

And one more, the last question is'nt initiated by me.

Also available in: Atom PDF