Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Precompile templates error with filter. #21

Open
daebak74 opened this issue Jul 9, 2019 · 8 comments
Open

Precompile templates error with filter. #21

daebak74 opened this issue Jul 9, 2019 · 8 comments
Labels

Comments

@daebak74
Copy link

daebak74 commented Jul 9, 2019

I try some test but I don't understand why is generated this error.

Delight\Foundation\Throwable\TemplateSyntaxError: Unknown "ifFileExist" filter. in file Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php on line 167
Stack trace:
  1. Delight\Foundation\Throwable\TemplateSyntaxError->() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php:167
  2. Twig_Error_Syntax->() Z:\ws\www\foundation\views\backend\default\catalog\includes\javascript\prices.html.twig:16
  3. Twig_ExpressionParser->getFilterNodeClass() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:484
  4. Twig_ExpressionParser->parseFilterExpressionRaw() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:469
  5. Twig_ExpressionParser->parseFilterExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:323
  6. Twig_ExpressionParser->parsePostfixExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:215
  7. Twig_ExpressionParser->parsePrimaryExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:102
  8. Twig_ExpressionParser->getPrimary() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\ExpressionParser.php:55
  9. Twig_ExpressionParser->parseExpression() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\TokenParser\If.php:33
 10. Twig_TokenParser_If->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Parser.php:192
 11. Twig_Parser->subparse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Parser.php:105
 12. Twig_Parser->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:716
 13. Twig_Environment->parse() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:774
 14. Twig_Environment->compileSource() Z:\ws\www\foundation\vendor\twig\twig\lib\Twig\Environment.php:452
 15. Twig_Environment->loadTemplate() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\TemplateManager.php:161
 16. Delight\Foundation\TemplateManager->precompile() Z:\ws\www\foundation\vendor\delight-im\foundation-core\src\App.php:931
 17. Delight\Foundation\App->precompileTemplates() Z:\ws\www\foundation\index.php:111

I created this filter after issue #14 my problem was to check if a lang file exist if not use a fallback file. Because is in Template I prefered to use this solution and not file exist for directory traversal attacks.

MY FILTER


$app->getTemplateManager()->addFilter('ifFileExist', function($file) {
		
		$real_base = realpath('public');
		$check_file = $real_base . $file;
		$real_file = realpath($check_file);
		
		if ($real_file === false || strpos($real_file, $real_base) !== 0) {
			return false;
		} else {
			return true;
		}
	});

The if condition in template where is indicated the error

{% set qb_lang = '/assets/querybuilder/i18n/query-builder.'~ session.EZ_LANG ~'.js' %}

{% if qb_lang | ifFileExist %}
<script src="{{ app.url('/assets/querybuilder/i18n/query-builder.'~ session.EZ_LANG ~'.js') }}"></script>
{% else %}
<script src="{{ app.url('/assets/querybuilder/i18n/query-builder.'~ session.EZ_FALLBACK_LANG ~'.js') }}"></script>
{% endif %}

Seems that doesn't like this syntax

{% if qb_lang | ifFileExist %} (Line 16)

Thanks.

@ocram ocram added the bug label Jul 9, 2019
@ocram
Copy link
Contributor

ocram commented Jul 9, 2019

Thank you!

When not trying to precompile templates but viewing your application in the browser, as usual, the filter works, doesn’t it? So it’s really not that something is wrong with the filter or the way you defined it.

I guess this must then be because the filter is not yet defined when the framework precompiles the templates for you. That step is executed in the index.php from the parent directory, while you have probably defined the filter in the index.php of the child directory or any other class or file loaded there.

What you did is correct, the problem is in this framework. You could temporarily move your filter definition to the index.php in the parent directory (before the code that precompiles the templates). But this is not a real solution because that file is not supposed to contain your custom application code. As a permanent fix, we have to find something else.

@daebak74
Copy link
Author

daebak74 commented Jul 10, 2019

Thank you for your fast reply!

Yes in the application the filter work and I suspected that the precompile was called before but I didn't check where exactly thanks for your link to show me where.

By the way I'll wait your fix because not just need to move the filter in parent but the class init should be moved too so the index.php in child directory become senseless.

@ocram
Copy link
Contributor

ocram commented Jul 12, 2019

