smarty-php / smarty

Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic.
Other
2.24k stars 705 forks source link

setForceCompile(TRUE) in Smarty 5 throw exception 'unable to write file' #898

Closed lkppo closed 12 months ago

lkppo commented 1 year ago

Hello,

We have been testing Smarty 5.0.0-rc1 with PHP 8.2 for a few months and have noticed on both Mac and Windows that if the Force Compile option is activated, errors occur when writing compiled files.

Fatal error: Uncaught --> Smarty: unable to write file C:\devel\www\wikindx\cache\templates\default\compile\1d93a5418ebba31bc468f3d375f30b3aab8d0444_0.file_content.tpl.php <-- thrown in C:\devel\www\wikindx\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php on line 1738

Regards,

wisskid commented 1 year ago

Any clue? The writeFile method (the one triggering the error) hasn't been changed. A reproduction scenario would help. Does the error not occur with Smarty v4.3?

lkppo commented 1 year ago

Right. I just tested with 4.3 and found the same error. How to help?

lkppo commented 1 year ago

I have something more in logs. An access error on renaming (with v4.3):

[2023-08-31T00:30:52+02:00] PHP Warning: rename(C:\devel\www\wkxlocal\cache\templates\default\compile\wrt64efc31c2f0678_24005802,C:\devel\www\wkxlocal\cache\templates\default\compile\98311c0ceca995f0db9f4ad41b2dcfa2b27b16c2_0.file.display.tpl.php): Accès refusé (code: 5) in C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php on line 1818
[2023-08-31T00:30:52+02:00] #1 rename called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php:1818]
[2023-08-31T00:30:52+02:00] #2 Smarty\Smarty->writeFile called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:232]
[2023-08-31T00:30:52+02:00] #3 Smarty\Template\Compiled->write called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:195]
[2023-08-31T00:30:52+02:00] #4 Smarty\Template\Compiled->compileAndWrite called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:148]
[2023-08-31T00:30:52+02:00] #5 Smarty\Template\Compiled->compileAndLoad called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:108]
[2023-08-31T00:30:52+02:00] #6 Smarty\Template\Compiled->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:184]
[2023-08-31T00:30:52+02:00] #7 Smarty\Template->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:639]
[2023-08-31T00:30:52+02:00] #8 Smarty\Template->_execute called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:576]
[2023-08-31T00:30:52+02:00] #9 Smarty\Template->display called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php:2243]
[2023-08-31T00:30:52+02:00] #10 Smarty\Smarty->display called at [C:\devel\www\wkxlocal\core\libs\CLOSE.php:241]
[2023-08-31T00:30:52+02:00] #11 CLOSE->__construct called at [C:\devel\www\wkxlocal\core\libs\CLOSE.php:367]
[2023-08-31T00:30:52+02:00] #12 CLOSEPOPUP->__construct called at [C:\devel\www\wkxlocal\core\startup\FACTORY.php:608]
[2023-08-31T00:30:52+02:00] #13 FACTORY_CLOSEPOPUP::getInstance called at [C:\devel\www\wkxlocal\public\tinymce\plugins\wkxcharmap\dialog_column_right.php:105]
[2023-08-31T00:30:52+02:00] 
lkppo commented 1 year ago

Greenshot-20230831003814

lkppo commented 1 year ago

An other example after cleaning the compile directory by hand (with v4.3):

