Skip to content

Commit

Permalink
Fix/improve handling of escaping in ini parser
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dryabov authored and nikic committed Aug 30, 2021
1 parent 15ba73c commit d3a6054
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 10 deletions.
22 changes: 13 additions & 9 deletions Zend/zend_ini_scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -591,31 +591,35 @@ end_raw_value_chars:
return 0;
}

while (YYCURSOR < YYLIMIT) {
switch (*YYCURSOR++) {
unsigned char *s = SCNG(yy_text);

while (s < YYLIMIT) {
switch (*s++) {
case '"':
if (YYCURSOR < YYLIMIT && YYCURSOR[-2] == '\\' && *YYCURSOR != '\r' && *YYCURSOR != '\n') {
continue;
}
break;
case '$':
if (*YYCURSOR == '{') {
if (s < YYLIMIT && *s == '{') {
break;
}
continue;
case '\\':
if (YYCURSOR < YYLIMIT && *YYCURSOR != '"') {
YYCURSOR++;
if (s < YYLIMIT) {
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;
default:
continue;
}

YYCURSOR--;
s--;
break;
}

YYCURSOR = s;
yyleng = YYCURSOR - SCNG(yy_text);

zend_ini_escape_string(ini_lval, yytext, yyleng, '"');
Expand Down
11 changes: 11 additions & 0 deletions ext/standard/tests/general_functions/parse_ini_basic.data
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,14 @@ ini-with.hyphen = hyphen and dot
[windows paths]
winpath1="c:\some windows\path\test\new\r\quote \" here\single ' quote\some more"
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"
18 changes: 17 additions & 1 deletion ext/standard/tests/general_functions/parse_ini_basic.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var_dump(parse_ini_file($ini_file, 1));
echo "Done.\n";
?>
--EXPECT--
array(26) {
array(27) {
["basic"]=>
array(15) {
["basicval"]=>
Expand Down Expand Up @@ -279,5 +279,21 @@ array(26) {
["winpath2"]=>
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.

0 comments on commit d3a6054

Please sign in to comment.