Not sure if you should really wait for a fix, because we cannot give any time estimate right now.

Are you sure you really need to move all your definitions and classes? You should make your classes compatible with autoload. If you do this, it’s not important where your classes are loaded first.

Any class in /app will be available via autoloading if you declare namespace App; at the top and the filename is the class name with the PHP extension.

As for this issue here, I see two possible solutions:

  • Processing the CLI commands not before processing your /app/index.php with all routes and custom application codes, but after. At that point, all filters, globals, functions and classes will be available. But this doesn’t work if you exit somewhere in your custom application code (that is executed), or if a route is executed that should not be run on the CLI.
  • Splitting /app/index.php into /app/global.php, where you can put filter definitions, global functions, etc., and which is executed before the CLI commands are processed, and /app/routes.php, which is executed after the CLI commands are processed, and which can contain your normal route definitions (and other custom application code).

@daebak74
Copy link
Author

daebak74 commented Jul 13, 2019

Thanks!

I'll try to read well and understand your 2 solutions and make some test hope that I fix because I didn't get what do you mean with

Are you sure you really need to move all your definitions and classes? You should make your classes compatible with autoload. If you do this, it’s not important where your classes are loaded first.

I just split classes because the app is big but I think that I followed your directive How To manage the Route and Class definition.

app/index.php

use Delight\Foundation\App;

require ('/routes/backend.php');	
$app->setStatus(404);
$app->redirect('/foundation/error?code=404');

app/routes/backend.php

use Delight\Foundation\App;
$app->get('/foundation/dashboard', ['\App\Controllers\Backend\Core\Dashboard', 'getDashboard']);

app/controllers/backend/core/dashboard.php

namespace App\Controllers\Backend\Core;	
use Delight\Foundation\App;	
class Dashboard {		
	public static function getDashboard(App $app) {

		echo $app->view('/backend/'. $_SESSION['BE_THEME'] .'/core/dashboard.html.twig', [...]);

	}		
}

Now even if I add filter function on top of index.php show me the error because the template precompiled is before in parent index.php so where is my different declaration ?

Any class in /app will be available via autoloading if you declare namespace App; at the top and the filename is the class name with the PHP extension.

@ocram
Copy link
Contributor

ocram commented Jul 16, 2019

Your code looks good.

Look into the index.php in the parent directory, just before the CLI commands are handled:

PHP-Foundation/index.php

Lines 106 to 108 in 42ee0cf

function _m($text) { global $app; return $app->i18n()->markForTranslation($text); }
if ($app->isClientCli() || $app->isClientLoopback()) {

Right there, in line 107, simply insert

require __DIR__ . '/app/global.php';

and then create a new global.php in your /app/ folder right next to your index.php.

Now move the definition of the filter from index.php to global.php.

Does that work?

@daebak74
Copy link
Author

Sorry for long the delay of my answer, but I was working on other part.

For make this test is not so much fast and simple because I don't have only 1 filter but different Filter, function and Global. Than I should to change some constants.

If this is the final solution and this is the only way so I'll change all the structure.

Thanks.

@daebak74
Copy link
Author

Anyway as a temp test I initialized everything before and work.

@ocram
Copy link
Contributor

ocram commented Jan 23, 2020

Thanks, good to know!

Unfortunately, this is still the only two solutions I can imagine:

* Processing the CLI commands _not before_ processing your `/app/index.php` with all routes and custom application codes, but _after_. At that point, all filters, globals, functions and classes will be available. But this doesn’t work if you `exit` somewhere in your custom application code (that is executed), or if a route is executed that should not be run on the CLI.

* Splitting `/app/index.php` into `/app/global.php`, where you can put filter definitions, global functions, etc., and which is executed _before_ the CLI commands are processed, and `/app/routes.php`, which is executed after the CLI commands are processed, and which can contain your normal route definitions (and other custom application code).

As I have explained the second solution already, let’s talk about the first solution and what you’d need to do:

In /index.php, move require __DIR__ . '/app/index.php'; (and its comment) before the larger block starting with if ($app->isClientCli() || $app->isClientLoopback()) { – that’s all. But if your index route (GET /) is then executed when running on the CLI, you could get results that you don’t want, e.g. HTML output on the CLI. As it is a GET request, it should not have any side effects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants