PHP: Fixed closing tag issue (#1652) This fixes that PHP's closing tag (`?>`) was detected inside strings and comments.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
diff --git a/components/prism-php.js b/components/prism-php.js
index 8f3498d..fc10e36 100644
--- a/components/prism-php.js
+++ b/components/prism-php.js
@@ -35,11 +35,14 @@
}
});
- Prism.languages.insertBefore('php', 'keyword', {
+ Prism.languages.insertBefore('php', 'comment', {
'delimiter': {
- pattern: /\?>|<\?(?:php|=)?/i,
+ pattern: /\?>$|^<\?(?:php(?=\s)|=)?/i,
alias: 'important'
- },
+ }
+ });
+
+ Prism.languages.insertBefore('php', 'keyword', {
'variable': /\$+(?:\w+\b|(?={))/i,
'package': {
pattern: /(\\|namespace\s+|use\s+)[\w\\]+/,
@@ -114,11 +117,11 @@
delete Prism.languages.php['string'];
Prism.hooks.add('before-tokenize', function(env) {
- if (!/(?:<\?php|<\?)/ig.test(env.code)) {
+ if (!/<\?/.test(env.code)) {
return;
}
- var phpPattern = /(?:<\?php|<\?)[\s\S]*?(?:\?>|$)/ig;
+ var phpPattern = /<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#)(?:[^?\n\r]|\?(?!>))*|\/\*[\s\S]*?(?:\*\/|$))*?(?:\?>|$)/ig;
Prism.languages['markup-templating'].buildPlaceholders(env, 'php', phpPattern);
});
@@ -126,4 +129,4 @@
Prism.languages['markup-templating'].tokenizePlaceholders(env, 'php');
});
-}(Prism));
\ No newline at end of file
+}(Prism));
diff --git a/components/prism-php.min.js b/components/prism-php.min.js
index 999111b..cb0060e 100644
--- a/components/prism-php.min.js
+++ b/components/prism-php.min.js
@@ -1 +1 @@
-!function(e){e.languages.php=e.languages.extend("clike",{keyword:/\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|new|or|parent|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,"boolean":{pattern:/\b(?:false|true)\b/i,alias:"constant"},constant:[/\b[A-Z_][A-Z0-9_]*\b/,/\b(?:null)\b/i],comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0}}),e.languages.insertBefore("php","string",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),e.languages.insertBefore("php","keyword",{delimiter:{pattern:/\?>|<\?(?:php|=)?/i,alias:"important"},variable:/\$+(?:\w+\b|(?={))/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),e.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}});var n={pattern:/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[.+?]|->\w+)*)/,lookbehind:!0,inside:{rest:e.languages.php}};e.languages.insertBefore("php","string",{"nowdoc-string":{pattern:/<<<'([^']+)'(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;/,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},"heredoc-string":{pattern:/<<<(?:"([^"]+)"(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;|([a-z_]\w*)(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\2;)/i,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:n}},"single-quoted-string":{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,alias:"string",inside:{interpolation:n}}}),delete e.languages.php.string,e.hooks.add("before-tokenize",function(n){if(/(?:<\?php|<\?)/gi.test(n.code)){var t=/(?:<\?php|<\?)[\s\S]*?(?:\?>|$)/gi;e.languages["markup-templating"].buildPlaceholders(n,"php",t)}}),e.hooks.add("after-tokenize",function(n){e.languages["markup-templating"].tokenizePlaceholders(n,"php")})}(Prism);
\ No newline at end of file
+!function(e){e.languages.php=e.languages.extend("clike",{keyword:/\b(?:__halt_compiler|abstract|and|array|as|break|callable|case|catch|class|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|eval|exit|extends|final|finally|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|namespace|new|or|parent|print|private|protected|public|require|require_once|return|static|switch|throw|trait|try|unset|use|var|while|xor|yield)\b/i,"boolean":{pattern:/\b(?:false|true)\b/i,alias:"constant"},constant:[/\b[A-Z_][A-Z0-9_]*\b/,/\b(?:null)\b/i],comment:{pattern:/(^|[^\\])(?:\/\*[\s\S]*?\*\/|\/\/.*)/,lookbehind:!0}}),e.languages.insertBefore("php","string",{"shell-comment":{pattern:/(^|[^\\])#.*/,lookbehind:!0,alias:"comment"}}),e.languages.insertBefore("php","comment",{delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"}}),e.languages.insertBefore("php","keyword",{variable:/\$+(?:\w+\b|(?={))/i,"package":{pattern:/(\\|namespace\s+|use\s+)[\w\\]+/,lookbehind:!0,inside:{punctuation:/\\/}}}),e.languages.insertBefore("php","operator",{property:{pattern:/(->)[\w]+/,lookbehind:!0}});var n={pattern:/{\$(?:{(?:{[^{}]+}|[^{}]+)}|[^{}])+}|(^|[^\\{])\$+(?:\w+(?:\[.+?]|->\w+)*)/,lookbehind:!0,inside:{rest:e.languages.php}};e.languages.insertBefore("php","string",{"nowdoc-string":{pattern:/<<<'([^']+)'(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;/,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},"heredoc-string":{pattern:/<<<(?:"([^"]+)"(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\1;|([a-z_]\w*)(?:\r\n?|\n)(?:.*(?:\r\n?|\n))*?\2;)/i,greedy:!0,alias:"string",inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:n}},"single-quoted-string":{pattern:/'(?:\\[\s\S]|[^\\'])*'/,greedy:!0,alias:"string"},"double-quoted-string":{pattern:/"(?:\\[\s\S]|[^\\"])*"/,greedy:!0,alias:"string",inside:{interpolation:n}}}),delete e.languages.php.string,e.hooks.add("before-tokenize",function(n){if(/<\?/.test(n.code)){var t=/<\?(?:[^"'\/#]|\/(?![*\/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#)(?:[^?\n\r]|\?(?!>))*|\/\*[\s\S]*?(?:\*\/|$))*?(?:\?>|$)/gi;e.languages["markup-templating"].buildPlaceholders(n,"php",t)}}),e.hooks.add("after-tokenize",function(n){e.languages["markup-templating"].tokenizePlaceholders(n,"php")})}(Prism);
\ No newline at end of file
diff --git a/tests/languages/markup+php/issue1582.test b/tests/languages/markup+php/issue1582.test
new file mode 100644
index 0000000..255f97e
--- /dev/null
+++ b/tests/languages/markup+php/issue1582.test
@@ -0,0 +1,23 @@
+<?php
+
+ echo '<?xml version="1.0" encoding="UTF-8"?><tracker />';
+ echo PHP_EOL;
+
+----------------------------------------------------
+
+[
+ ["php", [
+ ["delimiter", "<?php"],
+ ["keyword", "echo"],
+ ["single-quoted-string", "'<?xml version=\"1.0\" encoding=\"UTF-8\"?><tracker />'"],
+ ["punctuation", ";"],
+ ["keyword", "echo"],
+ ["constant", "PHP_EOL"],
+ ["punctuation", ";"]
+ ]]
+]
+
+----------------------------------------------------
+
+Checks for PHP closing tags '?>' inside of strings.
+See #1582 for details.
diff --git a/tests/languages/markup+php/php_with_closing_tag_in_markup_feature.test b/tests/languages/markup+php/php_with_closing_tag_in_markup_feature.test
new file mode 100644
index 0000000..8067d7c
--- /dev/null
+++ b/tests/languages/markup+php/php_with_closing_tag_in_markup_feature.test
@@ -0,0 +1,44 @@
+<?php
+
+ // '
+ # "
+ //*
+ echo '?>' + "?>"; /* ?> */
+ echo PHP_EOL;
+ // */
+ // ?>
+
+<?php # ?>
+
+----------------------------------------------------
+
+[
+ ["php", [
+ ["delimiter", "<?php"],
+ ["comment", "// '"],
+ ["shell-comment", "# \""],
+ ["comment", "//*"],
+ ["keyword", "echo"],
+ ["single-quoted-string", "'?>'"],
+ ["operator", "+"],
+ ["double-quoted-string", ["\"?>\""]],
+ ["punctuation", ";"],
+ ["comment", "/* ?> */"],
+ ["keyword", "echo"],
+ ["constant", "PHP_EOL"],
+ ["punctuation", ";"],
+ ["comment", "// */"],
+ ["comment", "// "],
+ ["delimiter", "?>"]
+ ]],
+
+ ["php", [
+ ["delimiter", "<?php"],
+ ["shell-comment", "# "],
+ ["delimiter", "?>"]
+ ]]
+]
+
+----------------------------------------------------
+
+Checks for PHP closing tags '?>' inside of strings and comments.
diff --git a/tests/languages/php/delimiter_feature.test b/tests/languages/php/delimiter_feature.test
index 15bd9a8..f7bd684 100644
--- a/tests/languages/php/delimiter_feature.test
+++ b/tests/languages/php/delimiter_feature.test
@@ -1,6 +1,6 @@
<? ?>
<?php ?>
-<?= ?>
+<?= // ?>
----------------------------------------------------
@@ -15,10 +15,11 @@
]],
["php", [
["delimiter", "<?="],
+ ["comment", "// "],
["delimiter", "?>"]
]]
]
----------------------------------------------------
-Checks for delimiters.
\ No newline at end of file
+Checks for delimiters.