:: in .info files causes Fatal error
ExTexan - April 5, 2009 - 15:21
| Project: | Drupal |
| Version: | 6.x-dev |
| Component: | base system |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | needs review |
Description
Following the very detailed (and very helpful) instructions for creating a new sub-theme for Zen, I got down to modifying the .info file (mine is litdep.info). I changed the breadcrumb separator as follows:
settings[zen_breadcrumb_separator] = ' :: 'When I refreshed my front page, I got the following error:
Fatal error: Class ' ' not found in C:\Users\Doug\Webs\Drupal-Test\includes\common.inc on line 3551
Changing the separator back to ">" fixed the error.

#1
Yes, that’s very annoying. The syntax of the .info file doesn’t allow you to put a :: in it. :-( [edit: this is a bug in Drupal core.]
Fortunately, there's a workaround. Use an HTML escape sequence for the semi-colon, :
settings[zen_breadcrumb_separator] = ' :: '#2
Automatically closed -- issue fixed for 2 weeks with no activity.
#3
Why do issues automatically close? Seems to me they should only be closed manually when a solution is found and implemented.
#4
ExTexan, issues are automatically moved from "fixed" to "closed" after 2 weeks of inactivity. "Fixed" issues remain in the list of open issues so that other users can more easily see them, but "closed" ones can still be searched for.
I marked this issue "fixed" in comment #1 because I provided the solution.
#5
Yes, I understand that you provided a "work-around". But even so, I don't think something should remain in Drupal if it can crash the site as hard as this "bug" does. As I recall, the error message when it crashed wasn't even all that helpful in determining the cause. I had to spend way too much time retracing what I had done in order to pinpoint the cause.
If you can put forth a valid argument as to why an issue that crashes Drupal should be "closed", then I'm all ears.
#6
I meant it wasn't a bug in Zen. But I'm happy to move it over to the main Drupal core issue queue.
Because it means having to re-write the way .info files are formatted, it won't ever be fixed in D6. And D7's code freeze is on Sept 1.
#7
I see. Thanks for the clarification (Zen vs Drupal core). That makes sense. Hard to believe such a minor thing could cause such a hard failure in Drupal. Thanks for moving the issue to the proper place.
Cheers...
#8
Looks like the issue occurs during this call in common.inc (while parsing the .info files), where Drupal checks to see if any of the values in the .info file might be constants:
<?php// Handle PHP constants
if (defined($value)) {
$value = constant($value);
}
?>
Since PHP 5, the 'defined'-function can be used for class constants as well as 'normal' constants, and when it encounters '::' it expects a class + constant (it will also return a fatal error in case the class exists but the constant doesn't).
Attached is a patch that fixes this bug. Longer term, maybe we should consider using token replacements or something similar for the PHP constant replacements in the .info files.
The patch fetches a list of defined constants and checks against that list instead of using the 'defined' function. Besides no longer throwing fatal errors, some rudimentary tests show that this is about 40% faster than using defined (confirmation).
#13
Following some issue cleanup, I like the patch, but a) please use isset not array_key_exists b) write a test. I would write a test module and a text file and then var_exports the results of the parse into an unthemed page. The reason for this would be that fatal errors should not be tested in the process space of the parent Drupal but in the child.
#14
Thanks chx for the info on 7.x. Sorry to say though, I don't really understand this:
Can you elaborate (in newbie terms)? Thanks.
#15
ExTexan, I already unpublished several comments of yours on this issue. If you want to learn Drupal coding and test writing, I am eager to help you on IRC but not in this issue.
#16
New patch attached:
The test was built according to chx's guidance (#13 and IRC). I originally used eval to parse the output of 'common-test/drupal-parse-info-file' back to a PHP variable, but using eval proved to be to cumbersome (and it can still take down the parent Drupal instance), not to mention that it's probably bad practice to use it anyway, so I've settled for plain text assertions instead...
#17
Follow-up patch after talking to chx on IRC:
#18
Almost ready, but +class ParseInfoFilesTestCase extends DrupalWebTestCase { needs a doxygen.
#19
Now with additional Doxygen thingy :)
#20
I am so sorry for not catching this before but + $this->assertRaw("'simple_constant' => 6", t('Constant value was parsed correctly.'), t('System'));
this should use the constant instead of its value I think. "'simple_constant' => ". WATCHDOG_INFO
#21
No problem at all. I choose WATCHDOG_INFO to have a constant that would be around for a long time and doesn't change much over time, but it didn't occur to me to include the same constant in the assertion. Doh.
New patch attached...
#22
I like this patch very much. Is this our first fatal error testing? I think it is.
#23
Hm. Can I ask why an entire module with a menu callback was created for this, rather than just checking the results of drupal_get_path('module', 'simpletest') . '/tests/common_test_info.txt'); directly in the assertions?
(Hint: that means we need to document why that is, if it's intended ;))
#24
You can certainly ask :). I wondered about documentating this, but I have to admit that I don't know how to best phrase this... It boils down to something like this:
The extra module is necessary since a failed test might throw a fatal exception, halting further test processing. By moving it to its own module, the fatal error (if it occurs) is thrown in the child process instead of in the parent (testrunner) process, and it can be detected and handled cleanly without hindering other tests.
Here's chx's earlier quote describing the need for a separate module:
I think this way of working is similar to what is used in #469768: PASS.
#25
Would this be ok as documentation at the start of common_test.module:
#26
The last submitted patch failed testing.
#27
Re-rolled after changes to HEAD, and incorporated some documentation into common_test.module to explain the reasoning behind the use of a separate module.
#28
The last submitted patch failed testing.
#29
#30
The new comments look better. Couple of minor code style things:
+ * @file+ * A test module to assist in testing common.inc.
+ * This module can be used whenever a test might potentially throw a fatal error. By
Should probably be a line break between the first line and the rest of the description.
++/**
+ * Implementation of hook_menu().
This is now "Implement hook_menu() in core.
#31
Thanks, new patch attached with the code style changes mentioned in #30.
#32
Looks good now, back to RTBC.
#33
I'm not sure I understand why we create a new module for this. There is a lot of code that can throw fatal errors, and when that happens, we need to debug it either way. We improved reporting of fatal errors so this should be reasonably easy to do. Still feels like overkill to me.
#34
The last submitted patch failed testing.
#35
Setting to RTBC - testbot was broken.
#36
Setting to 'needs review' because of #33. I'm not convinced this is the proper approach.
#37
The last submitted patch failed testing.
#38
Re-rolled. Dropped the extra module all-together in favor of just a unit test.
#39
The last submitted patch failed testing.
#40
subscribing -- after submitting a duplicate issue in http://drupal.org/node/430166
#41
This just killed contrib testing, lets get this in, eh? Re-roll and confirmation it worked on d6.
#42
Stripped t() from getInfo().
#43
D6 patch.
#44
Cool. This approach makes a lot more sense than adding the overhead of a new module. And we can extend this tests in the text file to put other things that might break the .info file parser in the future.
Committed to HEAD! Thanks!
Marking back down to 6.x.
#45
I'm not getting why we invoke constant() when we already have the value of the constant in an array key. Looks to be no reason for that.
#46
@Gabor:
The original issue was defined() choking on keys with double colons in them, so the "check to see if we're dealing with a constant"-logic was altered, the rest (including actually loading the value of the constant) was left untouched.
From a DX perspective I actually prefer the current solution, performance-wise it looks like re-using the array is 2-3 times faster compared to loading the value via constant().
I don't really care whether we replace constant() or leave it in place... Patch attached in case looking up the value in the array is prefered over the use of the function.
#47
If it's faster, let's do it...
#48
Committed to CVS HEAD. Thanks!
#49
Ok, let's port this updated approach to D6.
#50
Merged #43 and #46 together.