Drupal Association members fund grants that make connections all over the world.
For Drupal 8, with the Dependency Injection Container we really, really want to compile the container configuration to a serialized form. Re-configuring the container on every page request would be on the scale of re-running hook_menu and hook_theme on every page request; that's simply not acceptable.
Symfony supports dumping that information to a couple of different forms, and we could add additional dump mechanisms, such as to JSON, or the database, or something. However, the fastest mechanism (and, incidentally, the easiest to debug) is to dump to PHP code, which can then simply be loaded off disk (cached in APC).
For Drupal 8, there's a strong push to use Twig for the template layer. That has many advantages, discussed elsewhere, but most of Twig's performance benefits come from its ability to compile templates to PHP code that can simply be executed. That, of course, requires generating PHP code, and there is no other compiled form available (as that would entirely defeat the purpose).
As we all know, generating PHP from Apache that gets executed by Apache is a security no-no. We are drawing the line between acceptable and unacceptable risk is where your directories are Apache writeable and at the same those written things are Apache executable. This risk is too big for us because both the write and the execute can happen outside of the Drupal realm. (See more at 5) )
For most Symfony2-based applications, that is no problem. Configuration changes are done by editing a config file and running a CLI command (using Symfony's Console component) that rebuilds the DIC, regenerates template files, etc. (It may be multiple commands, I don't know off hand, but that's irrelevant.)
For Drupal, we have this really big administrative area where people can change all sorts of things without editing a config file. That's rather the point of Drupal. That applies to important things like enabling modules, even if most configuration will be handled by CMI, not by the DIC. We also consider as a target market people who are making changes without shell access. And, we have this annoying problem that we really really care about security.
Basically, we run into another case of the classic 3-point balance: Performance, Security, Usability -- Pick two.
We need to find some way to resolve this. In general, we need to understand that we will *not* be able to entirely get all three of our wants (Security, Performance, Usability), so we are going to have to sacrifice at least some of all of them.
We provide a very small, very tight API, pluggable via settings.php (yes, this will be a different plugging mechanism) that can:
- Write PHP files
- Load PHP files
- Tell the rest of the system whether 1. is available.
The implementations we ship with are:
- Bare files. Works for shared hosts / devel sites where the same user runs Apache and owns the files and if you chmod every time you want to do an operation from the UI needing a write.
- A stream wrapper reading-writing PHP files with a header consisting of
<?php exit; ?>randomstring. This would be used mostly by shared hosts or no-staging installations.
- Perhaps a Phar storage and reader, Phar is native, code will be minimal and fast, same as native except the chmod will be done on one file only.
Before #78, we had the following, competing proposals:
1) Say that certain changes, those that would affect the DIC, may only be made if you have shell access. Yes, that would include enabling/disabling modules. Pro: Neatly avoids the problem. Con: Neatly kills a large chunk of Drupal's flexibility.
2) Dump DIC information to JSON, YAML, or some other non-executable format. Symfony has support for this, so we just need to choose or write a backend. Pro: We're not writing anything more dangerous to disk than CMI files will be. Con: Doesn't help Twig at all, and is slower than PHP code.
3) Dump DIC and Twig files to the database, and write a stream wrapper that lets us include() them straight out of there. Pros: Very elegant for the rest of the system, and should be reasonably easy to do. Con: I have no idea if the performance of that would be any good, or if it's as bad as eval(). Introduces an extremely early database dependency, and in turn makes putting the database connection in the DIC a circular problem.
4) Require themes to come with pre-compiled Twig files. If you're editing a theme, you need to rerun the compile script. Pros: Neatly side-steps the security issue. Con: No idea if this screws with Twig's design because then compiled files would not all be in the same directory. Does nothing at all to help the DIC problem. Could make theme development more difficult, like it was before the "rebuild theme registry on ever page" checkbox was invented.
5) Use a stream wrapper to include files in the filesystem. This allows to add a random value to the beginning of the file (something like
exit; randomvalue where randomvalue is the same for every file and is settings.php / CMI stored ) so that an attacker can't upload a valid include (because the randomvalue is unknown). We can also, possibly, put them in a random directory CMI-style, although whether or not that's necessary is debatable. Pros: this is likely quite performant and usable too. Cons: the security here is debatable but it seems anyone able to exploit this would be able to exploit a Drupal without this subsystem as well.
Figure this out. :-)
User interface changes