Project

General

Profile

Actions

Bug #79572

closed

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

Added by René Rossi almost 8 years ago. Updated 4 months ago.

Status:
Closed
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:
11
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


Files

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

Updated by René Rossi almost 8 years ago

  • Assignee set to Benni Mack
Actions #2

Updated by Riccardo De Contardi over 6 years 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')

Actions #3

Updated by Riccardo De Contardi over 6 years ago

  • Assignee deleted (Benni Mack)
Actions #4

Updated by Markus Klein over 6 years 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()".

Actions #5

Updated by Markus Klein over 6 years 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
Actions #6

Updated by René Rossi over 6 years 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;
    }
}
Actions #7

Updated by Markus Timtner over 5 years 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)

Actions #8

Updated by Markus Klein over 5 years 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.

Actions #9

Updated by René Rossi over 5 years 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.

Actions #10

Updated by Ge Rie over 2 years ago

  • TYPO3 Version changed from 9 to 11

Markus Timtner wrote in #note-7:

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

[...]

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

This is still a problem in TYPO3 11.
The output from something like this:

clip-path: url(#c1); 

Is translated to:

clip-path: url('../../../typo3conf/ext/myextension/Resources/Public/css/#c1');

So inline SVG can't be used. It works when you link to a svg file though

clip-path: url(/typo3conf/ext/myextension/Resources/Public/svg/imageclipform.svg#c1);
Actions #11

Updated by Thomas Helmrich about 2 years ago

hi,

there is an check in RelativeCssPathFixer.php:71 that seems like it should prevent this issue.

// we must not rewrite paths containing ":" or "url(", e.g. data URIs (see RFC 2397)
if (!str_contains($match, ':') && !preg_match('/url\\s*\\(/i', $match)) {

I did some debugging, in case of background: url("data:image/... fill='url('%23a')'... the $match is just %23a, so it proceeds with 'fixing' to a relative path.

Actions #12

Updated by Timo Klinge over 1 year ago

Hi,

I encountered the same problem, when I implemented an inline-svg-filter on our website.

filter: url(#rounded-box-filter);
<svg style="visibility: hidden; position: absolute;" width="0" height="0">
    <defs>
        <filter id="rounded-box-filter">
            ...
        </filter>
    </defs>
</svg>

While everything worked on our test- and staging-server, on the liveserver the URL was converted from url(#rounded-box-filter) to url(../../../typo3conf/ext/{package}/Resources/Public/CSS/#rounded-box-filter).

It turned out that the problem only occurs when concatenateCss = 1 or compressCss = 1 is set.

My workaround was to use a Typo3-AssetCollector directly in the html-file instead. For me it is not clear why this bug is still existent in Typo3-v11.

<f:asset.css identifier="rounded-box-style" priority="true">
    ...
    filter: url(#rounded-box-filter);
    ...
</f:asset.css>
Actions #13

Updated by Garvin Hicking 4 months ago

  • Status changed from Accepted to Closed

Following along the reason to close #75127 I would like to ask if you agree that we could close this issue, too.

Todays recommendation is to try to not rely on compression/concatenation through these TypoScript options, but either use distinct bundlers or rely on HTTP/2 multiplexing. There are several edge-case scenarios at play here, which did not really gain traction to be fixed in the many years now, so it's unlikely moving forward this would change.

I hope you can understand the reasoning of this and an team discussion about this and agree. If not, please let me know and we'll see how to proceed with this. :-)

Actions

Also available in: Atom PDF