]> granicus.if.org Git - php/commitdiff
Fix #77812: Interactive mode does not support PHP 7.3-style heredoc
authorChristoph M. Becker <cmbecker69@gmx.de>
Fri, 23 Aug 2019 11:59:10 +0000 (13:59 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Fri, 23 Aug 2019 11:59:10 +0000 (13:59 +0200)
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.

NEWS
ext/readline/readline_cli.c
ext/readline/tests/bug77812-libedit.phpt [new file with mode: 0644]
ext/readline/tests/bug77812-readline.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index eda4a46ed23ecc7e360fc9a67eac7519625fa95a..0e6efd76cd18bb4653922c469abd0a4c95f99c0b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ PHP                                                                        NEWS
     property). (Nikita)
   . Fixed bug #78441 (Parse error due to heredoc identifier followed by digit).
     (cmb)
+  . Fixed bug #77812 (Interactive mode does not support PHP 7.3-style heredoc).
+    (cmb, Nikita)
 
 - Intl:
   . Ensure IDNA2003 rules are used with idn_to_ascii() and idn_to_utf8()
index 69ebe117cb16110dc585b2ce3caa197a131eea51..6e6e9161be452284f52d87c4c3eae53971b2de43 100644 (file)
@@ -347,11 +347,14 @@ static int cli_is_valid_code(char *code, size_t len, zend_string **prompt) /* {{
                                }
                                break;
                        case heredoc:
-                               if (code[i - (heredoc_len + 1)] == '\n' && !strncmp(code + i - heredoc_len, heredoc_tag, heredoc_len) && code[i] == '\n') {
-                                       code_type = body;
-                               } else if (code[i - (heredoc_len + 2)] == '\n' && !strncmp(code + i - heredoc_len - 1, heredoc_tag, heredoc_len) && code[i-1] == ';' && code[i] == '\n') {
+                               if (!strncmp(code + i - heredoc_len + 1, heredoc_tag, heredoc_len)) {
+                                       unsigned char c = code[i + 1];
+                                       char *p = code + i - heredoc_len;
+
+                                       if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || c >= 0x80) break;
+                                       while (*p == ' ' || *p == '\t') p--;
+                                       if (*p != '\n') break;
                                        code_type = body;
-                                       valid_end = 1;
                                }
                                break;
                        case outside:
diff --git a/ext/readline/tests/bug77812-libedit.phpt b/ext/readline/tests/bug77812-libedit.phpt
new file mode 100644 (file)
index 0000000..478274a
--- /dev/null
@@ -0,0 +1,34 @@
+--TEST--
+Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc)
+--SKIPIF--
+<?php
+if (!extension_loaded('readline')) die('skip readline extension not available');
+if (READLINE_LIB !== "libedit") die('skip libedit only');
+if (!function_exists('proc_open')) die('skip proc_open() not available');
+?>
+--FILE--
+<?php
+$php = getenv('TEST_PHP_EXECUTABLE');
+$ini = getenv('TEST_PHP_EXTRA_ARGS');
+$descriptorspec = [['pipe', 'r'], STDOUT, STDERR];
+$proc = proc_open("$php $ini -a", $descriptorspec, $pipes);
+var_dump($proc);
+fwrite($pipes[0], "echo <<<FOO\n    bar\n    FOO;\n");
+fwrite($pipes[0], "print(<<<FOO\nxx\nFOO);\n");
+fwrite($pipes[0], "echo <<<FOO\n    xxx\n    FOO;\nFOO\n;\n");
+fwrite($pipes[0], "echo <<<FOO\nFOOL\nFOO\n,1;\n");
+fwrite($pipes[0], "echo <<<FOO\nFOO4\nFOO\n,2;\n");
+fclose($pipes[0]);
+proc_close($proc);
+?>
+--EXPECTF--
+resource(%d) of type (process)
+Interactive shell
+
+bar
+xx
+xxx
+
+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
+FOOL1
+FOO42
diff --git a/ext/readline/tests/bug77812-readline.phpt b/ext/readline/tests/bug77812-readline.phpt
new file mode 100644 (file)
index 0000000..32d9f4d
--- /dev/null
@@ -0,0 +1,54 @@
+--TEST--
+Bug #77812 (Interactive mode does not support PHP 7.3-style heredoc)
+--SKIPIF--
+<?php
+if (!extension_loaded('readline')) die('skip readline extension not available');
+if (READLINE_LIB !== "readline") die('skip readline only');
+if (!function_exists('proc_open')) die('skip proc_open() not available');
+?>
+--FILE--
+<?php
+$php = getenv('TEST_PHP_EXECUTABLE');
+$ini = getenv('TEST_PHP_EXTRA_ARGS');
+$descriptorspec = [['pipe', 'r'], STDOUT, STDERR];
+$proc = proc_open("$php $ini -a", $descriptorspec, $pipes);
+var_dump($proc);
+fwrite($pipes[0], "echo <<<FOO\n    bar\n    FOO;\n");
+fwrite($pipes[0], "print(<<<FOO\nxx\nFOO);\n");
+fwrite($pipes[0], "echo <<<FOO\n    xxx\n    FOO;\nFOO\n;\n");
+fwrite($pipes[0], "echo <<<FOO\nFOOL\nFOO\n,1;\n");
+fwrite($pipes[0], "echo <<<FOO\nFOO4\nFOO\n,2;\n");
+fclose($pipes[0]);
+proc_close($proc);
+?>
+--EXPECTF--
+resource(%d) of type (process)
+Interactive shell
+
+php > echo <<<FOO
+<<< >     bar
+<<< >     FOO;
+bar
+php > print(<<<FOO
+<<< > xx
+<<< > FOO);
+xx
+php > echo <<<FOO
+<<< >     xxx
+<<< >     FOO;
+xxx
+php > FOO
+php > ;
+
+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
+php > echo <<<FOO
+<<< > FOOL
+<<< > FOO
+php > ,1;
+FOOL1
+php > echo <<<FOO
+<<< > FOO4
+<<< > FOO
+php > ,2;
+FOO42
+php >