Preserve whitespace between concurent HTML elements in raw markup - php

I need to render raw HTML on page using twig. Issue that I'm having is that when I have two concurrent HTML element separated by white-space, that white-space gets removed.
How can I preserve that space?
I'm rendering HTML string as so:
{{ set _html = entity.html }}
{{ _html|raw }}
For example:
<p>start <span class="some-class">one</span> <span class="some-class">two</span> stop</p>
Is rendered as:
<p>start <span class="some-class">one</span><span class="some-class">two</span> stop</p>
I'm sure that twig raw function is sanitizing my data and therefore my issue.
How I see it:

As cale_b recommended, I will be using following CSS hack to add a space before element that lacks my spacing:
.monograph {
* + span:before {
content: ' ';
}
}

As answered in here and also in my case, the issue was that I had a {% spaceless %} tag that wrapped my content. So |raw was working correctly but it was the spaceless tag that was stripping the spaces.

Related

HTML Entities in Symfony Twig

I´m currently working on a code review of a friend and I found an XSS-Vulnerability I´d like to understand properly:
Lets say i I have a Variable foo.bar with the input <h1>test</h1>
I now figured out this pattern:
{{foo.bar}} -> no XSS
{% trans with { '%var%': foo.bar } %} My "%var%" {% endtrans %} -> XSS
{% trans with { '%var%': foo.bar | e('html') } %} My "%var%" {% endtrans %} -> no XSS
I thought I´ll run a Regex Pattern trough his whole code to find potential other places for bad encoding of HTML Character, but I did not quite understand when twig is encoding HTML tags and when not. I do understand the "e" (Encoding) function which decodes my variable value in html entities, but why is {{foo.bar}} encoding the characters while {% trans with ... is not?
I would search with this pattern for Coding mistakes in Twig:
Regex:
'\{%(.){0,2}[trans](.){0,2}[with].*'
-> Searching for "{%[space?]trans[space?] with"
as I guess everytime he missed the |e('html') there might be an issue. Am I on the right track? Do I miss something??
I hope i can find more clarification on this topic here :)
Twig always escapes but "trans with" is part of symfony and not twig. It is not autoescaped because it is passed to a tag, and the tag may output it but that is not a certainty so this is why they refuse to autoescape.
I personally always use the |trans() filter instead so by default you know you are safe, you can still ofcourse use |raw if needed.
https://symfony.com/doc/current/translation/templates.html
Using the translation tags or filters have the same effect, but with one subtle difference: automatic output escaping is only applied to translations using a filter. In other words, if you need to be sure that your translated message is not output escaped, you must apply the raw filter after the translation filter:

Inconsistent line-feed rendering with PHP echo

