Fix/improve handling of escaping in ini parser

Quoting from UPGRADING:

- A leading dollar in a quoted string can now be escaped: "\${" will now be
  interpreted as a string with contents `${`.

- Backslashes in double quoted strings are now more consistently treated as
  escape characters. Previously, "foo\\" followed by something other than a
  newline was not considered as a teminated string. It is now interpreted as a
  string with contents `foo\`. However, as an exception, the string "foo\"
  followed by a newline will continue to be treated as a valid string with
  contents `foo\` rather than an unterminated string. This exception exists to
  support naive uses of Windows file pahts as "C:\foo\".

Closes GH-7420.
This commit is contained in:
Denis Ryabov 2021-08-28 16:30:36 +03:00 committed by Nikita Popov
parent 15ba73cee3
commit d3a6054d44
3 changed files with 41 additions and 10 deletions

View file

@ -591,31 +591,35 @@ end_raw_value_chars:
return 0; return 0;
} }
while (YYCURSOR < YYLIMIT) { unsigned char *s = SCNG(yy_text);
switch (*YYCURSOR++) {
while (s < YYLIMIT) {
switch (*s++) {
case '"': case '"':
if (YYCURSOR < YYLIMIT && YYCURSOR[-2] == '\\' && *YYCURSOR != '\r' && *YYCURSOR != '\n') {
continue;
}
break; break;
case '$': case '$':
if (*YYCURSOR == '{') { if (s < YYLIMIT && *s == '{') {
break; break;
} }
continue; continue;
case '\\': case '\\':
if (YYCURSOR < YYLIMIT && *YYCURSOR != '"') { if (s < YYLIMIT) {
YYCURSOR++; unsigned char escaped = *s++;
/* A special case for Windows paths, e.g. key="C:\path\" */
if (escaped == '"' && (s >= YYLIMIT || *s == '\n' || *s == '\r')) {
break;
}
} }
ZEND_FALLTHROUGH; ZEND_FALLTHROUGH;
default: default:
continue; continue;
} }
YYCURSOR--; s--;
break; break;
} }
YYCURSOR = s;
yyleng = YYCURSOR - SCNG(yy_text); yyleng = YYCURSOR - SCNG(yy_text);
zend_ini_escape_string(ini_lval, yytext, yyleng, '"'); zend_ini_escape_string(ini_lval, yytext, yyleng, '"');

View file

@ -130,3 +130,14 @@ ini-with.hyphen = hyphen and dot
[windows paths] [windows paths]
winpath1="c:\some windows\path\test\new\r\quote \" here\single ' quote\some more" winpath1="c:\some windows\path\test\new\r\quote \" here\single ' quote\some more"
winpath2="special case\" winpath2="special case\"
[characters escaping]
; Note: single-quoted strings don't support characters escaping, and the line below
; is single-quoted string, followed by unquoted text, followed by single-quoted '.'
single_quoted = 'She said \'Exactly my point\'.'
double_quoted = "She said \"Exactly my point\"."
double_quoted_2 = "Use \\\" to escape double quote"
double_quoted_multiline = "Lorem \"ipsum\"""
dolor"
dollar_test = "\${test}"
unescaped ="\n\r\t"

View file

@ -15,7 +15,7 @@ var_dump(parse_ini_file($ini_file, 1));
echo "Done.\n"; echo "Done.\n";
?> ?>
--EXPECT-- --EXPECT--
array(26) { array(27) {
["basic"]=> ["basic"]=>
array(15) { array(15) {
["basicval"]=> ["basicval"]=>
@ -279,5 +279,21 @@ array(26) {
["winpath2"]=> ["winpath2"]=>
string(13) "special case\" string(13) "special case\"
} }
["characters escaping"]=>
array(6) {
["single_quoted"]=>
string(28) "She said \Exactly my point\."
["double_quoted"]=>
string(28) "She said "Exactly my point"."
["double_quoted_2"]=>
string(29) "Use \" to escape double quote"
["double_quoted_multiline"]=>
string(20) "Lorem "ipsum"
dolor"
["dollar_test"]=>
string(7) "${test}"
["unescaped"]=>
string(6) "\n\r\t"
}
} }
Done. Done.