Skip to content

Conversation

@8ctopus
Copy link
Contributor

@8ctopus 8ctopus commented Dec 25, 2025

Add draft to attempt to resolve #1443

There are no specific tests yet, and there are improvements that can be made, I just want to get your approval before I polish things up.

@coveralls
Copy link

coveralls commented Dec 25, 2025

Coverage Status

coverage: 70.775% (+0.3%) from 70.514%
when pulling 90d1602 on 8ctopus:css-string-escaping
into 2b61cd5 on MyIntervals:main.

Copy link
Collaborator

@JakeQZ JakeQZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be significantly slower looping through the string rather than using the built-in function (particularly as some strings may be base64-encoded images). Also this is reimplementing some of what addslashes() does.

Wouldn't it be simpler (and more efficient) to use addslashes() as before, then do a str_replace() to replace \' with ' or \" with " depending on the string quoting type?

@JakeQZ
Copy link
Collaborator

JakeQZ commented Dec 30, 2025

Wouldn't it be simpler (and more efficient) to use addslashes() as before, then do a str_replace() to replace \' with ' or \" with " depending on the string quoting type?

PS. I agree with adding a separate method to do this.

@8ctopus
Copy link
Contributor Author

8ctopus commented Jan 7, 2026

Updated according to your feedback.

@oliverklee
Copy link
Collaborator

@8ctopus Thanks! Could you please rebase?

@8ctopus 8ctopus force-pushed the css-string-escaping branch from 2a66812 to 47970ab Compare January 7, 2026 08:52
@8ctopus
Copy link
Contributor Author

8ctopus commented Jan 7, 2026

done

@oliverklee
Copy link
Collaborator

Thanks! GitHub is still showing merge conflicts. Could you please have a look?

@8ctopus 8ctopus force-pushed the css-string-escaping branch from 47970ab to 676dd8c Compare January 7, 2026 10:27
@8ctopus
Copy link
Contributor Author

8ctopus commented Jan 7, 2026

now should be good.

@oliverklee
Copy link
Collaborator

Thanks! Now GitHub was able to run the CI jobs.

The PHP-CS-Fixer job suggests some improvements. Could you please apply those to get the build green? Thanks!

@8ctopus
Copy link
Contributor Author

8ctopus commented Jan 8, 2026

This time all tests are green, I also added a test to check that we do not escape when not necessary.

@oliverklee
Copy link
Collaborator

Thanks!

Copy link
Collaborator

@JakeQZ JakeQZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks generally good now.

However, looking at the tests, there don't seem to be any covering that double-quotes within a single-quoted string are no longer escaped, e.g. if string quoting type is ', the quotes in "Hello World" don't need escaping and the result should be '"Hello World"'. Could you add a test for that?

I've suggested a couple of improvements, and a further correction to a comment that was previously wrong.

I'm not sure whether we have a project preference for string concatenation vs interpolation, so am asking @oliverklee for comment...

Comment on lines +117 to +121
$input = "data:image/svg+xml,%3Csvg width='24' height='24' viewBox='0 0 24 24' fill='none'" .
" xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd'" .
" d='M14.3145 2 3V11.9987H17.5687L18 8.20761H14.3145L14.32 6.31012C14.32 5.32134 14.4207" .
' 4.79153 15.9426 4.79153H17.977V1H14.7223C10.8129 1 9.43687 2.83909 9.43687 ' .
" 5.93187V8.20804H7V11.9991H9.43687V23H14.3145Z' fill='black'/%3E%3C/svg%3E%0A";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Autoformatting may apply some indentation, but I suggest leaving it as is for now. @oliverklee can run the autoformatter he uses as a post-PR (I think it's part of PHPStorm, which I don't have, and even if you have it, you may not have the same configuration set-up).


$outputFormat = OutputFormat::createPretty();

self::assertSame("\"{$input}\"", (new CSSString($input))->render($outputFormat));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are generally favouring using string contactenation rather than string interpolation, but I'm not sure of the rationale. All I can gather from some threads on StackOverflow is that it is a matter of personal preference. @oliverklee, are you able to expand on this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you regex the project with /\{\$.*\}/ you will see that interpolation is used 19 times, 4 times being my newly added code.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for new code, please use string concatenation instead of interpolation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for new code, please use string concatenation instead of interpolation.

I've opened #1464, because I'm not sure that's best.

Apologies for the conflicting reviewer requests.

I'd be happy to merge with string interpolation for now. We can revisit this later pending the outcome of that discussion.

@oliverklee, would you be happy to merge this with the strings as are, pending further revisitation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'd be fine to keep the string interpolation when we merge this PR. I'd still like to get rid of the addslash-first-and-then-partially-undo part, though.


$expected = str_replace("'", "\\'", $input);

self::assertSame("'{$expected}'", (new CSSString($input))->render($outputFormat));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

@JakeQZ JakeQZ requested a review from oliverklee January 9, 2026 00:36
@8ctopus
Copy link
Contributor Author

8ctopus commented Jan 9, 2026

However, looking at the tests, there don't seem to be any covering that double-quotes within a single-quoted string are no longer escaped, e.g. if string quoting type is ', the quotes in "Hello World" don't need escaping and the result should be '"Hello World"'. Could you add a test for that?

done

@oliverklee
Copy link
Collaborator

oliverklee commented Jan 9, 2026

I'm not sure whether we have a project preference for string concatenation vs interpolation,

For new/updated code, we prefer string concatenation over interpolation (without having a hard-and-fast rule, though).

@oliverklee oliverklee changed the title Do not escape characters that do not need escaping in CSS string [BUGFIX] Do not escape characters that do not need escaping in CSS string Jan 9, 2026

private function escape(string $string, string $quote): string
{
$string = \addslashes($string);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of first escaping unnecessarily and then undoing part of the work, I'd prefer to only escape what we need to escape in the first place, i.e., directly use str_replace and avoid addslashes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggested the current approach in my original review - see #1444 (review)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm … couldn't we use just the str_replace and skip the addslashes (without using a loop)?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

… or use addcslashes and provide the characters to escape?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably use addcslashes to escape the backslash and quote.

The only other character that addslashes escapes is the null character (U+0000), which I don't think we need to worry about (there are no tests for this, it is highly unlikely to be used in the real world, and it was probably just an inconsequential side-effect of addslashes that that would be the behaviour - other control characters aren't handled, apart from newline which is currently str_replaced separately by the calling method).

Perhaps we could move the str_replace for newline to the new method as part of this change.


$outputFormat = OutputFormat::createPretty();

self::assertSame("\"{$input}\"", (new CSSString($input))->render($outputFormat));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, for new code, please use string concatenation instead of interpolation.

Copy link
Collaborator

@JakeQZ JakeQZ left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the tests, there don't seem to be any covering that double-quotes within a single-quoted string are no longer escaped

done

Thanks for your perseverence <3

I've made a suggestion for what the additional test should cover (to be consistent with the first test for single quotes), and for the test method naming. (The comments appear in order of writing in the Conversation tab, and should be read in that order, which is not in the order of the code. Hope that makes sense and they make sense.)

The code change suggested includes avoiding string interpolation in the one instance covered, though that would still need to resolved in the other three instances as per @oliverklee's comments.

Comment on lines +139 to +145
$outputFormat = OutputFormat::createPretty();

$input = "'Hello World'";

self::assertSame("\"{$input}\"", (new CSSString($input))->render($outputFormat));

$input = '"Hello World"';
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first test checks that single quote (') is escaped when it needs to be but not when it doesn't.

I'd suggest the second test does likewise for double quote ("), i.e. focuses only on the double quote and includes confirmation that it is still escaped when it needs to be:

Suggested change
$outputFormat = OutputFormat::createPretty();
$input = "'Hello World'";
self::assertSame("\"{$input}\"", (new CSSString($input))->render($outputFormat));
$input = '"Hello World"';
$input = '"Hello World"';
$outputFormat = OutputFormat::createPretty();
self::assertSame('"\\"Hello World\\""', (new CSSString($input))->render($outputFormat));

/**
* @test
*/
public function doesNotEscapeCharactersThatDoNotNeedToBeEscaped2(): void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now there are two test methods, rather than appending the number 2 to the name of the second, they could be renamed to indicate their character speciality:

Suggested change
public function doesNotEscapeCharactersThatDoNotNeedToBeEscaped2(): void
public function doesNotEscapeDoubleQuotesThatDoNotNeedToBeEscaped(): void

/**
* @test
*/
public function doesNotEscapeCharactersThatDoNotNeedToBeEscaped(): void
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and

Suggested change
public function doesNotEscapeCharactersThatDoNotNeedToBeEscaped(): void
public function doesNotEscapeSingleQuotesThatDoNotNeedToBeEscaped(): void

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

escaping data:image when not required

4 participants