I'm working on a large website and am often getting this warning:
Warning: preg_match(): Compilation failed: regular expression is too large at offset 39102 in drupal_match_path() (row 331 of includes/path.inc).
This is caused by the memory limit that is imposed on regexes by the pcre.backtrack_limit setting in php.ini. By default this is set to 1MB, and if this limit is exceeded while the regex is being processed, the warning is given and the function returns FALSE. Apart from the warning this causes unexpected behaviour since the paths are not being matched correctly.
A good solution would be to split large regexes into smaller chunks so this memory limit is never exceeded.
Comments
Comment #1
pfrenssenHere is a test that exposes the problem on a vanilla PHP 5.4.6 install, and a patch that fixes the problem.
Comment #2
pfrenssenDrupal 8-versions of the patch and test. These also contain some small improvements to the patch which should be backported to the D7 version above.
Comment #3
domidc commentedPatch reviewed. Looks good.
Comment #4
catchI'm not sure why we need to support such a massive string in drupal_match_path(). Could you post the real-life string that this is breaking on?
Comment #5
pfrenssenThe test uses a truly gigantic string but this was just to make sure the test fails on the test bot regardless of the settings of
pcre.backtrack_limit. In real life I'm seeing this fail on much smaller strings.I have included an example pattern string that causes my website to break. The site is using Spaces with the PURL module. To be able to show all admin paths in the admin theme all admin paths are duplicated for every Space, and this causes the patterns list to grow dramatically. At first we increased the
pcre.backtrack_limitbut this is not a sustainable situation as the number of Spaces will continue to grow and we will eventually hit this limit again.I think drupal_match_path() should always return a valid result, regardless of pattern size and PHP settings.
Comment #6
pfrenssenSetting back to needs review, also changing title because this will always break at some point regardless of PHP settings.
Comment #7
catchOK thanks for posting the example. I'm afraid I don't think this is a good use-case at all for drupal_match_path(). You could implement hook_block_list_alter() and affect visibility that way without running into the pcre limit. Moving this to 'works as designed'.
Comment #8
pfrenssenThe admin paths are determined with path_is_admin(), this has not much to do with block visibility settings or hook_block_list_alter().
I think at least that if it is intentional that drupal_match_path() breaks on large patterns that this should be documented.
Comment #9
catchSo if the use case is to only show a block on path_is_admin(), then it should be entirely possible to add a checkbox to block configuration to only show on admin paths, then in hook_block_list_alter() just check the value of that checkbox vs. path_is_admin() - then you're not copying a vast list of paths into the block visibility.
Comment #10
pfrenssen@catch, Sorry I missed you on IRC, I had changed nicks and didn't get your ping.
I'm really not trying to do anything with blocks :) My use case is to show all admin screens (for example /admin/config, /node/add) in the admin theme (Seven). To support this in Spaces and PURL all admin paths need to be prefixed with the names of the Spaces (/space1/admin/config, /space2/admin/config etc) using hook_admin_path(). See issue #1693984: Admin theme is not applied when using path prefix.
I can understand your hesitation though as this is not terribly clean. Maybe I can take a look at how this is handled in the i18n modules since these also deal with path prefixes.
Comment #11
pfrenssenJust a followup for people that might hit this error message. The actual problem I was dealing with was that path_is_admin() was being called early in the bootstrap, before hook_init() was invoked. During purl_init() the current path is rewritten to the normal Drupal paths so from this point onwards path_is_admin() would return correct results.
I just had to address this one instance where path_is_admin() is called before hook_init(): in system_custom_theme(), invoked by menu_set_custom_theme(). I implemented my own hook_custom_theme() and the problem was solved.
Comment #12
xmacinfoI also get this problem. We have a large site where publishers use block visibility on a lot of paths. Between 31000 and 32000 characters, the visibility will return false without warning.
Any chance we see that 1783704-1-drupal_match_path_memory.patch commited? Or at least reviewed?
Comment #13
ajay gadhavana commentedSame here I have more than 600 URLs in which I wanted to hide particular block but its giving error in dblog
Warning: preg_match(): Compilation failed: regular expression is too large at offset **** in drupal_match_path() (line 331 of /var/www/html/sitename/includes/path.inc) any chance to solve this ?
Comment #14
ajay gadhavana commentedFinally I found solution, Might be its not solution but its working fine for me.
When you are adding URLS in block, in backend its matching urls using preg_match so if you are adding lots of URL this is giving error. Solution is instead of adding URL add node id like "node/1212"
Logic is url length is bigger than "node/1231" so its reduce preg_match content
Comment #15
xmacinfoThis is a good workaround, but we'd still need a better fix.