Consider the following PHP code:
<?php
echo "prefix";
echo "
{{ foo }}
";
echo "suffix";
It renders as:
prefix
{{ foo }}
suffix
As can be seen here:
http://sandbox.onlinephpfunctions.com/code/4c0b3a3e921b0a761b1cf05f12f709d025d1b2de
Note the line feed between prefix and {{ foo }}.
Now consider the following code:
<?php
echo "
{{ foo }}
";
echo "suffix";
It renders as:
{{ foo }}
suffix
As can be seen here:
http://sandbox.onlinephpfunctions.com/code/18b07b9d05b79703617364b4d301d6799654a086
Why was the first line feed not rendered in the second case while it was in the first?
This seems to be because the web browser (or website running the PHP for you) is removing the extra whitespace from the rendered HTML output. (See: https://stackoverflow.com/a/17784740)
If you run your code on the PHP command line, then you will see the leading newline that you desire.
If this code is going to be used in a HTML page, then use <br/> tags to make new lines.

How to get the first character from a record not including html

I'm making a theme for Bolt (CMS) and it uses the Twig engine.
The website contains articles so I get an article's field like this {{ article.body }}
Now what I wanted to achieve was get the first letter of the body of the article and make it big and then display the rest of the article's body (without this first character) normally, you sometimes see this in books. I managed to do that and I successfully change the style of the first character.
However, using most functions that Twig offers in the documentation, I most often get a "<" as the first symbol as when typing the body of the article in the administration panel it automatically puts a <p> tag to the start.
Is there a way to overcome this?! I wouldn't want my client to have to delete the <p> tag every time. I thought there would be an easy way to get the body without any html in it or something else suitable for my use case.
The way it currently works beautifully:
<span class="firstcharacter">{{ article.body[:1] }}</span> {{ article.body[1:] }}</p>
but this relies on the article not starting with any html
There is a css pseudo-selector for first letter:
.firstcharacter::first-letter{font-size: 50px;}
Would this work for you?
You can use the striptags filter. As example:
{{ article.body| striptags [:1] }}
Here a working example
Hope this help
You shouldn't need to extract the first letter if you use CSS e.g.
Template:
<div class="dropcap">{{ article.body }}</div>
CSS:
div.dropcap p:first-of-type::first-letter {color: #f00;}
That will alter the first letter of the first paragraph.

How to output html without whitespace getting removed in twig?

I started to use twig as template engine and I like it somehow.
The only thing I don't know how to disable it, is the optimized html that it renders (newest version of twig).
Twig seems to remove all unused white spaces and line breaks.
In Productive Mode it is quite useful if you have a page that should have a high rank in google.
But during Development it is not really usefull.
So my question: How do you disable this?
If you use the spaceless tag twig remove whitespace between HTML tags, not whitespace within HTML tags or whitespace in plain text:
{% spaceless %}
<div>
<strong>foo</strong>
</div>
{% endspaceless %}
output will be <div><strong>foo</strong></div>
For more information on whitespace control, read the dedicated section of the documentation and learn how you can also use the whitespace control modifier on your tags.
Your twig version is 1.18.1 ?

shortcut to escaping to prevent XSS

I've just discovered that my website (html/php) is vulnerable to XSS attacks.
Is there any way to sanitize my data besides manually adding htmlspecialchars to each individual variable that I send to the webpage (and proably missing a few thereby leaving it still open to attack)?
No, there is no shortcut. Data escaping always needs to happen on a case by case basis; not only with regards to HTML, but to any other textual format as well (SQL, JSON, CSV, whathaveyou). The "trick" is use tools which do not require you to think about this much and hence may allow you to "miss" something. If you're just echoing strings into other strings, you're working at the bare metal level and you do need a lot of conscious effort to escape everything. The generally accepted alternative is to use a templating language which implicitly escapes everything.
For example, Twig:
The PHP language is verbose and becomes ridiculously verbose when it
comes to output escaping:
<?php echo $var ?>
<?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8') ?>
In comparison, Twig has a very concise syntax, which make
templates more readable:
{{ var }}
{{ var|escape }}
{{ var|e }} {# shortcut to escape a variable #}
To be on the safe side, you can enable automatic output escaping globally or for a block of code:
{% autoescape true %}
{{ var }}
{{ var|raw }} {# var won't be escaped #}
{{ var|escape }} {# var won't be doubled-escaped #}
{% endautoescape %}
This still lets you shoot yourself in the foot, but is a lot better.
One step up still is PHPTAL:
<div class="item" tal:repeat="value values">
<div class="title">
<span tal:condition="value/hasDate" tal:replace="value/getDate"/>
<a tal:attributes="href value/getUrl" tal:content="value/getTitle"/>
</div>
<div id="content" tal:content="value/getContent"/>
</div>
It requires you to write valid HTML simply to compile the template, and the template engine is fully aware of HTML-syntax and will process all user data at the level of a DOM, instead of a string soup. This relegates HTML to a pure serialisation format (which it should be anyway) which is produced by a serialiser whose only job it is to turn an object oriented data structure into text. There's no way to mess up that syntax through bad escaping.

Categories