[2023-08-31T00:48:28+02:00] PHP Warning: rename(C:\devel\www\wkxlocal\cache\templates\default\compile\wrt64efc73bef1716_94705877,C:\devel\www\wkxlocal\cache\templates\default\compile\e8aa5c4d14c9bcd5d59a3c94eb62fdd56be81fe7_0.file.content.tpl.php): Accès refusé (code: 5) in C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php on line 1818
[2023-08-31T00:48:28+02:00] #1 rename called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php:1818]
[2023-08-31T00:48:28+02:00] #2 Smarty\Smarty->writeFile called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:232]
[2023-08-31T00:48:28+02:00] #3 Smarty\Template\Compiled->write called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:195]
[2023-08-31T00:48:28+02:00] #4 Smarty\Template\Compiled->compileAndWrite called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:148]
[2023-08-31T00:48:28+02:00] #5 Smarty\Template\Compiled->compileAndLoad called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:108]
[2023-08-31T00:48:28+02:00] #6 Smarty\Template\Compiled->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:184]
[2023-08-31T00:48:28+02:00] #7 Smarty\Template->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:289]
[2023-08-31T00:48:28+02:00] #8 Smarty\Template->renderSubTemplate called at [C:\devel\www\wkxlocal\cache\templates\default\compile\98311c0ceca995f0db9f4ad41b2dcfa2b27b16c2_0.file.display.tpl.php:81]
[2023-08-31T00:48:28+02:00] #9 content_64efc73bd4d1c4_85818131 called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\GeneratedPhpFile.php:110]
[2023-08-31T00:48:28+02:00] #10 Smarty\Template\GeneratedPhpFile->getRenderedTemplateCode called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template\Compiled.php:115]
[2023-08-31T00:48:28+02:00] #11 Smarty\Template\Compiled->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:184]
[2023-08-31T00:48:28+02:00] #12 Smarty\Template->render called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:639]
[2023-08-31T00:48:28+02:00] #13 Smarty\Template->_execute called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Template.php:576]
[2023-08-31T00:48:28+02:00] #14 Smarty\Template->display called at [C:\devel\www\wkxlocal\core\libs\vendor\smarty\smarty\smarty\src\Smarty.php:2252]
[2023-08-31T00:48:28+02:00] #15 Smarty\Smarty->display called at [C:\devel\www\wkxlocal\core\libs\CLOSE.php:241]
[2023-08-31T00:48:28+02:00] #16 CLOSE->__construct called at [C:\devel\www\wkxlocal\core\libs\CLOSE.php:367]
[2023-08-31T00:48:28+02:00] #17 CLOSEPOPUP->__construct called at [C:\devel\www\wkxlocal\core\startup\FACTORY.php:608]
[2023-08-31T00:48:28+02:00] #18 FACTORY_CLOSEPOPUP::getInstance called at [C:\devel\www\wkxlocal\public\tinymce\plugins\wkxcharmap\dialog_column_left.php:82]
[2023-08-31T00:48:28+02:00] 
wisskid commented 1 year ago

What are the steps you take that trigger the error?

lkppo commented 1 year ago

WIKINDX use globals to collect variables to render. Smarty is called only at the end for rendering by the CLOSE::_construct() function. Smarty's behavior is configured just before rendering by TEMPLATE::loadTemplate().

There are only two differences from the common case where the error is not triggered:

Maybe I'm doing something incompatible during configuration, calling functions in the wrong order, or there's an error in the template?

Do you need any other information?

wisskid commented 1 year ago
  1. Does the error occur every time you call $smarty->display()?
  2. Can you provide a minimal example (without any of the WIKINDX code) that triggers this error?
lkppo commented 1 year ago

This happens whenever $smarty->display() is called, Force compile is enabled, and the menu is hidden. In a context where the menu is displayed there is no error.

I'm preparing a minimal example for tomorrow.

lkppo commented 1 year ago

A minimal example is attached.

You need to call many time the index.php page from this archive with a browser to trigger the error.

The error occurs less often because I removed a lot of code.

My understanding of the error is this: as index.php uses an HTML frame to call two pages that are rendered separately but at the same time when Force Compile is enabled the destruction of the templates can cause a race condition when the compiled templates are recreated.

wkxdebugsmarty.zip

wisskid commented 1 year ago

Yes, that seems reasonable. And I'm not sure this can be fixed easily.

This is one the reasons why you would not want to use force compile in production.

lkppo commented 1 year ago

We don't use it in production fortunately. Forgetting to disable it during development is the only annoyance. So I no longer see any reason to worry about this problem either.

I'm just wondering why this strategy of writing to a temporary file then renaming it to write it directly to the file?

wisskid commented 1 year ago

Interestingly, I believe this was introduced to prevent a race condition where two processes would write to the same file... 🤪

lkppo commented 1 year ago

Concurrency is hard... It would have been better to write directly and if that fails to set a pause of a few microseconds then try again once.

I am making a proposal since this seems like an opportunity. I wrote an SQLite storage backend of the cached and compiled pages. This was to test feasibility and performance. It seemed more efficient to me than writing directly to files. Is this a good replacement option or a contribution you would accept? And if you accept it, I undertake to maintain this code.

wisskid commented 1 year ago

SQLite stores the whole database as a single file and locks the database file during writing.

Thus, I doubt it would be more efficient than writing to (separate) files directly.

lkppo commented 1 year ago

I noticed during the test that the same page was displayed twice as fast.

But it's true that it wasn't a server facing the internet.

https://sourceforge.net/p/wikindx/v5bugs/604/#788e/7713