diff --git a/phpBB/phpbb/template/twig/extension/icon.php b/phpBB/phpbb/template/twig/extension/icon.php index 27807c9ecc..b2a98fad3f 100644 --- a/phpBB/phpbb/template/twig/extension/icon.php +++ b/phpBB/phpbb/template/twig/extension/icon.php @@ -125,6 +125,9 @@ class icon extends \Twig\Extension\AbstractExtension */ protected function prepare_svg(\Twig\TemplateWrapper $file) { + $code = $file->render(); + $code = preg_replace( "/<\?xml.+?\?>/", '', $code); + $doc = new \DOMDocument(); $doc->preserveWhiteSpace = false; @@ -132,7 +135,16 @@ class icon extends \Twig\Extension\AbstractExtension * Suppression is needed as DOMDocument does not like HTML5 and SVGs. * Options parameter prevents $dom->saveHTML() from adding an element. */ - @$doc->loadHTML($file->render(), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + @$doc->loadHTML($code, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD); + + // Remove any DOCTYPE + foreach ($doc->childNodes as $child) + { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) + { + $child->parentNode->removeChild($child); + } + } $xpath = new \DOMXPath($doc); diff --git a/tests/template/extension_test.php b/tests/template/extension_test.php index 0e9f2110ed..4e8a71b7a9 100644 --- a/tests/template/extension_test.php +++ b/tests/template/extension_test.php @@ -15,7 +15,7 @@ require_once dirname(__FILE__) . '/template_test_case.php'; class phpbb_template_extension_test extends phpbb_template_template_test_case { - protected function setup_engine(array $new_config = array()) + protected function setup_engine(array $new_config = []) { global $config, $phpbb_container, $phpbb_dispatcher, $phpbb_root_path, $phpEx; @@ -28,6 +28,7 @@ class phpbb_template_extension_test extends phpbb_template_template_test_case $lang_loader = new \phpbb\language\language_file_loader($phpbb_root_path, $phpEx); $this->lang = $lang = new \phpbb\language\language($lang_loader); $this->user = new \phpbb\user($lang, '\phpbb\datetime'); + $this->user->style['style_path'] = 'prosilver'; global $auth, $request, $symfony_request, $user; $user = new phpbb_mock_user(); @@ -73,7 +74,7 @@ class phpbb_template_extension_test extends phpbb_template_template_test_case $cache_path = $phpbb_root_path . 'cache/twig'; $context = new \phpbb\template\context(); - $loader = new \phpbb\template\twig\loader(''); + $loader = new \phpbb\template\twig\loader([]); $twig = new \phpbb\template\twig\environment( $config, $filesystem, @@ -82,12 +83,12 @@ class phpbb_template_extension_test extends phpbb_template_template_test_case null, $loader, new \phpbb\event\dispatcher($phpbb_container), - array( + [ 'cache' => false, 'debug' => false, 'auto_reload' => true, 'autoescape' => false, - ) + ] ); $this->template = new phpbb\template\twig\twig( $phpbb_path_helper, @@ -100,11 +101,16 @@ class phpbb_template_extension_test extends phpbb_template_template_test_case new \phpbb\template\twig\extension($context, $twig, $this->lang), new \phpbb\template\twig\extension\avatar(), new \phpbb\template\twig\extension\config($config), + new \phpbb\template\twig\extension\icon($this->user), new \phpbb\template\twig\extension\username(), ] ); $twig->setLexer(new \phpbb\template\twig\lexer($twig)); - $this->template->set_custom_style('tests', $this->template_path); + $this->template->set_style(); + $this->template->set_custom_style('tests', [ + $this->template_path, + $phpbb_root_path . 'styles/prosilver/template', + ]); } public function data_template_extensions() @@ -253,8 +259,166 @@ class phpbb_template_extension_test extends phpbb_template_template_test_case /** * @dataProvider data_template_extensions */ - public function test_get_user_avatar($file, $vars, $block_vars, $destroy_array, $expected, $lang_vars = []) + public function test_template_extensions($file, $vars, $block_vars, $destroy_array, $expected, $lang_vars = []) { $this->run_template($file, $vars, $block_vars, $destroy_array, $expected, $lang_vars); } + + public function data_template_icon_extension() + { + return [ + /** Font: default */ + [ + [ + 'type' => 'font', + 'icon' => 'phone', + 'title' => 'ICON_PHONE', + 'hidden' => false, + 'classes' => '', + 'attributes' => [], + ], + [ + 'ICON_PHONE' => 'Phone icon', + ], + 'Phone icon', + + ], + /** Font: all options */ + [ + [ + 'type' => 'font', + 'icon' => 'pencil', + 'title' => 'ICON_PENCIL', + 'hidden' => true, + 'classes' => 'a-class another-class', + 'attributes' => [ + 'data-attr-1' => 'true', + 'data-attr-2' => 'two', + ], + ], + [ + 'ICON_PENCIL' => 'Pencil icon', + ], + ' + Pencil icon' + ], + /** PNG: default */ + [ + [ + 'type' => 'png', + 'icon' => 'phone', + 'title' => 'ICON_PHONE', + 'hidden' => false, + 'classes' => '', + 'attributes' => [], + ], + [ + 'ICON_PHONE' => 'Phone icon', + ], + 'Phone icon', + ], + /** PNG: all options */ + [ + [ + 'type' => 'png', + 'icon' => 'pencil', + 'title' => 'ICON_PENCIL', + 'hidden' => true, + 'classes' => 'my-class', + 'attributes' => [ + 'data-url' => 'my-test-url/test-page.php?u=2', + ], + ], + [ + 'ICON_PENCIL' => 'Pencil icon', + ], + 'Pencil icon', + ], + /** SVG: default */ + [ + [ + 'type' => 'svg', + 'icon' => 'phone', + 'title' => 'ICON_PHONE', + 'hidden' => false, + 'classes' => '', + 'attributes' => [], + ], + [ + 'ICON_PHONE' => 'Phone icon', + ], + ' + Phone icon + + + ', + ], + /** SVG: all options */ + [ + [ + 'type' => 'svg', + 'icon' => 'pencil', + 'title' => 'ICON_PENCIL', + 'hidden' => true, + 'classes' => 'my-svg-class', + 'attributes' => [ + 'data-ajax' => 'my_ajax_callback', + ], + ], + [ + 'ICON_PENCIL' => 'Pencil icon', + ], + '', + ], + /** SVG: Sanitization */ + [ + [ + 'type' => 'svg', + 'icon' => 'dirty', + 'title' => '', + 'hidden' => false, + 'classes' => '', + 'attributes' => [], + ], + [], + ' + + ', + ], + ]; + } + + /** + * @dataProvider data_template_icon_extension + */ + public function test_template_icon_extension($vars, $lang_vars, $expected) + { + $file = 'extension_icon_test.html'; + + $this->template->set_filenames(array('test' => $file)); + $this->template->assign_vars($vars); + + foreach ($lang_vars as $name => $value) + { + self::$language_reflection_lang->setValue($this->lang, array_merge( + self::$language_reflection_lang->getValue($this->lang), + [$name => $value] + )); + } + + $expected = str_replace(["\n", "\r", "\t"], '', $expected); + $output = str_replace(["\n", "\r", "\t"], '', $this->display('test')); + + if ($vars['type'] === 'svg') + { + $prefix = strtolower($vars['title']) . '-'; + $output = preg_replace('/' . $prefix . '\d+/', $prefix . '123456789', $output); + } + + $this->assertEquals($expected, $output, "Testing {$file}"); + } } diff --git a/tests/template/templates/extension_icon_test.html b/tests/template/templates/extension_icon_test.html new file mode 100644 index 0000000000..4ea6eb0410 --- /dev/null +++ b/tests/template/templates/extension_icon_test.html @@ -0,0 +1 @@ +{{ Icon(type, icon, title, hidden, classes, attributes) }} diff --git a/tests/template/templates/icons/svg/dirty.svg b/tests/template/templates/icons/svg/dirty.svg new file mode 100644 index 0000000000..29c1500ffe --- /dev/null +++ b/tests/template/templates/icons/svg/dirty.svg @@ -0,0 +1,6 @@ + + + diff --git a/tests/template/templates/icons/svg/pencil.svg b/tests/template/templates/icons/svg/pencil.svg new file mode 100644 index 0000000000..c9c021d811 --- /dev/null +++ b/tests/template/templates/icons/svg/pencil.svg @@ -0,0 +1 @@ +My fake title! diff --git a/tests/template/templates/icons/svg/phone.svg b/tests/template/templates/icons/svg/phone.svg new file mode 100644 index 0000000000..5fbfe196ba --- /dev/null +++ b/tests/template/templates/icons/svg/phone.svg @@ -0,0 +1 @@ +