Problem/Motivation
fnmatch() is not available in PHP on all platforms.
Proposed resolution
Replace usages of fnmatch() with preg_match().
Remaining tasks
User interface changes
none
API changes
none
Data model changes
none
Original Report
Trying to start the drupal installation process, but I keep running into a WSOD before the installation script even starts. After enabling error reporting in my server's php.ini I now get the following fatal error:
Fatal error: Call to undefined function Drupal\Core\Config\fnmatch() in /share/MD0_DATA/Web/drupal/core/lib/Drupal/Core/Config/InstallStorage.php on line 233
I thought I should share this. Any help is appreciated. I am not familiar with drupal development, but I hope this is the right place to share.
Comments
Comment #2
longwavefnmatch() is a built in PHP function: http://php.net/manual/en/function.fnmatch.php - though there is a note "Warning: For now, this function is not available on non-POSIX compliant systems except Windows."
What server/hosting platform and version of PHP are you using?
Comment #3
chapf commentedThanks for your reply.
Running php version 5.5.29 on an apache server version 2.2.31.
For now I'm testing on a local nas server running a custom linux (qnap qts 4.2).
This should be fine according to drupal 8 system requirements ...
Any suggestions?
Comment #4
chapf commentedWell, I tried installing a competing CMS on my system and it runs perfectly fine. The issue seems to be within drupal, also persists with version 8.0.1 !
Comment #5
chapf commentedComment #6
catch@chapf that's probably because the other CMS doesn't use fnmatch()
We can add a warning to the installer if the function isn't available, and add a note to http://drupal.org/requirements that it's required.
The PHP docs comments have suggested polyfills for when it's not available, could potentially look at that as well.
Comment #7
chapf commentedI guess any warning/error handling is better than running into a WSOD as long as there aren't any intentions to replace that particular function.
Comment #8
cilefen commentedA requirements check patch.
Comment #9
cilefen commented#8 may not work if the installer can't make it there. This check may have to go in install.php the way it was done in #2421451-14: Drupal needs comments in opcache.
Comment #10
alexpott@cilefen I think it might be possible to not use this function and use preg_match() or something similar.
Comment #11
alexpottWe could then open a followup to add this to the list of functions that the phpcs rules provided by Coder say we shouldn't use.
Comment #12
cilefen commentedThis is one of six usages.
Comment #14
cilefen commentedComment #16
cilefen commentedThis is still wrong and the config import test will fail.
Comment #17
cilefen commentedComment #19
alexpottCreated #2630270: fnmatch is not available on non-posix php builds (apart Windows) - let's add it to the list of not allowed methods
Comment #20
rsbecker commentedThis patch does not work for D8.0.3 because fnmatch() is now also called at
FileStorage.php line 211.
Perhaps it's time to fix this so those of us who cannot use fnmatch() don't have to patch every new version.
Comment #21
cilefen commented@rsbecker I am a little busy today but would you like to create the patch so this can be fixed?
Comment #22
cilefen commented@rsbecker Not sure what you mean. The patch in #17 contains the fix to FileStorage. The issue needs a review to get done.
Comment #23
rsbecker commentedSorry. I made a mistake. There is now a third place.
In the FileStorage.php file that shipped with 8.0.3, the changes are at 211, 222 and 314.
Comment #24
cilefen commentedThat is not what I see.
Comment #25
alexpottWith the patch in #17 applied I can't find any usages in core.
Comment #26
alexpottThis looks great. Let's get this done.
Comment #27
alexpottI think the usage of strtr() makes this a bit complex to read...
Comment #28
alexpottFurther to #27:
/^.*\.yml$/since what we want is just to check that the filename ends in.yml. The pattern for that is/\.yml$/Comment #29
dawehnerSo what actually provides this functionality. Is this some form of compiler flag?
It seems to be that QNAP for example strips down their PHP binary as much as possible I would guess there are more problems beside this function,
but let's see.
Nice simplification of the regex
Comment #30
xjmThanks @cilefen, @dawehner, and @alexpott for working on this!
So I looked at this and noticed we are making it case-insensitive (the
/i). Since case sensitivity definitely differs from environment to environment and so could have different results, I asked @alexpott about this choice. We looked at fnmatch() and it does have a flag for case insensitivity, but it is not the default, so this is changing the behavior. Marking NW for that.This also makes me think we should have test coverage for what we expect the results of these filename matches to be -- i.e., factor them out into a method, then have some data providers with unit tests for some different patterns. It doesn't necessarily need to block this issue, but it's worth discussing whether it should.
@alexpott also suggested it could be three separate issues for three separate tests: one for the config storages, one for Migrate, and one for CKeditor.
Comment #31
tstoecklerWow, impressive detective work @xjm!
I'm generally not a huge fan of the so-called "Drupalisms", but does it make sense to add a utility helper function for this á la
\Drupal\Component\Utility\Compatibility::fnMatch()(namespace/function name TBD, of course) ? Not sure myself, as this seems less of a common use-case than e.g.\Drupal\Component\Utility\Unicode::strlen()and friends, but OTOH it's one-less thing contrib authors would have to copy-paste. Thoughts?Comment #32
alexpottSo yep #30 is correct the
iis wrong. I think given that we're not changing behaviour in this issue we don't need to add extensive additional tests here BUT a followup issue sounds a good idea. Given the importance of the config FileStorage I've improved FileStorageTest to cover the untested assumptions in HEAD and this patch. HOWEVER, i suspect that config's database storage is case insensitive - which can be confirmed by doing\Drupal::service('config.storage')->listAll('System');and yep with a mysql or even postgres backend it is (because we're using a like query). So I think there should be a followup to make config storages behave the same way. Nice catch @xjm.Just to confirm
fnmatch()is case sensitive I did...Comment #33
alexpott@tstoeckler yeah I considered that too... but still a contrib author would have to learn the fnmatch needs to be Comptability::fnmatch() and we already added a warning to coder... #2630270: fnmatch is not available on non-posix php builds (apart Windows) - let's add it to the list of not allowed methods
Comment #34
alexpottAdded #2666954: StorageInterface::listAll() implementations are different as followup based on #33.
Comment #35
xjmShould we put an
@todofor #2666954: StorageInterface::listAll() implementations are different here?Comment #36
alexpott@xjm I don't think so - depending on what we choose the tests will either break or continue to be affective.
Comment #37
xjm@alexpott I'd agree with you if the title of this issue were something like "Config storage is case-sensitive". However, it is not directly in scope here. For that reason, to me, one shouldn't be expected to
git blameto know why the test is there. So I'd prefer a comment explaining that it's a known issue that the case sensitivity does not extend to certain databases. :)Edit: or in other words, there is a difference between why the test is there and why the test was added. VCS should be used for the latter. The former however needs code documentation, and we all know about
@todoswithout issues. ;)Not a big deal either way I guess, but meh. At least having the test coverage is a big step. What it doesn't cover though is the database-specific case insensitivity part targeted for the followup (and not this issue, therefore not in the commit history).
Anyway, I agree that retaining the case-sensitive behavior seems like the correct course for now.
Comment #38
alexpottAdding an @todo
Comment #39
longwaveThe regular expressions all look okay to me and I think this covers @xjm's concern from #37 now.
Comment #40
alexpott#2671708: Add a RegexDirectoryIterator is related
Comment #43
xjmStudied the regexes again and this looks good to me. Since this is fixing a major bug, let's get it into both 8.0.x and 8.1.x now. Then we can follow up with #2671708: Add a RegexDirectoryIterator and using that in 8.1.x.
Thanks @chapf for reporting this issue! Committed to 8.1.x and cherry-picked to 8.0.x