Problem/Motivation
TwigEnvironment is sending invalid filenames to the storage backends when using inline templates.
In this method:
namespace Drupal\Core\Template;
// [...]
/**
* Implements Twig_Environment::loadTemplate().
*
* We need to overwrite this function to integrate with drupal_php_storage().
*
* This is a straight copy from loadTemplate() changed to use
* drupal_php_storage().
*
* @param string $name
* The template name or the string which should be rendered as template.
* @param int $index
* The index if it is an embedded template.
*
* @return \Twig_TemplateInterface
* A template instance representing the given template name.
*
* @throws \Twig_Error_Loader
* When the template cannot be found.
* @throws \Twig_Error_Syntax
* When an error occurred during compilation.
*/
public function loadTemplate($name, $index = NULL) {
The $name parameter can either be a path to a twig template, or an inline template.
In that same method, the $cache_filename used to store the compiled template is generated like this:
$cache_filename = $this->getCacheFilename($name);
And getCacheFilename($name) is expecting $name to be a path, not an inline template:
public function getCacheFilename($name) {
// [...]
if (!$this->cache) {
return FALSE;
}
$class = substr($this->getTemplateClass($name), strlen($this->templateClassPrefix));
// The first part is what is invalidated.
return $this->templateCacheFilenamePrefix . '_' . basename($name) . '_' . $class;
}
This can result in generating a cache_filename with invalid characters such as this one:
eab26728_{# inline_template_start #}{{ items | safe_join(separator) }}_6a27047eeba00af1c60ff2f4c59e9e614903a38f7c90d62ed5441a2edb82b31b
On POSIX compatible systems I believe this is not an issue, but those characters are not allowed on other platforms. Anyways, having such a filename does not look goooood.
Later on, when MTimeProtectedFastFileStorage tries to store the data using the weird filename you get an error:
rename(sites/default/files/php/twig/.348cbdff96,sites/default/files/php/twig/eab26728_{# inline_template_start #}{{ items | safe_join(separator) }}_6a27047eeba00af1c60ff2f4c59e9e614903a38f7c90d62ed5441a2edb82b31b/681514bc3d30ec66b9f65af2fb67575dd13c2ac9e54f4e046da77e7e526d2753.php): The filename, directory name, or volume label syntax is incorrect. (code: 123)
One of the templates it is chocking on is this one:
{# inline_template_start #}{{ items | safe_join(separator) }}
Proposed resolution
Fix getCacheFilename($name) to account for $name having the possiblity of being a path or an inline template.
Remaining tasks
--
User interface changes
--
API changes
--
Data model changes
--
Beta phase evaluation
Issue category | Bug because twig template caching is failing for inline templates. |
---|---|
Issue priority | Major because twig caching is not working and warnings are issued upon failure flooding the system logs. |
Comment | File | Size | Author |
---|---|---|---|
#59 | interdiff.txt | 712 bytes | effulgentsia |
#39 | interdiff.txt | 1.82 KB | star-szr |
#38 | twigenvironment_is-2558885-38.patch | 3.09 KB | star-szr |
#38 | twigenvironment_is-2558885-38-testonly.patch | 2.1 KB | star-szr |
#30 | interdiff.txt | 2.16 KB | star-szr |
Comments
Comment #2
david_garcia CreditAttribution: david_garcia commentedComment #3
david_garcia CreditAttribution: david_garcia commentedComment #4
david_garcia CreditAttribution: david_garcia commentedComment #5
david_garcia CreditAttribution: david_garcia commentedComment #6
david_garcia CreditAttribution: david_garcia commentedComment #7
othermachines CreditAttribution: othermachines commentedI came across this error on a fresh test install in a WAMP environment:
Applied #6 patch and reinstalled with no error.
Comment #8
star-szrThanks, on my phone now but I think this was changed recently in another issue. I will try to link it here a bit later.
Comment #9
star-szrThe method was overridden in #2544932: Twig should not rely on loading php from shared file system. This needs automated test coverage.
Comment #10
jhedstromI'll work on a test.
Comment #11
jhedstromThis adds a test for the expected cached filename.
Comment #14
star-szrfile_exists() might be heavy here from a performance perspective because as far as I know getCacheFilename() will be called quite a bit.
Other than that, getCacheFilename() is deprecated and will be removed in Twig 2.0, but it looks like we can contain this logic in our custom Twig cache class (#2426563-95: Ignore: Patch testing issue contains the cache class and some other 2.0 fixes).
Comment #15
dawehnerDid someone tried out the patch in #2568171: Upgrade to Twig 1.22 and implement our own cache class to see whether its fixed there already? If it is, we should just need the test coverage which is part of this particular patch.
Comment #16
alexpottWe can be certain we're dealing with an inline template and therefore no file exists.
Also #2568171: Upgrade to Twig 1.22 and implement our own cache class might solve this.
Comment #17
dawehnerIMHO we should use the same hash as in other places which is sha256 using the hash() function in php.
Comment #18
johnvI implemented #16 on my WAMP environment with 8.beta15 (since it was much shorter then #2568171).
The 'rename' warning still appears twice: The mkdir perhaps only appears upon install.
The message DOES appear on /admin/modules, and it does NOT appear on /admin/config .
Comment #19
johnvComment #20
star-szrJust making the hash change. This needs more manual testing on Windows I think, thanks for testing @johnv!
Comment #21
star-szrThe comment makes more sense above the line it's talking about.
Interdiff is from #16.
Comment #22
oriol_e9gFor a performance perspective it's faster crc32 t'han sha256. Actually (i think) we are using crc32 in core in other places.
Comment #25
star-szrSome installer fails from the looks of it.
Twig upstream uses sha256, so I think we should just stick with that. https://github.com/twigphp/Twig/blob/9df64cf582ea3a4c33da3b9ef2ffe82f061...
We'll need to refactor this before/after #2568171: Upgrade to Twig 1.22 and implement our own cache class anyway and it will end up in the generateKey method of the cache class.
Comment #26
dawehnerCould we not use a more generic regex and remove just the following chars "{ #}".
Comment #27
johnvPatch #21 is better.
Both pages /admin/modules and /admin/config have no messages anymore.
But pressing [Clear all caches] on /admin/config/development/performance still generatess:
Warning: rename(sites/d8b150917.dd/files/php/twig/.373c5f4b30,sites/d8b150917.dd/files/php/twig/7eee24fc_block--system-messages-block.html.twig_NNN.php): No such file or directory in ...\core\lib\Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage.php on line 91
Comment #28
johnv#2568171: Upgrade to Twig 1.22 and implement our own cache class is now committed. See #15, #16, #25.
Is this patch still needed?
Comment #29
star-szrIt needs more testing, I'm thinking we still need to make a change to fix this but it would likely be in \Drupal\Core\Template\TwigPhpStorageCache now.
Comment #30
star-szrThis is what I would propose. The interdiff is after a reroll.
Comment #32
johnv@Cottser, Sorry, cannot test this ATM , since I am working on beta15, en the new patch requires an update of the environment.
Comment #34
star-szr@johnv thanks, I don't think at this point it makes sense to create a patch for beta15.
It would be really nice to get this in, I'm not sure if it actually needs manual testing but it would be great to get a confirmation from someone who's experiencing this problem.
For now it would be great to get the code reviewed.
Comment #35
alexpott@Cottser I think this should be really easy to write an automated test for since I broke it recently.
Comment #36
star-szr@alexpott there are tests, do you mean add more tests? :)
Comment #37
dawehnerYeah I think @alexpott means more like an integration test.
Comment #38
star-szrThis should be better because it will actually throw an exception from the storage. Thank you @alexpott on IRC for clarifying!
Comment #39
star-szrMissing interdiff.
Comment #42
mikeker CreditAttribution: mikeker as a volunteer commentedVerified that #38 fixes the errors on Windows. Thanks, @Cottser!
Comment #43
MattA CreditAttribution: MattA commentedI've also been using it for a few days on a dev box, and can confirm that it fixes the PHP warning. I don't know enough about the Twig caching system to RTBC it though. :(
Comment #44
david_garcia CreditAttribution: david_garcia commentedThis might be overkill but...
The original concern over file_exists() performance related.
Using strpos means scanning through the whole template when this is not an inline template.
What about something like this?
Comment #45
star-szrWhen it's not an inline template $name is the name of the template, like "node.html.twig", or in a worse case something like "@node/node.html.twig". If we consider further optimizing this it should be in a follow-up IMO, this bug is a serious issue for Windows and other users.
Comment #46
david_garcia CreditAttribution: david_garcia commentedThat's true, only filenames will make it here. Looks good to go.
Comment #47
star-szrIf we think people will have really long inline templates then it's relevant but should still be follow up I think. Thanks!
Comment #50
star-szrUnrelated failure in migrate, @mdrummond mentioned earlier he'd seen that before so I am guessing it's a random fail we have.
Comment #52
star-szrSame fail, Drupal\user\Tests\Migrate\MigrateUserProfileEntityDisplayTest. @larowlan on IRC said that this is a known random segfault.
Comment #59
effulgentsia CreditAttribution: effulgentsia at Acquia commentedPushed to 8.0.x, with this additional interdiff applied on commit.
Comment #61
hatuhay CreditAttribution: hatuhay commentedDrupal 8.0.0.rc2, under Windows 10 Bitnamis framework.
Fresh installation worked OK, start installing modules and suddenly Bam!! no more Drupal 8.
Checked that patch is already applied on this version.
Rebuild caches, same error.
Same error for
block--system-branding-block
.Both files are generated on
sites/default/files/php/twig/
but cannot be renamed to its own folder.Comment #62
hatuhay CreditAttribution: hatuhay commentedComment #63
jhedstrom#61 doesn't appear to be the same issue as this (this issue was about file names, the file names in #61 look valid). @hatuhay could you file a new issue with steps to reproduce the issue if available?
Comment #64
hass CreditAttribution: hass commentedWhere is the followup? I see the same bug.
Comment #65
hubert_r2 CreditAttribution: hubert_r2 commentedI seem to have the same thing suddenly happening with 8.0.0 (windows 10)
Warning: rename(sites/drupal8-acquia.dd/files/php/twig/.4fc79a9d06,sites/drupal8-acquia.dd/files/php/twig/7754c0f9_status-messages.html.twig_68d30c89960f316b7d3c7db2b571b5a73aaf8c7e32649f091d44943a5c3ce5ba/d89b2148112336754491be6bd185430cd0aafadc74263ffc86f74c8430598d2c.php): No such file or directory in Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage->save() (line 91 of core\lib\Drupal\Component\PhpStorage\MTimeProtectedFastFileStorage.php).
Comment #66
star-szr#2606772: Long Twig cache directories can cause failures on some filesystems
Comment #67
drupalfan2 CreditAttribution: drupalfan2 commentedThis problem still seems to be part oft drupal 8.0.1.
What can I do?
Comment #68
mikeker CreditAttribution: mikeker as a volunteer commentedSee the issue referenced above. What you are seeing is not this issue, but one that gives a similar error.
Comment #69
emena CreditAttribution: emena commentedI still have the problem in 8.0.2
Comment #70
mikeker CreditAttribution: mikeker as a volunteer commented@emena: You'll need to give us more information for us to be able to help you.
Also, if you're on Windows, you're likely seeing this issue: #2606772: Long Twig cache directories can cause failures on some filesystems, which results in a similar error but has a different cause.