Skip to content

Commit 03c7749

Browse files
committed
Fix #77812: Interactive mode does not support PHP 7.3-style heredoc
As of PHP 7.3.0, the rules regarding the heredoc and nowdoc closing identifier have been relaxed. While formerly, the closing identifier was required to be placed at the beginning of a line and to be immediately followed by (a semicolon and) a line break, it may now be preceeded by whitespace, and may be followed by any non-word character. We adjust the recognition logic respectively.
1 parent c9d3194 commit 03c7749

File tree

4 files changed

+97
-4
lines changed

4 files changed

+97
-4
lines changed

NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ PHP NEWS
88
property). (Nikita)
99
. Fixed bug #78441 (Parse error due to heredoc identifier followed by digit).
1010
(cmb)
11+
. Fixed bug #77812 (Interactive mode does not support PHP 7.3-style heredoc).
12+
(cmb, Nikita)
1113

1214
- Intl:
1315
. Ensure IDNA2003 rules are used with idn_to_ascii() and idn_to_utf8()

ext/readline/readline_cli.c

+7-4
Original file line numberDiff line numberDiff line change
@@ -347,11 +347,14 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{
347347
}
348348
break;
349349
case heredoc:
350-
if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') {
351-
code_type = body;
352-
} else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') {
350+
if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) {
351+
unsigned char c = code[i + 1];
352+
char *p = code + i - heredoc_len;
353+
354+
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c >= 0x80) break;
355+
while (*p == ' ' || *p == '\t') p--;
356+
if (*p != '\n') break;
353357
code_type = body;
354-
valid_end = 1;
355358
}
356359
break;
357360
case outside:
+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('readline')) die('skip readline extension not available');
6+
if (READLINE_LIB !== "libedit") die('skip libedit only');
7+
if (!function_exists('proc_open')) die('skip proc_open() not available');
8+
?>
9+
--FILE--
10+
<?php
11+
$php = getenv('TEST_PHP_EXECUTABLE');
12+
$ini = getenv('TEST_PHP_EXTRA_ARGS');
13+
$descriptorspec = [['pipe', 'r'], STDOUT, STDERR];
14+
$proc = proc_open("$php $ini -a", $descriptorspec, $pipes);
15+
var_dump($proc);
16+
fwrite($pipes[0], "echo <<<FOO\n bar\n FOO;\n");
17+
fwrite($pipes[0], "print(<<<FOO\nxx\nFOO);\n");
18+
fwrite($pipes[0], "echo <<<FOO\n xxx\n FOO;\nFOO\n;\n");
19+
fwrite($pipes[0], "echo <<<FOO\nFOOL\nFOO\n,1;\n");
20+
fwrite($pipes[0], "echo <<<FOO\nFOO4\nFOO\n,2;\n");
21+
fclose($pipes[0]);
22+
proc_close($proc);
23+
?>
24+
--EXPECTF--
25+
resource(%d) of type (process)
26+
Interactive shell
27+
28+
bar
29+
xx
30+
xxx
31+
32+
Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d
33+
FOOL1
34+
FOO42
+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
--TEST--
2+
Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('readline')) die('skip readline extension not available');
6+
if (READLINE_LIB !== "readline") die('skip readline only');
7+
if (!function_exists('proc_open')) die('skip proc_open() not available');
8+
?>
9+
--FILE--
10+
<?php
11+
$php = getenv('TEST_PHP_EXECUTABLE');
12+
$ini = getenv('TEST_PHP_EXTRA_ARGS');
13+
$descriptorspec = [['pipe', 'r'], STDOUT, STDERR];
14+
$proc = proc_open("$php $ini -a", $descriptorspec, $pipes);
15+
var_dump($proc);
16+
fwrite($pipes[0], "echo <<<FOO\n bar\n FOO;\n");
17+
fwrite($pipes[0], "print(<<<FOO\nxx\nFOO);\n");
18+
fwrite($pipes[0], "echo <<<FOO\n xxx\n FOO;\nFOO\n;\n");
19+
fwrite($pipes[0], "echo <<<FOO\nFOOL\nFOO\n,1;\n");
20+
fwrite($pipes[0], "echo <<<FOO\nFOO4\nFOO\n,2;\n");
21+
fclose($pipes[0]);
22+
proc_close($proc);
23+
?>
24+
--EXPECTF--
25+
resource(%d) of type (process)
26+
Interactive shell
27+
28+
php > echo <<<FOO
29+
<<< > bar
30+
<<< > FOO;
31+
bar
32+
php > print(<<<FOO
33+
<<< > xx
34+
<<< > FOO);
35+
xx
36+
php > echo <<<FOO
37+
<<< > xxx
38+
<<< > FOO;
39+
xxx
40+
php > FOO
41+
php > ;
42+
43+
Warning: Use of undefined constant FOO - assumed 'FOO' (this will throw an Error in a future version of PHP) in php shell code on line %d
44+
php > echo <<<FOO
45+
<<< > FOOL
46+
<<< > FOO
47+
php > ,1;
48+
FOOL1
49+
php > echo <<<FOO
50+
<<< > FOO4
51+
<<< > FOO
52+
php > ,2;
53+
FOO42
54+
php >

0 commit comments

Comments
 (0)