Skip to content

[9.x] Fixes blade tags issue #45424 馃敡 - #45490

Merged
taylorotwell merged 4 commits into
laravel:9.xfrom
imanghafoori1:blade
Jan 10, 2023
Merged

[9.x] Fixes blade tags issue #45424 馃敡#45490
taylorotwell merged 4 commits into
laravel:9.xfrom
imanghafoori1:blade

Conversation

@imanghafoori1

@imanghafoori1 imanghafoori1 commented Jan 2, 2023

Copy link
Copy Markdown
Contributor

solves #45424

The solution seems a bit hacky, but the idea, however, is simple:

  • Without changing the regex pattern, we perform our first search to get matches.
  • Then by using PHP tokenizer, we check if we are in trouble or not.
  • If we are in trouble, we try to fix it by adding the next candidate section to the matched string to see if we can reach the proper closing parenthesis or not.
  • We try the same process until we find the proper match for the closing parenthesis of the blade tag.
@include ( 
  'partial1', ['hell)o' => ')-)--)']  
)

in this example, regex finds the :
@include ( 'partial1', ['hell) first and the loop adds these portions until it reaches the closing:
)o' => '
)-
)--
'] ) <=== the closing one.

Performance:

  • Let me note that this part of the code is NOT run during each and every request/response life cycle since the compiled versions of blade files get cached.

  • Some tests are included to prove the fix.

As I know, Taylor likes to find a proper regex for it and does not like such solutions, maybe the regex can be found somewhere in open-source IDE syntax highlighters like VS code, or people from Jetbrain can help since they can highlight the syntax properly.

@taylorotwell

Copy link
Copy Markdown
Member

If we are going to attempt to solve that issue should we not add a new test ensuring that issue is actually fixed?

@imanghafoori1

Copy link
Copy Markdown
Contributor Author

Yeah, I will add more tests, currently, I have changed the previous test which proves the bug to indicate the fix.
But for now, it is a WIP. I should mark this as a draft. Slight tweaks are needed.

@imanghafoori1 imanghafoori1 changed the title [9.x] Fixes blade tags issue #45424 [9.x][WIP] Fixes blade tags issue #45424 Jan 3, 2023
@imanghafoori1
imanghafoori1 force-pushed the blade branch 3 times, most recently from e25a2f5 to 759089b Compare January 3, 2023 16:35
@imanghafoori1 imanghafoori1 changed the title [9.x][WIP] Fixes blade tags issue #45424 [9.x] Fixes blade tags issue #45424 Jan 3, 2023
@imanghafoori1

Copy link
Copy Markdown
Contributor Author

@taylorotwell I think I am done with this PR for now.

@imanghafoori1
imanghafoori1 force-pushed the blade branch 4 times, most recently from 2354c99 to 5015a74 Compare January 4, 2023 12:35
@imanghafoori1

imanghafoori1 commented Jan 4, 2023

Copy link
Copy Markdown
Contributor Author

The first commit solves the problem for closing chars (without touching the original regex)
like: @include('a', [' :)))) '])

The second commit solves the problem for opening chars (but tweaks the original regex)
like: @include('a', [' :(((( '])

So if you want to stay really safe and avoid touching the regex, you can keep the first and discard the second one.

  • Changing regex causes it to stop as soon as it reaches the first closing parenthesis, and do not match the opening and closing ones.

Comment thread src/Illuminate/View/Compilers/BladeCompiler.php
@taylorotwell

Copy link
Copy Markdown
Member

Can you provide some insight about what happens if it never finds a proper closing parenthesis?

Also, do you have some before / after benchmarks of running view:cache with this change on a code base with a fairly large amount of templates?

@imanghafoori1

Copy link
Copy Markdown
Contributor Author

Since the user has to provide valid PHP syntax as input for the blade tags, it means that the closing parenthesis should be found or there is a syntax error in the first place, but yeah it is good to have a test about the result and the thrown error.

  • Performance:
    I do not know how I should demo performance difference, but let's keep in mind:
    The new code is only executed if the regex fails to find a good match, so if you have an application with a lot of blade files that do not step over the bug, the tokenizer and all the added logic never get run even when you build the cache.

From experience, I know that the tokenizer is extremely fast. My laravel-microscope package runs the entire application code through tokenizer and all processes the tokens and this usually happens in a fraction of a second on a 10-years-old home PC.

@taylorotwell

Copy link
Copy Markdown
Member

Alright. Can you maybe add some sort of test case or behavior description for what happens if there is never a closing parenthesis found?

@imanghafoori1

Copy link
Copy Markdown
Contributor Author

I added the test for the unclosed blade tag. It seems that they are considered a tag with no parenthesis.

@timacdonald

timacdonald commented Jan 5, 2023

Copy link
Copy Markdown
Member

I spent some time trying to break this today, but it seems to be holding up to everything I've thrown at it.

I also booted up a decently sized Blade only project from a few years ago that uses all the older style blade bits (i.e. not <x-whatever) and it seemed happy.

I ran php artisan view:cache on a loop for 100 iterations against the project with the compiler before and after this PR. The results:

Before: 11.34 seconds
After: 11.98 seconds

Don't think there is anything performance-wise to worry about.

@taylorotwell
taylorotwell merged commit e4fdb29 into laravel:9.x Jan 10, 2023
@imanghafoori1 imanghafoori1 changed the title [9.x] Fixes blade tags issue #45424 [9.x] Fixes blade tags issue #45424 馃敡 Jan 10, 2023
@imanghafoori1
imanghafoori1 deleted the blade branch January 10, 2023 14:30
@rubenvanerk

Copy link
Copy Markdown

I think I may have found an edge case. The code below is broken on v9.47+, but works on v9.46.

<div>
    <span @class([
        'lt-text-xs lt-inline-block lt-py-1 lt-px-2 lt-rounded',
        'lt-text-green-600 lt-bg-green-50' => !@empty($success),
        'lt-text-yellow-600 lt-bg-yellow-50' => !@empty(
            $warning
        ),
        'lt-text-red-600 lt-bg-red-50' => !@empty($danger),
    ])>
        {{ $value }}
    </span>
</div>

This gets compiled to:

<span聽class="<?php聽echo聽\Illuminate\Support\Arr::toCssClasses([
聽聽聽聽聽聽聽聽'lt-text-xs聽lt-inline-block聽lt-py-1聽lt-px-2聽lt-rounded',
聽聽聽聽聽聽聽聽'lt-text-green-600聽lt-bg-green-50'聽=>聽!@empty($success),
聽聽聽聽聽聽聽聽'lt-text-yellow-600聽lt-bg-yellow-50'聽=>聽!<?php聽if(empty(
聽聽聽聽聽聽聽聽聽聽聽聽$warning
聽聽聽聽聽聽聽聽)):聽?>,
聽聽聽聽聽聽聽聽'lt-text-red-600聽lt-bg-red-50'聽=>聽!<?php聽if(empty($danger)):聽?>,
聽聽聽聽])聽?>">

And throws the error syntax error, unexpected token "<"

Context: lunarphp/lunar#822

@imanghafoori1

imanghafoori1 commented Jan 22, 2023

Copy link
Copy Markdown
Contributor Author

@rubenvanerk I think the fix is somewhat easy.
Thanks for your report.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants