aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--phpBB/includes/acp/acp_board.php7
-rw-r--r--phpBB/language/en/acp/board.php2
-rw-r--r--phpBB/phpbb/extension/metadata_manager.php5
-rw-r--r--phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php2
-rw-r--r--phpBB/phpbb/textformatter/data_access.php50
-rw-r--r--phpBB/phpbb/textformatter/s9e/factory.php3
-rw-r--r--phpBB/styles/prosilver/template/search_results.html2
-rw-r--r--phpBB/styles/prosilver/template/ucp_pm_viewmessage.html4
-rw-r--r--phpBB/styles/prosilver/theme/icons.css4
-rw-r--r--tests/functional/acp_bbcodes_test.php46
-rw-r--r--tests/functional/acp_smilies_test.php43
-rw-r--r--tests/functional/posting_test.php41
12 files changed, 189 insertions, 20 deletions
diff --git a/phpBB/includes/acp/acp_board.php b/phpBB/includes/acp/acp_board.php
index 826d0007b7..1f9c15dbd0 100644
--- a/phpBB/includes/acp/acp_board.php
+++ b/phpBB/includes/acp/acp_board.php
@@ -196,6 +196,7 @@ class acp_board
'allow_post_flash' => array('lang' => 'ALLOW_POST_FLASH', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_smilies' => array('lang' => 'ALLOW_SMILIES', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => false),
'allow_post_links' => array('lang' => 'ALLOW_POST_LINKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
+ 'allowed_schemes_links' => array('lang' => 'ALLOWED_SCHEMES_LINKS', 'validate' => 'string', 'type' => 'text:0:255', 'explain' => true),
'allow_nocensors' => array('lang' => 'ALLOW_NO_CENSORS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'allow_bookmarks' => array('lang' => 'ALLOW_BOOKMARKS', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
'enable_post_confirm' => array('lang' => 'VISUAL_CONFIRM_POST', 'validate' => 'bool', 'type' => 'radio:yes_no', 'explain' => true),
@@ -552,6 +553,12 @@ class acp_board
}
}
+ // Invalidate the text_formatter cache when posting options are changed
+ if ($mode == 'post' && $submit)
+ {
+ $phpbb_container->get('text_formatter.cache')->invalidate();
+ }
+
// Store news and exclude ids
if ($mode == 'feed' && $submit)
{
diff --git a/phpBB/language/en/acp/board.php b/phpBB/language/en/acp/board.php
index 08290c9617..6a5a4158e3 100644
--- a/phpBB/language/en/acp/board.php
+++ b/phpBB/language/en/acp/board.php
@@ -161,6 +161,8 @@ $lang = array_merge($lang, array(
'ACP_POST_SETTINGS_EXPLAIN' => 'Here you can set all default settings for posting.',
'ALLOW_POST_LINKS' => 'Allow links in posts/private messages',
'ALLOW_POST_LINKS_EXPLAIN' => 'If disallowed the <code>[URL]</code> BBCode tag and automatic/magic URLs are disabled.',
+ 'ALLOWED_SCHEMES_LINKS' => 'Allowed schemes in links',
+ 'ALLOWED_SCHEMES_LINKS_EXPLAIN' => 'Users can only post schemeless URLs or one of the comma-separated list of allowed schemes.',
'ALLOW_POST_FLASH' => 'Allow use of <code>[FLASH]</code> BBCode tag in posts',
'ALLOW_POST_FLASH_EXPLAIN' => 'If disallowed the <code>[FLASH]</code> BBCode tag is disabled in posts. Otherwise the permission system controls which users can use the <code>[FLASH]</code> BBCode tag.',
diff --git a/phpBB/phpbb/extension/metadata_manager.php b/phpBB/phpbb/extension/metadata_manager.php
index 2b8b1bbd6a..348b3c2cdf 100644
--- a/phpBB/phpbb/extension/metadata_manager.php
+++ b/phpBB/phpbb/extension/metadata_manager.php
@@ -214,7 +214,10 @@ class metadata_manager
case 'all':
$this->validate('display');
- $this->validate_enable();
+ if (!$this->validate_enable())
+ {
+ throw new \phpbb\extension\exception('META_FIELD_NOT_SET', array($name));
+ }
break;
case 'display':
diff --git a/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php
index 258a035768..5cdc331cbc 100644
--- a/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php
+++ b/phpBB/phpbb/install/helper/file_updater/ftp_file_updater.php
@@ -47,7 +47,7 @@ class ftp_file_updater implements file_updater_interface
* @param string $phpbb_root_path
* @param string $php_ext
*/
- public function __constructor(update_helper $update_helper, $phpbb_root_path, $php_ext)
+ public function __construct(update_helper $update_helper, $phpbb_root_path, $php_ext)
{
$this->transfer = null;
$this->update_helper = $update_helper;
diff --git a/phpBB/phpbb/textformatter/data_access.php b/phpBB/phpbb/textformatter/data_access.php
index 2103bf8e60..0d37e62c87 100644
--- a/phpBB/phpbb/textformatter/data_access.php
+++ b/phpBB/phpbb/textformatter/data_access.php
@@ -81,11 +81,8 @@ class data_access
public function get_bbcodes()
{
$sql = 'SELECT bbcode_match, bbcode_tpl FROM ' . $this->bbcodes_table;
- $result = $this->db->sql_query($sql);
- $rows = $this->db->sql_fetchrowset($result);
- $this->db->sql_freeresult($result);
- return $rows;
+ return $this->fetch_decoded_rowset($sql, ['bbcode_match']);
}
/**
@@ -101,11 +98,8 @@ class data_access
$sql = 'SELECT code, emotion, smiley_url, smiley_width, smiley_height
FROM ' . $this->smilies_table . '
ORDER BY display_on_posting DESC';
- $result = $this->db->sql_query($sql);
- $rows = $this->db->sql_fetchrowset($result);
- $this->db->sql_freeresult($result);
- return $rows;
+ return $this->fetch_decoded_rowset($sql, ['code', 'emotion', 'smiley_url']);
}
/**
@@ -116,11 +110,8 @@ class data_access
protected function get_styles()
{
$sql = 'SELECT style_id, style_path, style_parent_id, bbcode_bitfield FROM ' . $this->styles_table;
- $result = $this->db->sql_query($sql);
- $rows = $this->db->sql_fetchrowset($result);
- $this->db->sql_freeresult($result);
- return $rows;
+ return $this->fetch_decoded_rowset($sql);
}
/**
@@ -219,10 +210,43 @@ class data_access
public function get_censored_words()
{
$sql = 'SELECT word, replacement FROM ' . $this->words_table;
+
+ return $this->fetch_decoded_rowset($sql, ['word', 'replacement']);
+ }
+
+ /**
+ * Decode HTML special chars in given rowset
+ *
+ * @param array $rows Original rowset
+ * @param array $columns List of columns to decode
+ * @return array Decoded rowset
+ */
+ protected function decode_rowset(array $rows, array $columns)
+ {
+ foreach ($rows as &$row)
+ {
+ foreach ($columns as $column)
+ {
+ $row[$column] = htmlspecialchars_decode($row[$column]);
+ }
+ }
+
+ return $rows;
+ }
+
+ /**
+ * Fetch all rows for given query and decode plain text columns
+ *
+ * @param string $sql SELECT query
+ * @param array $columns List of columns to decode
+ * @return array
+ */
+ protected function fetch_decoded_rowset($sql, array $columns = [])
+ {
$result = $this->db->sql_query($sql);
$rows = $this->db->sql_fetchrowset($result);
$this->db->sql_freeresult($result);
- return $rows;
+ return $this->decode_rowset($rows, $columns);
}
}
diff --git a/phpBB/phpbb/textformatter/s9e/factory.php b/phpBB/phpbb/textformatter/s9e/factory.php
index 55149b8e63..5cbf2712f7 100644
--- a/phpBB/phpbb/textformatter/s9e/factory.php
+++ b/phpBB/phpbb/textformatter/s9e/factory.php
@@ -333,8 +333,7 @@ class factory implements \phpbb\textformatter\cache_interface
$configurator->plugins->load('Censor', array('tagName' => 'censor:tag'));
foreach ($censor as $row)
{
- // NOTE: words are stored as HTML, we need to decode them to plain text
- $configurator->Censor->add(htmlspecialchars_decode($row['word']), htmlspecialchars_decode($row['replacement']));
+ $configurator->Censor->add($row['word'], $row['replacement']);
}
}
diff --git a/phpBB/styles/prosilver/template/search_results.html b/phpBB/styles/prosilver/template/search_results.html
index f7114567e5..ff4f3389c6 100644
--- a/phpBB/styles/prosilver/template/search_results.html
+++ b/phpBB/styles/prosilver/template/search_results.html
@@ -78,7 +78,7 @@
<!-- EVENT search_results_topic_before -->
<li class="row<!-- IF searchresults.S_ROW_COUNT is even --> bg1<!-- ELSE --> bg2<!-- ENDIF -->">
<dl class="row-item {searchresults.TOPIC_IMG_STYLE}">
- <dt<!-- IF searchresults.TOPIC_ICON_IMG and S_TOPIC_ICONS --> style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{searchresults.TOPIC_FOLDER_IMG_ALT}">
+ <dt<!-- IF searchresults.TOPIC_ICON_IMG --> style="background-image: url({T_ICONS_PATH}{searchresults.TOPIC_ICON_IMG}); background-repeat: no-repeat;"<!-- ENDIF --> title="{searchresults.TOPIC_FOLDER_IMG_ALT}">
<!-- IF searchresults.S_UNREAD_TOPIC and not S_IS_BOT --><a href="{searchresults.U_NEWEST_POST}" class="row-item-link"></a><!-- ENDIF -->
<div class="list-inner">
<!-- EVENT topiclist_row_prepend -->
diff --git a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
index e2a086060c..4295867c05 100644
--- a/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
+++ b/phpBB/styles/prosilver/template/ucp_pm_viewmessage.html
@@ -15,7 +15,7 @@
<!-- ENDIF -->
<!-- IF U_VIEW_NEXT_HISTORY -->
<a href="{U_VIEW_NEXT_HISTORY}" class="right-box arrow-{S_CONTENT_FLOW_END}">
- <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_HISTORY}</span>
+ <i class="icon fa-angle-{S_CONTENT_FLOW_END} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_HISTORY}</span>
</a>
<!-- ENDIF -->
</fieldset>
@@ -179,7 +179,7 @@
<!-- ENDIF -->
<!-- IF U_NEXT_PM -->
<a href="{U_NEXT_PM}" class="right-box arrow-{S_CONTENT_FLOW_END}">
- <i class="icon fa-angle-{S_CONTENT_FLOW_BEGIN} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_PM}</span>
+ <i class="icon fa-angle-{S_CONTENT_FLOW_END} fa-fw icon-black" aria-hidden="true"></i><span>{L_VIEW_NEXT_PM}</span>
</a>
<!-- ENDIF -->
<!-- IF not S_UNREAD and not S_SPECIAL_FOLDER --><label for="dest_folder"><!-- IF S_VIEW_MESSAGE -->{L_MOVE_TO_FOLDER}{L_COLON} <!-- ELSE -->{L_MOVE_MARKED_TO_FOLDER}<!-- ENDIF --> <select name="dest_folder" id="dest_folder">{S_TO_FOLDER_OPTIONS}</select></label> <input class="button2" type="submit" name="move_pm" value="{L_GO}" /><!-- ENDIF -->
diff --git a/phpBB/styles/prosilver/theme/icons.css b/phpBB/styles/prosilver/theme/icons.css
index 9fb7244f4b..411fecaf3b 100644
--- a/phpBB/styles/prosilver/theme/icons.css
+++ b/phpBB/styles/prosilver/theme/icons.css
@@ -54,6 +54,10 @@
font-size: 16px;
}
+.arrow-left .icon {
+ float: left;
+}
+
.arrow-left:hover .icon {
margin-left: -5px;
margin-right: 5px;
diff --git a/tests/functional/acp_bbcodes_test.php b/tests/functional/acp_bbcodes_test.php
new file mode 100644
index 0000000000..58681dfa07
--- /dev/null
+++ b/tests/functional/acp_bbcodes_test.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * @group functional
+ */
+class phpbb_functional_acp_bbcodes_test extends phpbb_functional_test_case
+{
+ public function test_htmlspecialchars()
+ {
+ $this->login();
+ $this->admin_login();
+
+ // Create the BBCode
+ $crawler = self::request('GET', 'adm/index.php?i=acp_bbcodes&sid=' . $this->sid . '&mode=bbcodes&action=add');
+ $form = $crawler->selectButton('Submit')->form(array(
+ 'bbcode_match' => '[mod="{TEXT1}"]{TEXT2}[/mod]',
+ 'bbcode_tpl' => '<div>{TEXT1}</div><div>{TEXT2}</div>'
+ ));
+ self::submit($form);
+
+ // Test it in the "new topic" preview
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid);
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'subject',
+ 'message' => '[mod=a]b[/mod][mod="c"]d[/mod]'
+ ));
+ $crawler = self::submit($form);
+
+ $html = $crawler->filter('#preview')->html();
+ $this->assertContains('<div>a</div>', $html);
+ $this->assertContains('<div>b</div>', $html);
+ $this->assertContains('<div>c</div>', $html);
+ $this->assertContains('<div>d</div>', $html);
+ }
+}
diff --git a/tests/functional/acp_smilies_test.php b/tests/functional/acp_smilies_test.php
new file mode 100644
index 0000000000..ebe8717fa7
--- /dev/null
+++ b/tests/functional/acp_smilies_test.php
@@ -0,0 +1,43 @@
+<?php
+/**
+ *
+ * This file is part of the phpBB Forum Software package.
+ *
+ * @copyright (c) phpBB Limited <https://www.phpbb.com>
+ * @license GNU General Public License, version 2 (GPL-2.0)
+ *
+ * For full copyright and license information, please see
+ * the docs/CREDITS.txt file.
+ *
+ */
+
+/**
+ * @group functional
+ */
+class phpbb_functional_acp_smilies_test extends phpbb_functional_test_case
+{
+ public function test_htmlspecialchars()
+ {
+ $this->login();
+ $this->admin_login();
+
+ // Create the BBCode
+ $crawler = self::request('GET', 'adm/index.php?i=acp_icons&sid=' . $this->sid . '&mode=smilies&action=edit&id=1');
+ $form = $crawler->selectButton('Submit')->form(array(
+ 'code[icon_e_biggrin.gif]' => '>:D',
+ 'emotion[icon_e_biggrin.gif]' => '>:D'
+ ));
+ self::submit($form);
+
+ // Test it in the "new topic" preview
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2&sid=' . $this->sid);
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'subject',
+ 'message' => '>:D'
+ ));
+ $crawler = self::submit($form);
+
+ $html = $crawler->filter('#preview')->html();
+ $this->assertRegexp('(<img [^>]+ alt="&gt;:D" title="&gt;:D"[^>]*>)', $html);
+ }
+}
diff --git a/tests/functional/posting_test.php b/tests/functional/posting_test.php
index 83acefd2f3..8e6328d1d3 100644
--- a/tests/functional/posting_test.php
+++ b/tests/functional/posting_test.php
@@ -264,4 +264,45 @@ class phpbb_functional_posting_test extends phpbb_functional_test_case
// Test that the preview contains the correct link
$this->assertEquals($url, $crawler->filter('#preview a')->attr('href'));
}
+
+ public function test_allowed_schemes_links()
+ {
+ $text = 'http://example.org/ tcp://localhost:22/ServiceName';
+
+ $this->login();
+ $this->admin_login();
+
+ // Post with default settings
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text,
+ ));
+ $crawler = self::submit($form);
+ $this->assertContains(
+ '<a href="http://example.org/" class="postlink">http://example.org/</a> tcp://localhost:22/ServiceName',
+ $crawler->filter('#preview .content')->html()
+ );
+
+ // Update allowed schemes
+ $crawler = self::request('GET', 'adm/index.php?sid=' . $this->sid . '&i=acp_board&mode=post');
+ $form = $crawler->selectButton('Submit')->form();
+ $values = $form->getValues();
+ $values['config[allowed_schemes_links]'] = 'https,tcp';
+ $form->setValues($values);
+ $crawler = self::submit($form);
+ $this->assertEquals(1, $crawler->filter('.successbox')->count());
+
+ // Post with new settings
+ $crawler = self::request('GET', 'posting.php?mode=post&f=2');
+ $form = $crawler->selectButton('Preview')->form(array(
+ 'subject' => 'Test subject',
+ 'message' => $text,
+ ));
+ $crawler = self::submit($form);
+ $this->assertContains(
+ 'http://example.org/ <a href="tcp://localhost:22/ServiceName" class="postlink">tcp://localhost:22/ServiceName</a>',
+ $crawler->filter('#preview .content')->html()
+ );
+ }
}