I have this code to process a config file:
<?php
$config = '[log]
log_writers[] = "file"
log_writers[] = "screen"
[General]
maintenance_mode = 0
enable_browser_archiving_triggering = 0
enable_sql_optimize_queries = 0
force_ssl = 1';
echo preg_match_all( '/^maintenance_mode[ t]*=[ t]*d$/m', $config );
The echo displays 0
Updating the regex to:
echo preg_match_all( '/^maintenance_mode[ t]*=[ t]*ds$/m', $config );
results in the expected 1
WHY??
I even verified my sanity in regex101
https://regex101.com/r/CIxCkN/1
Local test environments:
RHEL 7
PHP 5.6.25
PCRE v8.32 2012-11-30
and
Windows Server 2022
PHP 8.2.7
PCRE v10.40 2022-04-14
Per comment request:
var_dump(base64_encode($config));
string(240) "W2xvZ10NCmxvZ193cml0ZXJzW10gPSAiZmlsZSINCmxvZ193cml0ZXJzW10gPSAic2NyZWVuIg0KDQpbR2VuZXJhbF0NCm1haW50ZW5hbmNlX21vZGUgPSAwDQplbmFibGVfYnJvd3Nlcl9hcmNoaXZpbmdfdHJpZ2dlcmluZyA9IDANCmVuYWJsZV9zcWxfb3B0aW1pemVfcXVlcmllcyA9IDANCmZvcmNlX3NzbCA9IDE="
var_dump(bin2hex($config));
string(358) "5b6c6f675d0d0a6c6f675f777269746572735b5d203d202266696c65220d0a6c6f675f777269746572735b5d203d202273637265656e220d0a0d0a5b47656e6572616c5d0d0a6d61696e74656e616e63655f6d6f6465203d20300d0a656e61626c655f62726f777365725f617263686976696e675f74726967676572696e67203d20300d0a656e61626c655f73716c5f6f7074696d697a655f71756572696573203d20300d0a666f7263655f73736c203d2031"
2
Answers
One answer would be that your string (or script generally) has Windows line-endings.
In multi-line mode,
d$
will only match a digit followed by an immediate newline (as determined by PCRE’s compile-time setting), which might not work if there was ar
hiding in there.Adding
s
at the end of your regex would match all line-ending characters, which explains why that helps in your affected test environments.For a fix (other than the
s
addition you’ve already found), PCRE lets you adjust which characters are matched as a newline using a modifier at the start of the string, e.g.(*ANYCRLF)
:See https://3v4l.org/vOUgM for a demo, and the Newline Conventions section of the PCRE docs for some detail.
Or alternatively, just use the newline character(s) in your string that PCRE is expecting locally.
And more generally, if you’re actually trying to parse the string/file in your question then a combination of
array_key_exists
andparse_ini_string/parse_ini_file
will make everything a lot cleaner.your config file does indeed have windows-newlines
rn
, the first part of your bin2hex5b6c6f675d0d0a
translates to[log]rn
which means @iainn’s hunch is correct 🙂Still though, i would have written that regex as
it’s just more robust that way, then doesn’t matter if you write it as
maintenance_mode=5
or
maintenance_mode =5
or
maintenance_mode= 5
or
maintenance_mode = 5
, and doesn’t matter if you use spaces or tabs, and doesn’t matter what your line endings are.