Smarty Forum Index Smarty
The discussions here are for Smarty, a template engine for the PHP programming language.

Inaccurate Lexer/Compiler - TRAILING NEWLINE Issue

 
Post new topic   Reply to topic    Smarty Forum Index -> General
View previous topic :: View next topic  
Author Message
XPSystemServices
Smarty n00b


Joined: 20 Apr 2017
Posts: 4

PostPosted: Thu Apr 20, 2017 11:46 am    Post subject: Inaccurate Lexer/Compiler - TRAILING NEWLINE Issue Reply with quote

Why Template Compiler removes trailing NEWLINE-s in some cases?
This will produce an inaccurate HTML-code.
Please look at the examples shown below:

Example 1
Code:
SOURCE TEMPLATE:
=====================
a
{* comment 1 *}
{* comment 2 *}
{* comment 3 *}
b

RESULT HTML (accurate, as expected):
=====================
a



b


Example 2
Code:
SOURCE TEMPLATE:
=====================
a
b{if ...}
d<span></span>
f{/if}
h

RESULT HTML (inaccurate):
=====================
a
bd<span></span>
fh

Expected result:
=====================
a
b
d<span></span>
f
h


Smarty should only remove Smarty-commands {...}, but shouldn't remove leading and trailing html-content (such as whitespaces and newlines). Please fix it, because this will produce undefined behavior (for example inside html <pre>-tags).

Please let developer consider how to deal with leading/trailing content (for example using smarty pre-filters).

Thank you!

Smarty version: 3.1.30


Last edited by XPSystemServices on Fri Apr 21, 2017 10:58 pm; edited 1 time in total
Back to top
View user's profile Send private message
AnrDaemon
Administrator


Joined: 03 Dec 2012
Posts: 1024

PostPosted: Thu Apr 20, 2017 11:34 pm    Post subject: Reply with quote

This is a PHP problem. PHP truncates EOL character immediately after "?>".
The only way you can get the code you want is to account for this PHP behavior.
Back to top
View user's profile Send private message
XPSystemServices
Smarty n00b


Joined: 20 Apr 2017
Posts: 4

PostPosted: Fri Apr 21, 2017 7:20 am    Post subject: Reply with quote

Ok, this is documented feature in PHP, and this behavior will newer change.

What is the cause of the problem? And why you can't fix it?

Is it possible to add extra "newline" after "?>" when {/if} comes with trailing "newline". For example:

"{/if}\r\n" compile to "?>\r\n\r\n"

"{/if}\n" compile to "?>\n\n"

"{/if}" compile to "?>"

...
Back to top
View user's profile Send private message
AnrDaemon
Administrator


Joined: 03 Dec 2012
Posts: 1024

PostPosted: Fri Apr 21, 2017 4:25 pm    Post subject: Reply with quote

While it is rare to see Smarty used to construct binary data, it is not uncommon.
The problem is that you can't always say with certain that this or that EOL in template is significant for the resulting document. But as long as the compiled code matches template code closely, you can predict the behavior and account for it.
Back to top
View user's profile Send private message
XPSystemServices
Smarty n00b


Joined: 20 Apr 2017
Posts: 4

PostPosted: Fri Apr 21, 2017 6:36 pm    Post subject: Reply with quote

AnrDaemon wrote:
While it is rare to see Smarty used to construct binary data, it is not uncommon.


We are not talking about binary data. You can't ignore, that output inside <pre></pre> is always broken.

AnrDaemon wrote:

The problem is that you can't always say with certain that this or that EOL in template is significant for the resulting document.


This is completely no problem. Developers can easily control output using pre/post filters. There are a lot useful solutions... for example this one:

https://gist.github.com/rodneyrehm/3013807

But at this time this is very hard and not intuitive because output content is inaccurate.

AnrDaemon wrote:

But as long as the compiled code matches template code closely, you can predict the behavior and account for it.


No and No! In the current version (3.1.30) this behavior is completely unpredictable, because Compiler sometimes merges several smarty-commands to the single PHP-block, and sometimes not. A NEWLINES between smarty-commands in some cases disappears, but kept in some other cases.

There is a simple (demo) solution to implement accurate output in the current version of Smarty using pre-filter. We can replace NEWLINES in the source template with some escape sequence, and then compile template, and finally replace NEWLINES back.

Code:

function smarty_prefilter_trailing_NL_control($string, Smarty_Internal_Template $template) {
  return preg_replace(
    '/' . preg_quote($template->smarty->right_delimiter) . '(\r?\n)' . '/msi',
    $template->smarty->right_delimiter . '{$smarty.const.PHP_EOL}',
    $string
  );
}


But this is really ugly solution. It currently does not handle {literal}-commands.

This behavior should be implemented in Smarty-core.

PS: Sorry for my english.
Back to top
View user's profile Send private message
AnrDaemon
Administrator


Joined: 03 Dec 2012
Posts: 1024

PostPosted: Fri Apr 21, 2017 7:53 pm    Post subject: Reply with quote

Please be more specific, than "several".
I can imagine certain sequence of blocks being merged due to compilation and caching reasons, but specific examples would help to better understand your issue.
Back to top
View user's profile Send private message
XPSystemServices
Smarty n00b


Joined: 20 Apr 2017
Posts: 4

PostPosted: Fri Apr 21, 2017 10:34 pm    Post subject: Reply with quote

AnrDaemon wrote:
Please be more specific, than "several".
I can imagine certain sequence of blocks being merged due to compilation and caching reasons, but specific examples would help to better understand your issue.


Code:

These commands will be compiled to single PHP-block
=======
{/if}
{if}

These commands will be compiled to separate PHP-blocks
=======
{/if}

{if}


I mean this behavior is unpredictable, because of several problems:

1) Smarty margins some commands to a single PHP-block and omits NEWLINES between these commands.
2) PHP removes NEWLINES after PHP closing-tag (?>) but Smarty doesn't add it back.
3) Smarty removes NEWLINES between commands only for some specific sequence... For example NEWLINE for {if}\n{if} or {\if}\n{\if} will be removed, but for {* *}\n{* *} will be kept.

Below are shown absolutely equivalent examples... and absolutely identical outputs are expected for each example, but results are really unpredictable.

Code:
Source:
=====================
{if ...}
{foreach ...}
    <htmltag />
{/foreach}
{/if}
=====================

Result:
=====================
    <htmltag />

=====================

Code:
Source:
=====================
{if ...}
{if ...}
    <htmltag />
{/if}
{/if}
=====================

Result:
=====================
     <htmltag />
=====================

Code:
Source:
=====================
{* comment *}
{* comment *}
    <htmltag />
{* comment *}
{* comment *}
=====================

Result:
=====================


    <htmltag />


=====================
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    Smarty Forum Index -> General All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group
Protected by Anti-Spam ACP