diff --git a/Sources/Actions/Admin/ACP.php b/Sources/Actions/Admin/ACP.php
index afa160dd2f..a3fdc28abb 100644
--- a/Sources/Actions/Admin/ACP.php
+++ b/Sources/Actions/Admin/ACP.php
@@ -19,7 +19,6 @@
use SMF\Actions\MessageIndex;
use SMF\Actions\Notify;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Cache\CacheApi;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
@@ -28,6 +27,7 @@
use SMF\Lang;
use SMF\Mail;
use SMF\Menu;
+use SMF\Parser;
use SMF\SecurityToken;
use SMF\Theme;
use SMF\Url;
@@ -976,7 +976,7 @@ public static function prepareDBSettingContext(array &$config_vars): void
// What about any BBC selection boxes?
if (!empty($bbcChoice)) {
// What are the options, eh?
- $temp = BBCodeParser::getCodes();
+ $temp = Parser::getBBCodes();
$bbcTags = [];
foreach ($temp as $tag) {
@@ -1351,7 +1351,7 @@ public static function saveDBSettings(array &$config_vars): void
elseif ($var[0] == 'bbc') {
$bbcTags = [];
- foreach (BBCodeParser::getCodes() as $tag) {
+ foreach (Parser::getBBCodes() as $tag) {
$bbcTags[] = $tag['tag'];
}
diff --git a/Sources/Actions/Admin/Boards.php b/Sources/Actions/Admin/Boards.php
index 40c71fffcf..67b8ef4596 100644
--- a/Sources/Actions/Admin/Boards.php
+++ b/Sources/Actions/Admin/Boards.php
@@ -18,7 +18,6 @@
use SMF\ActionInterface;
use SMF\Actions\BackwardCompatibility;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Board;
use SMF\Category;
use SMF\Config;
@@ -28,6 +27,7 @@
use SMF\IntegrationHook;
use SMF\Lang;
use SMF\Menu;
+use SMF\Parser;
use SMF\SecurityToken;
use SMF\Theme;
use SMF\Url;
@@ -366,7 +366,7 @@ public function editCategory2(): void
// Try to get any valid HTML to BBC first, add a naive attempt to strip it off, htmlspecialchars for the rest
$catOptions['cat_name'] = Utils::htmlspecialchars(strip_tags($_POST['cat_name']));
- $catOptions['cat_desc'] = Utils::htmlspecialchars(strip_tags(BBCodeParser::load()->unparse($_POST['cat_desc'])));
+ $catOptions['cat_desc'] = Utils::htmlspecialchars(strip_tags(Parser::transform($_POST['cat_desc'], Parser::OUTPUT_BBC)));
$catOptions['is_collapsible'] = isset($_POST['collapse']);
if (isset($_POST['add'])) {
@@ -677,7 +677,7 @@ public function editBoard2(): void
// Try to get any valid HTML to BBC first, add a naive attempt to strip it off, htmlspecialchars for the rest
$boardOptions['board_name'] = Utils::htmlspecialchars(strip_tags($_POST['board_name']));
- $boardOptions['board_description'] = Utils::htmlspecialchars(strip_tags(BBCodeParser::load()->unparse($_POST['desc'])));
+ $boardOptions['board_description'] = Utils::htmlspecialchars(strip_tags(Parser::transform($_POST['desc'], Parser::OUTPUT_BBC)));
$boardOptions['moderator_string'] = $_POST['moderators'];
diff --git a/Sources/Actions/Admin/ErrorLog.php b/Sources/Actions/Admin/ErrorLog.php
index b5a5664be9..ffd1018a3e 100644
--- a/Sources/Actions/Admin/ErrorLog.php
+++ b/Sources/Actions/Admin/ErrorLog.php
@@ -17,13 +17,13 @@
use SMF\ActionInterface;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\ErrorHandler;
use SMF\IP;
use SMF\Lang;
use SMF\PageIndex;
+use SMF\Parser;
use SMF\SecurityToken;
use SMF\Theme;
use SMF\Time;
@@ -430,7 +430,7 @@ public function viewFile(): void
ErrorHandler::fatalLang('error_bad_line');
}
- $file_data = explode('
', BBCodeParser::highlightPhpCode(Utils::htmlspecialchars(file_get_contents($file))));
+ $file_data = explode('
', Parser::highlightPhpCode(Utils::htmlspecialchars(file_get_contents($file))));
// We don't want to slice off too many so lets make sure we stop at the last one
$max = min($max, max(array_keys($file_data)));
diff --git a/Sources/Actions/Admin/Features.php b/Sources/Actions/Admin/Features.php
index e7136c2c40..4483f665ab 100644
--- a/Sources/Actions/Admin/Features.php
+++ b/Sources/Actions/Admin/Features.php
@@ -19,7 +19,6 @@
use SMF\Actions\BackwardCompatibility;
use SMF\Actions\Profile\Notification;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\ErrorHandler;
@@ -27,8 +26,9 @@
use SMF\IntegrationHook;
use SMF\ItemList;
use SMF\Lang;
-use SMF\MarkdownParser;
use SMF\Menu;
+use SMF\Parser;
+use SMF\Parsers\MarkdownParser;
use SMF\Profile;
use SMF\Sapi;
use SMF\SecurityToken;
@@ -185,7 +185,7 @@ public function bbc(): void
$bbcTags = [];
$bbcTagsChildren = [];
- foreach (BBCodeParser::getCodes() as $tag) {
+ foreach (Parser::getBBCodes() as $tag) {
$bbcTags[] = $tag['tag'];
if (isset($tag['require_children'])) {
@@ -194,8 +194,8 @@ public function bbc(): void
}
// Clean up tags with children
- foreach($bbcTagsChildren as $parent_tag => $children) {
- foreach($children as $index => $child_tag) {
+ foreach ($bbcTagsChildren as $parent_tag => $children) {
+ foreach ($children as $index => $child_tag) {
// Remove entries where parent and child tag is the same
if ($child_tag == $parent_tag) {
unset($bbcTagsChildren[$parent_tag][$index]);
@@ -592,7 +592,7 @@ public function signature(): void
// Clean up the tag stuff!
$bbcTags = [];
- foreach (BBCodeParser::getCodes() as $tag) {
+ foreach (Parser::getBBCodes() as $tag) {
$bbcTags[] = $tag['tag'];
}
@@ -1035,7 +1035,7 @@ public function profileEdit(): void
[],
);
- while($row = Db::$db->fetch_assoc($request)) {
+ while ($row = Db::$db->fetch_assoc($request)) {
$fields[] = $row['id_field'];
}
Db::$db->free_result($request);
diff --git a/Sources/Actions/Admin/News.php b/Sources/Actions/Admin/News.php
index 6f4c5fe5c6..7b141962f9 100644
--- a/Sources/Actions/Admin/News.php
+++ b/Sources/Actions/Admin/News.php
@@ -19,7 +19,6 @@
use SMF\Actions\BackwardCompatibility;
use SMF\Actions\Notify;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\Editor;
@@ -31,6 +30,7 @@
use SMF\Mail;
use SMF\Menu;
use SMF\Msg;
+use SMF\Parser;
use SMF\PersonalMessage\PM;
use SMF\SecurityToken;
use SMF\Theme;
@@ -1106,7 +1106,7 @@ public static function list_getNews(): array
$admin_current_news[$id] = [
'id' => $id,
'unparsed' => Msg::un_preparsecode($line),
- 'parsed' => preg_replace('~<([/]?)form[^>]*?[>]*>~i', '<$1form>', BBCodeParser::load()->parse($line)),
+ 'parsed' => preg_replace('~<([/]?)form[^>]*?[>]*>~i', '<$1form>', Parser::transform($line)),
];
}
@@ -1193,7 +1193,7 @@ public static function prepareMailingForPreview(): void
if (!empty(Utils::$context['send_html'])) {
$enablePostHTML = Config::$modSettings['enablePostHTML'];
Config::$modSettings['enablePostHTML'] = Utils::$context['send_html'];
- Utils::$context[$key] = BBCodeParser::load()->parse(Utils::$context[$key]);
+ Utils::$context[$key] = Parser::transform(Utils::$context[$key]);
Config::$modSettings['enablePostHTML'] = $enablePostHTML;
}
diff --git a/Sources/Actions/Admin/Smileys.php b/Sources/Actions/Admin/Smileys.php
index f65ccd2eb8..5794751272 100644
--- a/Sources/Actions/Admin/Smileys.php
+++ b/Sources/Actions/Admin/Smileys.php
@@ -21,7 +21,6 @@
use SMF\Actions\BackwardCompatibility;
use SMF\Actions\MessageIndex;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Cache\CacheApi;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
@@ -33,6 +32,7 @@
use SMF\Menu;
use SMF\Msg;
use SMF\PackageManager\SubsPackage;
+use SMF\Parser;
use SMF\SecurityToken;
use SMF\Theme;
use SMF\User;
@@ -1622,7 +1622,7 @@ public function install(): void
if (!empty($action['parse_bbc'])) {
Msg::preparsecode(Utils::$context[$type]);
- Utils::$context[$type] = BBCodeParser::load()->parse(Utils::$context[$type]);
+ Utils::$context[$type] = Parser::transform(Utils::$context[$type]);
} else {
Utils::$context[$type] = nl2br(Utils::$context[$type]);
}
diff --git a/Sources/Actions/Agreement.php b/Sources/Actions/Agreement.php
index 661886c250..be325340fe 100644
--- a/Sources/Actions/Agreement.php
+++ b/Sources/Actions/Agreement.php
@@ -17,11 +17,10 @@
use SMF\ActionInterface;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\ErrorHandler;
use SMF\Lang;
-use SMF\MarkdownParser;
+use SMF\Parser;
use SMF\Theme;
use SMF\User;
use SMF\Utils;
@@ -149,31 +148,32 @@ protected function prepareAgreementContext(): void
if (!empty(Utils::$context['agreement_file'])) {
$cache_id = strtr(Utils::$context['agreement_file'], [Config::$languagesdir => '', '.txt' => '', '.' => '_']);
- Utils::$context['agreement'] = BBCodeParser::load()->parse(file_get_contents(Utils::$context['agreement_file']), true, $cache_id);
+ Utils::$context['agreement'] = Parser::transform(
+ string: file_get_contents(Utils::$context['agreement_file']),
+ options: ['cache_id' => $cache_id, 'hard_breaks' => 0],
+ );
} elseif (Utils::$context['can_accept_agreement']) {
ErrorHandler::fatalLang('error_no_agreement', false);
}
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- Utils::$context['agreement'] = MarkdownParser::load(MarkdownParser::OUTPUT_HTML, 0)->parse(Utils::$context['agreement'], true);
- }
}
if (!Utils::$context['accept_doc'] || Utils::$context['can_accept_privacy_policy']) {
// Have we got a localized policy?
if (!empty(Config::$modSettings['policy_' . User::$me->language])) {
- Utils::$context['privacy_policy'] = BBCodeParser::load()->parse(Config::$modSettings['policy_' . User::$me->language]);
+ Utils::$context['privacy_policy'] = Parser::transform(
+ string: Config::$modSettings['policy_' . User::$me->language],
+ options: ['hard_breaks' => 0],
+ );
} elseif (!empty(Config::$modSettings['policy_' . Lang::$default])) {
- Utils::$context['privacy_policy'] = BBCodeParser::load()->parse(Config::$modSettings['policy_' . Lang::$default]);
+ Utils::$context['privacy_policy'] = Parser::transform(
+ string: Config::$modSettings['policy_' . Lang::$default],
+ options: ['hard_breaks' => 0],
+ );
}
// Then I guess we've got nothing
elseif (Utils::$context['can_accept_privacy_policy']) {
ErrorHandler::fatalLang('error_no_privacy_policy', false);
}
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- Utils::$context['privacy_policy'] = MarkdownParser::load(MarkdownParser::OUTPUT_HTML, 0)->parse(Utils::$context['privacy_policy'], true);
- }
}
}
}
diff --git a/Sources/Actions/Announce.php b/Sources/Actions/Announce.php
index 4768a6fda4..2185bc09c8 100644
--- a/Sources/Actions/Announce.php
+++ b/Sources/Actions/Announce.php
@@ -17,7 +17,6 @@
use SMF\ActionInterface;
use SMF\ActionTrait;
-use SMF\BBCodeParser;
use SMF\Board;
use SMF\BrowserDetector;
use SMF\Config;
@@ -27,7 +26,7 @@
use SMF\Lang;
use SMF\Logging;
use SMF\Mail;
-use SMF\MarkdownParser;
+use SMF\Parser;
use SMF\Theme;
use SMF\Topic;
use SMF\User;
@@ -168,11 +167,7 @@ public function send(): void
Lang::censorText(Utils::$context['topic_subject']);
Lang::censorText($message);
- $message = BBCodeParser::load()->parse($message, false, $id_msg);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $message = MarkdownParser::load()->parse($message, true);
- }
+ $message = Parser::transform(string: $message, options: ['cache_id' => $id_msg]);
$message = trim(Utils::htmlspecialcharsDecode(strip_tags(strtr($message, ['
' => "\n", '' => "\n", '' => "\n", '
' => '', '
' => "\n\n", '[' => '[', ']' => ']'])))); diff --git a/Sources/Actions/Feed.php b/Sources/Actions/Feed.php index abb2d3b327..df8b8598e0 100644 --- a/Sources/Actions/Feed.php +++ b/Sources/Actions/Feed.php @@ -19,7 +19,6 @@ use SMF\ActionTrait; use SMF\Attachment; use SMF\Autolinker; -use SMF\BBCodeParser; use SMF\Board; use SMF\BrowserDetector; use SMF\Cache\CacheApi; @@ -29,7 +28,7 @@ use SMF\IntegrationHook; use SMF\IP; use SMF\Lang; -use SMF\MarkdownParser; +use SMF\Parser; use SMF\Sapi; use SMF\Theme; use SMF\Time; @@ -779,11 +778,11 @@ public function getXmlNews(): array $row['body'] = strtr(Utils::entitySubstr(str_replace(')?]*>|<\/code>(<\/pre>)?$/', '', $buffer);
+
+ return strtr($buffer, ['\'' => ''']);
+ }
+
+ /**
+ * Microsoft uses their own character set Code Page 1252 (CP1252), which is
+ * a superset of ISO 8859-1, defining several characters between DEC 128 and
+ * 159 that are not normally displayable. This converts the popular ones
+ * that appear from a cut and paste from Windows.
+ *
+ * @todo In a Unicode-aware world, we probably should not do this any more.
+ *
+ * @param string $string The string.
+ * @return string The sanitized string.
+ */
+ public static function sanitizeMSCutPaste(string $string): string
+ {
+ if (empty($string)) {
+ return $string;
+ }
+
+ self::setStaticVars();
+
+ // UTF-8 occurrences of MS special characters.
+ $findchars_utf8 = [
+ "\xe2\x80\x9a", // single low-9 quotation mark, U+201A
+ "\xe2\x80\x9e", // double low-9 quotation mark, U+201E
+ "\xe2\x80\xa6", // horizontal ellipsis, U+2026
+ "\xe2\x80\x98", // left single curly quote, U+2018
+ "\xe2\x80\x99", // right single curly quote, U+2019
+ "\xe2\x80\x9c", // left double curly quote, U+201C
+ "\xe2\x80\x9d", // right double curly quote, U+201D
+ ];
+
+ // windows 1252 / iso equivalents
+ $findchars_iso = [
+ chr(130),
+ chr(132),
+ chr(133),
+ chr(145),
+ chr(146),
+ chr(147),
+ chr(148),
+ ];
+
+ // safe replacements
+ $replacechars = [
+ ',', // ‚
+ ',,', // „
+ '...', // …
+ "'", // ‘
+ "'", // ’
+ '"', // “
+ '"', // ”
+ ];
+
+ $string = str_replace(self::$encoding === 'UTF-8' ? $findchars_utf8 : $findchars_iso, $replacechars, $string);
+
+ return $string;
+ }
+
+ /*************************
+ * Internal static methods
+ *************************/
+
+ /**
+ * Sets the values of this class's static variables.
+ *
+ * If a variable already has a value, the existing value is not changed.
+ * This ensures that custom values set by external code are respected.
+ */
+ protected static function setStaticVars(): void
+ {
+ // Is anything disabled?
+ self::$enable_bbc = self::$enable_bbc ?? !empty(Config::$modSettings['enableBBC']);
+ self::$enable_post_html = self::$enable_post_html ?? !empty(Config::$modSettings['enablePostHTML']);
+ self::$enable_markdown = self::$enable_markdown ?? !empty(Config::$modSettings['enableMarkdown']);
+ self::$custom_smileys_enabled = self::$custom_smileys_enabled ?? !empty(Config::$modSettings['smiley_enable']);
+
+ // Set up localization.
+ if (!isset(User::$me)) {
+ User::setMe(0);
+ }
+
+ self::$time_offset = self::$time_offset ?? User::$me->time_offset ?? 0;
+ self::$time_format = self::$time_format ?? User::$me->time_format ?? Time::getTimeFormat();
+
+ self::$locale = self::$locale ?? Lang::$txt['lang_locale'] ?? '';
+ self::$encoding = self::$encoding ?? (!empty(Utils::$context['utf8']) ? 'UTF-8' : (!empty(Config::$modSettings['global_character_set']) ? Config::$modSettings['global_character_set'] : (!empty(Lang::$txt['lang_character_set']) ? Lang::$txt['lang_character_set'] : 'UTF-8')));
+
+ // Smiley settings.
+ self::$custom_smileys_enabled = self::$custom_smileys_enabled ?? !empty(Config::$modSettings['smiley_enable']);
+ self::$smileys_url = self::$smileys_url ?? Config::$modSettings['smileys_url'];
+ self::$smiley_set = self::$smiley_set ?? (!empty(User::$me->smiley_set) ? User::$me->smiley_set : (!empty(Config::$modSettings['smiley_sets_default']) ? Config::$modSettings['smiley_sets_default'] : 'none'));
+ }
+
+ /**
+ * Fills in any missing elements of $options with the default values.
+ *
+ * @param array $options An array of parser options.
+ * @return array An updated copy of $options.
+ */
+ protected static function setOptions(array $options): array
+ {
+ IntegrationHook::call('integrate_parser_options', [&$options]);
+
+ return array_merge(self::$defalt_options, $options);
+ }
+
+ /**
+ * Transforms the input string into HTML.
+ *
+ * @param string $string The string in which to transform markup.
+ * @param int $input_types Bitmask of this class's INPUT_* constants.
+ * Only the indicated types of markup will be parsed in the input string.
+ * @param array $options An array of parser options.
+ * @return string The transformed string.
+ */
+ protected static function toHTML(string $string, int $input_types, array $options): string
+ {
+ // Allow mods access before parsing.
+ $smileys = !empty($input_types & self::INPUT_SMILEYS);
+
+ IntegrationHook::call('integrate_pre_parsebbc', [&$string, &$smileys, &$options['cache_id'], &$options['parse_tags']]);
+
+ $input_types = $input_types | ($smileys ? self::INPUT_SMILEYS : 0);
+
+ // Parse the BBCode.
+ if ($input_types & self::INPUT_BBC) {
+ $string = BBcodeParser::load(!empty($options['for_print']))->parse($string, $options['cache_id'], $options['parse_tags']);
+ }
+
+ // Parse the smileys.
+ if ($input_types & self::INPUT_SMILEYS) {
+ $string = SmileyParser::load()->parse($string);
+ }
+
+ // Parse the Markdown.
+ if ($input_types & self::INPUT_MARKDOWN) {
+ $string = MarkdownParser::load(MarkdownParser::OUTPUT_HTML, (int) $options['hard_breaks'])->parse($string, true);
+ }
+
+ // Allow mods access to the parsed value.
+ IntegrationHook::call('integrate_post_parsebbc', [&$string, $smileys, $options['cache_id'], $options['parse_tags']]);
+
+ return $string;
+ }
+
+ /**
+ * Transforms the input string into plain text (i.e. removes all markup).
+ *
+ * @param string $string The string in which to remove markup.
+ * @param int $input_types Bitmask of this class's INPUT_* constants.
+ * Only the indicated types of markup will be parsed in the input string.
+ * @param array $options An array of parser options.
+ * @return string The transformed string.
+ */
+ protected static function toText(string $string, int $input_types, array $options): string
+ {
+ // When transforming Markdown to plain text, the best results are
+ // obtained by transforming it into BBC as an intermediate stage.
+ if ($input_types & self::INPUT_MARKDOWN) {
+ $string = MarkdownParser::load(MarkdownParser::OUTPUT_BBC)->parse($string, false);
+ $input_types &= ~self::INPUT_MARKDOWN;
+ }
+
+ // Transform smiley images into smiley text.
+ if ($input_types & self::INPUT_SMILEYS) {
+ $string = SmileyParser::load()->unparse($string);
+ $input_types &= ~self::INPUT_SMILEYS;
+ }
+
+ // Ironically enough, the next step is to transform the BBC into HTML.
+ $string = self::toHTML($string, $input_types, $options);
+
+ // Do we have any replacements to make?
+ if (!empty($options['preg_replace'])) {
+ $string = preg_replace_callback_array($options['preg_replace'], $string);
+ }
+
+ if (!empty($options['str_replace'])) {
+ $string = strtr($string, $options['str_replace']);
+ }
+
+ // Strip out the HTML tags and return the result.
+ return strip_tags($string);
+ }
+
+ /**
+ * Transforms the input string into BBCode.
+ *
+ * - Markdown is transformed to the equivalent BBCode.
+ * - HTML img tags for smileys are transformed to smiley text.
+ * - Other HTML is transformed to the equivalent BBCode where possible.
+ * - HTML tags that cannot be transformed are removed.
+ *
+ * @param string $string The string in which to remove markup.
+ * @param int $input_types Bitmask of this class's INPUT_* constants.
+ * Only the indicated types of markup will be parsed in the input string.
+ * @param array $options An array of parser options.
+ * @return string The transformed string.
+ */
+ protected static function toBBC(string $string, int $input_types, array $options): string
+ {
+ if ($input_types & self::INPUT_MARKDOWN) {
+ $string = MarkdownParser::load(self::OUTPUT_BBC)->parse($string, false);
+ }
+
+ if ($input_types & self::INPUT_SMILEYS) {
+ $string = SmileyParser::load()->unparse($string);
+ }
+
+ $string = BBcodeParser::load()->unparse($string);
+
+ return $string;
+ }
+
+ /**
+ * Generates a unique cache key for the combination of string, parameters,
+ * settings, etc., that apply to this particular call to self::transform().
+ *
+ * @param string $string The string in which to transform markup.
+ * @param int $input_types Bitmask of this class's INPUT_* constants.
+ * @param int $output_type One of this class's INPUT_* constants.
+ * @param array $options An array of parser options.
+ * @return string A unique cache key.
+ */
+ protected static function getCacheKey(string $string, int $input_types, int $output_type, array $options): string
+ {
+ // Allow mods to add stuff to $cache_key_extras.
+ $cache_key_extras = [];
+
+ IntegrationHook::call('integrate_parser_cache', [&$cache_key_extras, $input_types, $output_type, $options]);
+
+ // If no cache id was given, make a generic one.
+ $cache_id = strval($options['cache_id'] ?? '') !== '' ? $options['cache_id'] : 'str' . substr(md5($string), 0, 7);
+
+ // Use a unique identifier key for this combination of string and settings.
+ return 'parse:' . $cache_id . '-' . md5(json_encode([
+ $string,
+ $input_types,
+ $output_type,
+ $options,
+ // Localization settings.
+ self::$encoding,
+ self::$locale,
+ self::$time_offset,
+ self::$time_format,
+ // BBCode settings.
+ self::getBBCodes(),
+ Config::$modSettings['disabledBBC'],
+ self::$enable_post_html,
+ // Smiley settings.
+ SmileyParser::loadData(self::$smiley_set),
+ // Additional stuff that might affect output.
+ $cache_key_extras,
+ ]));
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/Sources/BBCodeParser.php b/Sources/Parsers/BBCodeParser.php
similarity index 86%
rename from Sources/BBCodeParser.php
rename to Sources/Parsers/BBCodeParser.php
index 2103fa2f8a..a02fffefb9 100644
--- a/Sources/BBCodeParser.php
+++ b/Sources/Parsers/BBCodeParser.php
@@ -13,36 +13,25 @@
declare(strict_types=1);
-namespace SMF;
-
-use SMF\Cache\CacheApi;
-use SMF\Db\DatabaseApi as Db;
+namespace SMF\Parsers;
+
+use SMF\Attachment;
+use SMF\Autolinker;
+use SMF\BrowserDetector;
+use SMF\Config;
+use SMF\IntegrationHook;
+use SMF\Lang;
+use SMF\Parser;
+use SMF\Sapi;
+use SMF\Theme;
+use SMF\Time;
+use SMF\Url;
+use SMF\Utils;
/**
* Parses Bulletin Board Code in a string and converts it to HTML.
- *
- * The recommended way to use this class to parse BBCode in a string is:
- *
- * $parsed_string = BBCodeParser::load()->parse($unparsed_string);
- *
- * Calling the load() method like this will save on memory by reusing a single
- * instance of the BBCodeParser class. However, if you need more control over
- * the parser, you can always instantiate a new one.
- *
- * The following integration hooks are called during object construction:
- *
- * integrate_bbc_codes (Used to add or modify BBC)
- * integrate_smileys (Used for alternative smiley handling)
- *
- * The following integration hooks are called during parsing:
- *
- * integrate_pre_parsebbc (Allows adjustments before parsing)
- * integrate_post_parsebbc (Gives access to results of parsing)
- * integrate_attach_bbc_validate (Adjusts HTML produced by the attach BBC)
- * integrate_bbc_print (For BBC that need special handling in
- * print mode)
*/
-class BBCodeParser
+class BBCodeParser extends Parser
{
/*******************
* Public properties
@@ -55,20 +44,6 @@ class BBCodeParser
*/
public array $parse_tags = [];
- /**
- * @var bool
- *
- * Whether BBCode should be parsed.
- */
- public bool $enable_bbc;
-
- /**
- * @var bool
- *
- * Whether to allow certain basic HTML tags in the input.
- */
- public bool $enable_post_html;
-
/**
* @var array
*
@@ -76,69 +51,6 @@ class BBCodeParser
*/
public array $disabled = [];
- /**
- * @var bool
- *
- * Whether smileys should be parsed.
- */
- public bool $smileys = true;
-
- /**
- * @var string
- *
- * The smiley set to use when parsing smileys.
- */
- public string $smiley_set;
-
- /**
- * @var bool
- *
- * Whether custom smileys are enabled.
- */
- public bool $custom_smileys_enabled;
-
- /**
- * @var string
- *
- * URL of the base smileys directory.
- */
- public string $smileys_url;
-
- /**
- * @var string
- *
- * The character encoding of the strings to be parsed.
- */
- public string $encoding = 'UTF-8';
-
- /**
- * @var bool
- *
- * Shorthand check for whether character encoding is UTF-8.
- */
- public bool $utf8 = true;
-
- /**
- * @var string
- *
- * Language locale to use.
- */
- public string $locale = 'en_US';
-
- /**
- * @var int
- *
- * User's time offset from UTC.
- */
- public int $time_offset;
-
- /**
- * @var string
- *
- * User's strftime format.
- */
- public string $time_format;
-
/**
* @var bool
*
@@ -157,20 +69,6 @@ class BBCodeParser
*/
protected ?string $alltags_regex = null;
- /**
- * @var ?string
- *
- * Regular expression to match smileys.
- */
- protected ?string $smiley_preg_search = null;
-
- /**
- * @var array
- *
- * Replacement values for smileys.
- */
- protected array $smiley_preg_replacements = [];
-
/**
* @var array
*
@@ -272,13 +170,6 @@ class BBCodeParser
*/
private string $placeholder_template = "\u{E03C}" . '%1$s' . "\u{E03E}";
- /**
- * @var array
- *
- * Holds parsed messages.
- */
- private array $results = [];
-
/****************************
* Internal static properties
****************************/
@@ -942,11 +833,11 @@ class BBCodeParser
private static bool $integrate_bbc_codes_done = false;
/**
- * @var self
+ * @var array
*
- * A reference to an existing, reusable instance of this class.
+ * Reusable instances of this class.
*/
- private static self $parser;
+ private static array $parsers = [];
/*****************
* Public methods.
@@ -954,32 +845,12 @@ class BBCodeParser
/**
* Constructor.
- *
- * @return object A reference to this object for method chaining.
- * @suppress PHP0436
*/
- public function __construct()
+ public function __construct(bool $for_print = false)
{
- // Set up localization.
- if (!empty(Utils::$context['utf8'])) {
- $this->utf8 = true;
- $this->encoding = 'UTF-8';
- } else {
- $this->encoding = !empty(Config::$modSettings['global_character_set']) ? Config::$modSettings['global_character_set'] : (!empty(Lang::$txt['lang_character_set']) ? Lang::$txt['lang_character_set'] : $this->encoding);
+ $this->for_print = $for_print;
- $this->utf8 = $this->encoding === 'UTF-8';
- }
-
- if (!empty(Lang::$txt['lang_locale'])) {
- $this->locale = Lang::$txt['lang_locale'];
- }
-
- $this->time_offset = User::$me->time_offset ?? 0;
- $this->time_format = User::$me->time_format ?? Time::getTimeFormat();
-
- // Set up BBCode parsing.
- $this->enable_bbc = !empty(Config::$modSettings['enableBBC']);
- $this->enable_post_html = !empty(Config::$modSettings['enablePostHTML']);
+ parent::__construct();
self::integrateBBC();
@@ -987,27 +858,12 @@ public function __construct()
self::$codes,
fn ($a, $b) => $a['tag'] <=> $b['tag'],
);
-
- // Set up smileys parsing.
- $this->custom_smileys_enabled = !empty(Config::$modSettings['smiley_enable']);
- $this->smileys_url = Config::$modSettings['smileys_url'];
- $this->smiley_set = !empty(User::$me->smiley_set) ? User::$me->smiley_set : (!empty(Config::$modSettings['smiley_sets_default']) ? Config::$modSettings['smiley_sets_default'] : 'none');
-
- // Maybe a mod wants to implement an alternative method for smileys
- // (e.g. emojis instead of images)
- if ($this->smiley_set !== 'none') {
- IntegrationHook::call('integrate_smileys', [&$this->smiley_preg_search, &$this->smiley_preg_replacements]);
- }
-
- // Allow method chaining.
- return $this;
}
/**
- * Parse bulletin board code in a string, as well as smileys optionally.
+ * Parse bulletin board code in a string.
*
* @param string|bool $message The string to parse.
- * @param bool $smileys Whether to parse smileys. Default: true.
* @param string|int $cache_id The cache ID.
* If $cache_id is left empty, an ID will be generated automatically.
* Manually specifying a ID is helpful in cases when an integration hook
@@ -1016,7 +872,7 @@ public function __construct()
* @param array $parse_tags If set, only parses these tags rather than all of them.
* @return string The parsed string.
*/
- public function parse(string $message, bool $smileys = true, string|int $cache_id = '', array $parse_tags = []): string
+ public function parse(string $message, string|int $cache_id = '', array $parse_tags = []): string
{
// Don't waste cycles
if (strval($message) === '') {
@@ -1027,7 +883,6 @@ public function parse(string $message, bool $smileys = true, string|int $cache_i
$this->resetRuntimeProperties();
$this->message = $message;
- $this->smileys = $smileys;
$this->parse_tags = $parse_tags;
$this->setDisabled();
@@ -1041,174 +896,16 @@ public function parse(string $message, bool $smileys = true, string|int $cache_i
return $this->message;
}
- if (!$this->enable_bbc) {
- if ($this->smileys === true) {
- $this->message = $this->parseSmileys($this->message);
- }
-
+ if (!self::$enable_bbc) {
$this->message = $this->fixHtml($this->message);
return $this->message;
}
- // Allow mods access before entering $this->parseMessage.
- IntegrationHook::call('integrate_pre_parsebbc', [&$this->message, &$this->smileys, &$cache_id, &$this->parse_tags, &$this->cache_key_extras]);
-
- // If no cache id was given, make a generic one.
- $cache_id = strval($cache_id) !== '' ? $cache_id : 'str' . substr(md5($this->message), 0, 7);
-
- // Use a unique identifier key for this combination of string and settings.
- $cache_key = 'parse:' . $cache_id . '-' . md5(json_encode([
- $this->message,
- // Localization settings.
- $this->encoding,
- $this->locale,
- $this->time_offset,
- $this->time_format,
- // BBCode settings.
- $this->bbc_codes,
- $this->disabled,
- $this->parse_tags,
- $this->enable_post_html,
- $this->for_print,
- // Smiley settings.
- $this->smileys,
- $this->smiley_set,
- $this->smiley_preg_search,
- $this->smiley_preg_replacements,
- // Additional stuff that might affect output.
- $this->cache_key_extras,
- ]));
-
- // Have we already parsed this string?
- if (isset($this->results[$cache_key])) {
- return $this->results[$cache_key];
- }
-
- // Or maybe we cached the results recently?
- if (($this->results[$cache_key] = CacheApi::get($cache_key, 240)) != null) {
- return $this->results[$cache_key];
- }
-
- // Keep track of how long this takes.
- $cache_t = microtime(true);
-
// Do the job.
$this->parseMessage();
- // Allow mods access to what $this->parseMessage created.
- IntegrationHook::call('integrate_post_parsebbc', [&$this->message, &$this->smileys, &$cache_id, &$this->parse_tags]);
-
- // Cache the output if it took some time...
- if (!empty(CacheApi::$enable) && microtime(true) - $cache_t > pow(50, -CacheApi::$enable)) {
- CacheApi::put($cache_key, $this->message, 240);
- }
-
- // Remember for later.
- $this->results[$cache_key] = $this->message;
-
- return $this->results[$cache_key];
- }
-
- /**
- * Parse smileys in the passed message.
- *
- * The smiley parsing function which makes pretty faces appear :).
- * If custom smiley sets are turned off by smiley_enable, the default set of smileys will be used.
- * These are specifically not parsed in code tags [url=mailto:Dad@blah.com]
- * Caches the smileys from the database or array in memory.
- *
- * @param string $message The message to parse smileys in.
- * @return string The message with smiley images inserted.
- */
- public function parseSmileys(string $message): string
- {
- if ($this->smiley_set == 'none' || trim($message) == '') {
- return $message;
- }
-
- // If smileyPregSearch hasn't been set, do it now.
- if (empty($this->smiley_preg_search)) {
- // Cache for longer when customized smiley codes aren't enabled
- $cache_time = !$this->custom_smileys_enabled ? 7200 : 480;
-
- // Load the smileys in reverse order by length so they don't get parsed incorrectly.
- if (($temp = CacheApi::get('parsing_smileys_' . $this->smiley_set, $cache_time)) == null) {
- $smileysfrom = [];
- $smileysto = [];
- $smileysdescs = [];
-
- $result = Db::$db->query(
- '',
- 'SELECT s.code, f.filename, s.description
- FROM {db_prefix}smileys AS s
- JOIN {db_prefix}smiley_files AS f ON (s.id_smiley = f.id_smiley)
- WHERE f.smiley_set = {string:smiley_set}' . (!$this->custom_smileys_enabled ? '
- AND s.code IN ({array_string:default_codes})' : '') . '
- ORDER BY LENGTH(s.code) DESC',
- [
- 'default_codes' => ['>:D', ':D', '::)', '>:(', ':))', ':)', ';)', ';D', ':(', ':o', '8)', ':P', '???', ':-[', ':-X', ':-*', ':\'(', ':-\\', '^-^', 'O0', 'C:-)', 'O:-)'],
- 'smiley_set' => $this->smiley_set,
- ],
- );
-
- while ($row = Db::$db->fetch_assoc($result)) {
- $smileysfrom[] = $row['code'];
- $smileysto[] = Utils::htmlspecialchars($row['filename']);
- $smileysdescs[] = !empty(Lang::$txt['icon_' . strtolower($row['description'])]) ? Lang::$txt['icon_' . strtolower($row['description'])] : $row['description'];
- }
- Db::$db->free_result($result);
-
- CacheApi::put('parsing_smileys_' . $this->smiley_set, [$smileysfrom, $smileysto, $smileysdescs], $cache_time);
- } else {
- list($smileysfrom, $smileysto, $smileysdescs) = $temp;
- }
-
- // The non-breaking-space is a complex thing...
- $non_breaking_space = $this->utf8 ? '\x{A0}' : '\xA0';
-
- // This smiley regex makes sure it doesn't parse smileys within code tags (so [url=mailto:David@bla.com] doesn't parse the :D smiley)
- $this->smiley_preg_replacements = [];
- $search_parts = [];
- $smileys_path = Utils::htmlspecialchars($this->smileys_url . '/' . rawurlencode($this->smiley_set) . '/');
-
- for ($i = 0, $n = count($smileysfrom); $i < $n; $i++) {
- $special_chars = Utils::htmlspecialchars($smileysfrom[$i], ENT_QUOTES);
-
- $smiley_code = '';
-
- $this->smiley_preg_replacements[$smileysfrom[$i]] = $smiley_code;
-
- $search_parts[] = $smileysfrom[$i];
-
- if ($smileysfrom[$i] != $special_chars) {
- $this->smiley_preg_replacements[$special_chars] = $smiley_code;
- $search_parts[] = $special_chars;
-
- // Some 2.0 hex htmlchars are in there as 3 digits; allow for finding leading 0 or not
- $special_chars2 = preg_replace('/(\d{2});/', '$1;', $special_chars);
-
- if ($special_chars2 != $special_chars) {
- $this->smiley_preg_replacements[$special_chars2] = $smiley_code;
- $search_parts[] = $special_chars2;
- }
- }
- }
-
- $this->smiley_preg_search = '~(?<=[>:\?\.\s' . $non_breaking_space . '[\]()*\\\;]|(?utf8 ? 'u' : '');
- }
-
- // If there are no smileys defined, no need to replace anything
- if (empty($this->smiley_preg_replacements)) {
- return $message;
- }
-
- // Replace away!
- return preg_replace_callback(
- $this->smiley_preg_search,
- fn ($matches) => $this->smiley_preg_replacements[$matches[1]],
- $message,
- );
+ return $this->message;
}
/**
@@ -1258,38 +955,6 @@ public function unparse(string $string): string
$string = preg_replace('~\\<\\!--.*?-->~i', '', $string);
$string = preg_replace('~\\<\\!\\[CDATA\\[.*?\\]\\]\\>~i', '', $string);
- // Do the smileys ultra first!
- preg_match_all('~]+alt="([^"]+)"[^>]+class="smiley"[^>]*>(?:\s)?~i', $string, $matches);
-
- if (!empty($matches[0])) {
- // Get all our smiley codes
- $request = Db::$db->query(
- '',
- 'SELECT code
- FROM {db_prefix}smileys
- ORDER BY LENGTH(code) DESC',
- [],
- );
- $smiley_codes = Db::$db->fetch_all($request);
- Db::$db->free_result($request);
-
- foreach ($matches[1] as $k => $possible_code) {
- $possible_code = Utils::htmlspecialcharsDecode($possible_code);
-
- if (in_array($possible_code, $smiley_codes)) {
- $matches[1][$k] = '-[]-smf_smily_start#|#' . $possible_code . '-[]-smf_smily_end#|#';
- } else {
- $matches[1][$k] = $matches[0][$k];
- }
- }
-
- // Replace the tags!
- $string = str_replace($matches[0], $matches[1], $string);
-
- // Now sort out spaces
- $string = str_replace(['-[]-smf_smily_end#|#-[]-smf_smily_start#|#', '-[]-smf_smily_end#|#', '-[]-smf_smily_start#|#'], ' ', $string);
- }
-
// Only try to buy more time if the client didn't quit.
if (connection_aborted()) {
Sapi::resetTimeout();
@@ -2027,22 +1692,22 @@ public function getAllTagsRegex(): string
* Using this method to get a BBCodeParser instance saves memory by avoiding
* creating redundant instances.
*
- * @param bool $init If true, reinitializes the reusable BBCodeParser.
+ * @param bool $for_print If true, adjusts output for print media.
* @return object An instance of this class.
*/
- public static function load(bool $init = false): object
+ public static function load(bool $for_print = false): object
{
- if (!isset(self::$parser) || !empty($init)) {
- self::$parser = new self();
+ if (!isset(self::$parsers[(int) $for_print])) {
+ self::$parsers[(int) $for_print] = new self($for_print);
}
- return self::$parser;
+ return self::$parsers[(int) $for_print];
}
/**
* Get the list of supported BBCodes, including any added by modifications.
*
- * @return array List of supported BBCodes
+ * @return array List of supported BBCodes.
*/
public static function getCodes(): array
{
@@ -2052,9 +1717,10 @@ public static function getCodes(): array
}
/**
- * Returns an array of BBC tags that are allowed in signatures.
+ * Returns an array of BBCodes tags that are allowed in signatures.
*
- * @return array An array containing allowed tags for signatures, or an empty array if all tags are allowed.
+ * @return array An array containing allowed tags for signatures, or an
+ * empty array if all tags are allowed.
*/
public static function getSigTags(): array
{
@@ -2066,7 +1732,7 @@ public static function getSigTags(): array
$disabled_tags = explode(',', $sig_bbc);
- // Get all available bbc tags
+ // Get all available BBCode tags.
$temp = self::getCodes();
$allowed_tags = [];
@@ -2079,152 +1745,14 @@ public static function getSigTags(): array
$allowed_tags = array_unique($allowed_tags);
if (empty($allowed_tags)) {
- // An empty array means that all bbc tags are allowed. So if all tags are disabled we need to add a dummy tag.
+ // An empty array means that all BBCode tags are allowed.
+ // So if all tags are disabled we need to add a dummy tag.
$allowed_tags[] = 'nonexisting';
}
return $allowed_tags;
}
- /**
- * Highlight any code.
- *
- * Uses PHP's highlight_string() to highlight PHP syntax.
- * Does special handling to keep the tabs in the code available.
- * Used to parse PHP code from inside [code] and [php] tags.
- *
- * @param string $code The code.
- * @return string The code with highlighted HTML.
- */
- public static function highlightPhpCode(string $code): string
- {
- // Remove special characters.
- $code = Utils::htmlspecialcharsDecode(strtr($code, ['
' => "\n", '
' => "\n", "\t" => 'SMF_TAB();', '[' => '[']));
-
- $oldlevel = error_reporting(0);
-
- $buffer = str_replace(["\n", "\r"], '', @highlight_string($code, true));
-
- error_reporting($oldlevel);
-
- // Yes, I know this is kludging it, but this is the best way to preserve tabs from PHP :P.
- $buffer = preg_replace('~SMF_TAB(?:(?:font|span)><(?:font color|span style)="[^"]*?">)?\(\);~', '' . "\t" . '', $buffer);
-
- // PHP 8.3 changed the returned HTML.
- $buffer = preg_replace('/^()?]*>|<\/code>(<\/pre>)?$/', '', $buffer);
-
- return strtr($buffer, ['\'' => ''']);
- }
-
- /**
- * Microsoft uses their own character set Code Page 1252 (CP1252), which is
- * a superset of ISO 8859-1, defining several characters between DEC 128 and
- * 159 that are not normally displayable. This converts the popular ones
- * that appear from a cut and paste from Windows.
- *
- * @param string $string The string.
- * @return string The sanitized string.
- */
- public static function sanitizeMSCutPaste(string $string): string
- {
- if (empty($string)) {
- return $string;
- }
-
- self::load();
-
- // UTF-8 occurrences of MS special characters.
- $findchars_utf8 = [
- "\xe2\x80\x9a", // single low-9 quotation mark
- "\xe2\x80\x9e", // double low-9 quotation mark
- "\xe2\x80\xa6", // horizontal ellipsis
- "\xe2\x80\x98", // left single curly quote
- "\xe2\x80\x99", // right single curly quote
- "\xe2\x80\x9c", // left double curly quote
- "\xe2\x80\x9d", // right double curly quote
- ];
-
- // windows 1252 / iso equivalents
- $findchars_iso = [
- chr(130),
- chr(132),
- chr(133),
- chr(145),
- chr(146),
- chr(147),
- chr(148),
- ];
-
- // safe replacements
- $replacechars = [
- ',', // ‚
- ',,', // „
- '...', // …
- "'", // ‘
- "'", // ’
- '"', // “
- '"', // ”
- ];
-
- $string = str_replace(Utils::$context['utf8'] ? $findchars_utf8 : $findchars_iso, $replacechars, $string);
-
- return $string;
- }
-
- /**
- * Backward compatibility wrapper for parse() and/or getCodes().
- *
- * @param string|bool $message The message.
- * When an empty string, nothing is done.
- * When false we provide a list of BBC codes available.
- * When a string, the message is parsed and bbc handled.
- * @param bool $smileys Whether to parse smileys as well.
- * @param string $cache_id The cache ID.
- * @param array $parse_tags If set, only parses these tags rather than all of them.
- * @return string|array The parsed message or the list of BBCodes.
- */
- public static function backcompatParseBbc(string|bool $message, bool $smileys = true, string $cache_id = '', array $parse_tags = []): string|array
- {
- if ($message === false) {
- return self::getCodes();
- }
-
- self::load();
-
- $cache_id = (is_string($cache_id) || is_int($cache_id)) && strlen($cache_id) === strspn($cache_id, '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_') ? (string) $cache_id : '';
-
- $for_print = self::$parser->for_print;
- self::$parser->for_print = $smileys === 'print';
-
- $message = self::$parser->parse((string) $message, !empty($smileys), $cache_id, (array) $parse_tags);
-
- self::$parser->for_print = $for_print;
-
- return $message;
- }
-
- /**
- * Backward compatibility wrapper for parseSmileys().
- * Doesn't return anything, but rather modifies $message directly.
- *
- * @param string &$message The message to parse smileys in.
- */
- public static function backcompatParseSmileys(string &$message)
- {
- $message = self::load()->parseSmileys($message);
- }
-
- /**
- * Backward compatibility wrapper for unparse().
- *
- * @param string $string Text containing HTML
- * @return string The string with html converted to bbc
- */
- public function htmlToBbc(string $string): string
- {
- return self::load()->unparse($string);
- }
-
/*
* BBCode validation methods.
*/
@@ -2727,20 +2255,7 @@ protected function parseMessage(): void
$this->message .= "\n" . $tag['after'] . "\n";
}
- // Parse the smileys within the parts where it can be done safely.
- if ($this->smileys === true) {
- $message_parts = explode("\n", $this->message);
-
- for ($i = 0, $n = count($message_parts); $i < $n; $i += 2) {
- $message_parts[$i] = $this->parseSmileys($message_parts[$i]);
- }
-
- $this->message = implode('', $message_parts);
- }
- // No smileys, just get rid of the markers.
- else {
- $this->message = strtr($this->message, ["\n" => '']);
- }
+ $this->message = strtr($this->message, ["\n" => '']);
// Transform the first table row into a table header and wrap the rest
// in table body tags.
@@ -2852,7 +2367,7 @@ protected function setDisabled(): void
protected function setBbcCodes(): void
{
// If we already have a version of the BBCodes for the current language, use that.
- $locale_key = $this->locale . '|' . implode(',', $this->disabled);
+ $locale_key = self::$locale . '|' . implode(',', $this->disabled);
if (!empty($this->bbc_lang_locales[$locale_key])) {
$this->bbc_codes = $this->bbc_lang_locales[$locale_key];
@@ -3007,7 +2522,7 @@ function ($matches) {
*/
protected function fixHtml(string $data): string
{
- if (empty($this->enable_post_html) || !str_contains($data, '<')) {
+ if (empty(self::$enable_post_html) || !str_contains($data, '<')) {
return $data;
}
@@ -3019,10 +2534,10 @@ function ($matches) {
}
if (str_starts_with($matches[2], Config::$boardurl)) {
- return $this->enable_bbc ? '[iurl="' . $matches[2] . '"]' . $matches[3] . '[/iurl]' : '' . $matches[3] . '';
+ return self::$enable_bbc ? '[iurl="' . $matches[2] . '"]' . $matches[3] . '[/iurl]' : '' . $matches[3] . '';
}
- return $this->enable_bbc ? '[url="' . $matches[2] . '"]' . $matches[3] . '[/url]' : '' . $matches[3] . '';
+ return self::$enable_bbc ? '[url="' . $matches[2] . '"]' . $matches[3] . '[/url]' : '' . $matches[3] . '';
},
$data,
);
@@ -4225,7 +3740,6 @@ protected function resetRuntimeProperties(): void
$to_reset = [
'message',
'bbc_codes',
- 'smileys',
'parse_tags',
'open_tags',
'inside',
@@ -4239,6 +3753,7 @@ protected function resetRuntimeProperties(): void
$class_vars = get_class_vars(__CLASS__);
foreach ($to_reset as $var) {
+ unset($this->{$var});
$this->{$var} = $class_vars[$var];
}
}
@@ -4266,7 +3781,7 @@ private static function integrateBBC(): void
// Closures cannot be serialized, but they can be reflected.
if (($value['validate'] ?? null) instanceof \Closure) {
- $value['validate'] = (string) new ReflectionFunction($value['validate']);
+ $value['validate'] = (string) new \ReflectionFunction($value['validate']);
}
$serialized = serialize($value);
diff --git a/Sources/MarkdownParser.php b/Sources/Parsers/MarkdownParser.php
similarity index 98%
rename from Sources/MarkdownParser.php
rename to Sources/Parsers/MarkdownParser.php
index b9399bd1a3..ecf7f0053e 100644
--- a/Sources/MarkdownParser.php
+++ b/Sources/Parsers/MarkdownParser.php
@@ -13,7 +13,14 @@
declare(strict_types=1);
-namespace SMF;
+namespace SMF\Parsers;
+
+use SMF\Autolinker;
+use SMF\Config;
+use SMF\IntegrationHook;
+use SMF\Lang;
+use SMF\Parser;
+use SMF\Utils;
/**
* Converts Markdown to BBCode or HTML.
@@ -33,7 +40,7 @@
*
* SMF is capable of much more robust URI validation, so we use it.
*/
-class MarkdownParser
+class MarkdownParser extends Parser
{
/*****************
* Class constants
@@ -47,26 +54,7 @@ class MarkdownParser
* Used to set the output to HTML rendered the same way that the reference
* implementation of CommonMark would.
*/
- public const OUTPUT_HTML_STRICT = 0;
-
- /**
- * @var int
- *
- * Possible value for $this->output_type.
- *
- * Used to set the output to HTML rendered like the equivalent BBCode.
- * This is the default output type.
- */
- public const OUTPUT_HTML = 1;
-
- /**
- * @var int
- *
- * Possible value for $this->output_type.
- *
- * Used to convert Markdown into BBCode.
- */
- public const OUTPUT_BBC = 2;
+ public const OUTPUT_HTML_STRICT = 3;
/**
* @var int
@@ -725,8 +713,8 @@ class MarkdownParser
* Constructor.
*
* @param int $output_type The type of output to generate.
- * Value must be one of this class's OUTPUT_* constants.
- * Default: self::OUTPUT_HTML.
+ * Value must be one of this class's or its parent class's OUTPUT_*
+ * constants. Default: self::OUTPUT_HTML.
* @param ?int $hard_breaks How to handle line breaks in HTML output.
* Value should be a bitmask of this class's BR_* constants.
* If null, uses the value of Config::$modSettings['markdown_brs'].
@@ -735,13 +723,18 @@ class MarkdownParser
*/
public function __construct(int $output_type = self::OUTPUT_HTML, ?int $hard_breaks = null)
{
+ if ($output_type === self::OUTPUT_TEXT) {
+ $output_type === self::OUTPUT_HTML;
+ }
+
if (!in_array($output_type, [self::OUTPUT_BBC, self::OUTPUT_HTML, self::OUTPUT_HTML_STRICT])) {
throw new \ValueError();
}
- $this->output_type = $output_type;
+ parent::__construct();
- $this->hard_breaks = $hard_breaks ?? (int) (Config::$modSettings['markdown_brs'] ?? 0);
+ $this->hard_breaks = (int) ($hard_breaks ?? Config::$modSettings['markdown_brs'] ?? 0);
+ $this->output_type = $output_type;
// Maybe a mod wants to add a Markdown extension or something?
IntegrationHook::call('integrate_markdown', [&$this->block_types, &$this->render_methods]);
@@ -752,11 +745,11 @@ public function __construct(int $output_type = self::OUTPUT_HTML, ?int $hard_bre
*
* Getting Markdown and BBCode to play nicely with each other requires some
* extra handling, so $from_bbcode_parser should always be set to true if
- * the string was already processed by the SMF\BBCodeParser class.
+ * the string was already processed by the SMF\Parsers\BBCodeParser class.
*
* @param string $string The string to parse.
* @param string $from_bbcode_parser Whether the string was the output from
- * the SMF\BBCodeParser class.
+ * the SMF\Parsers\BBCodeParser class.
* @return string The result of parsing the string.
*/
public function parse(string $string, bool $from_bbcode_parser = false): string
@@ -3988,21 +3981,35 @@ protected function getMethod(string|bool|null $method): mixed
*/
protected function resetRuntimeProperties(): void
{
- foreach (get_class_vars($this::class) as $var => $value) {
- if (in_array($var, ['output_type', 'hard_breaks', 'parsers'])) {
- continue;
- }
+ // Reset these properties.
+ $to_reset = [
+ 'line_info',
+ 'structure',
+ 'open',
+ 'last_block',
+ 'link_reference_definitions',
+ 'in_code',
+ 'opening_fence_linenum',
+ 'opening_fence',
+ 'info_string',
+ 'in_html',
+ 'table_align',
+ 'placeholders',
+ 'rendered',
+ ];
- // Ensure p is always last.
- if ($var === 'block_types') {
- $p = $value['p'];
- unset($value['p']);
- $value['p'] = $p;
- }
+ $class_vars = get_class_vars(__CLASS__);
+ foreach ($to_reset as $var) {
unset($this->{$var});
+ $this->{$var} = $class_vars[$var];
+ }
- $this->{$var} = $value;
+ // Ensure p is always the last element in $this->block_types.
+ if (array_key_last($this->block_types) !== 'p') {
+ $p = $this->block_types['p'];
+ unset($this->block_types['p']);
+ $this->block_types['p'] = $p;
}
}
}
diff --git a/Sources/Parsers/SmileyParser.php b/Sources/Parsers/SmileyParser.php
new file mode 100644
index 0000000000..7c8d34f96d
--- /dev/null
+++ b/Sources/Parsers/SmileyParser.php
@@ -0,0 +1,252 @@
+smiley_preg_replacements = [];
+ $search_parts = [];
+ $smileys_path = Utils::htmlspecialchars(self::$smileys_url . '/' . rawurlencode(self::$smiley_set) . '/');
+
+ foreach ($data as $id => $smiley) {
+ $special_chars = Utils::htmlspecialchars($smiley['code'], ENT_QUOTES);
+
+ $smiley_code = '';
+
+ $this->smiley_preg_replacements[$smiley['code']] = $smiley_code;
+
+ $search_parts[] = $smiley['code'];
+
+ if ($smiley['code'] != $special_chars) {
+ $this->smiley_preg_replacements[$special_chars] = $smiley_code;
+ $search_parts[] = $special_chars;
+
+ // Some 2.0 hex htmlchars are in there as 3 digits; allow for finding leading 0 or not
+ $special_chars2 = preg_replace('/(\d{2});/', '$1;', $special_chars);
+
+ if ($special_chars2 != $special_chars) {
+ $this->smiley_preg_replacements[$special_chars2] = $smiley_code;
+ $search_parts[] = $special_chars2;
+ }
+ }
+ }
+
+ // This smiley regex makes sure it doesn't parse smileys within code tags (so [url=mailto:David@bla.com] doesn't parse the :D smiley)
+ $this->smiley_preg_search = '~(?<=[>:\?\.\s' . $non_breaking_space . '[\]()*\\\;]|(?smiley_preg_search, &$this->smiley_preg_replacements]);
+ }
+ }
+
+ /**
+ * Parse smileys in the passed string.
+ *
+ * The smiley parsing function which makes pretty faces appear :).
+ * If custom smiley sets are turned off by smiley_enable, the default set of smileys will be used.
+ * These are specifically not parsed in code tags [url=mailto:Dad@blah.com]
+ * Caches the smileys from the database or array in memory.
+ *
+ * @param string $string The string to parse smileys in.
+ * @return string The string with smiley images inserted.
+ */
+ public function parse(string $string): string
+ {
+ if (
+ self::$smiley_set == 'none'
+ || !isset($this->smiley_preg_search)
+ || empty($this->smiley_preg_replacements)
+ || trim($string) == ''
+ ) {
+ return $string;
+ }
+
+ // Don't parse smileys inside HTML or BBCode tags.
+ $parts = preg_split('~(<[^>]*>|\[\/?' . BBCodeParser::load()->getAllTagsRegex() . '[^\]]*\])~u', $string, -1, PREG_SPLIT_DELIM_CAPTURE);
+
+ for ($i = 0; $i < count($parts); $i++) {
+ if ($i % 2 === 0) {
+ $parts[$i] = preg_replace_callback(
+ $this->smiley_preg_search,
+ fn ($matches) => $this->smiley_preg_replacements[$matches[1]],
+ $parts[$i],
+ );
+ }
+ }
+
+ return implode('', $parts);
+ }
+
+ /**
+ * Converts HTML img tags for smileys back into smiley text.
+ *
+ * @param string $string Text containing HTML.
+ * @return string The string with smiley images converted to text.
+ */
+ public function unparse(string $string): string
+ {
+ $smiley_codes = array_map(fn ($smiley) => $smiley['code'], self::loadData(''));
+
+ return preg_replace_callback(
+ '~(\h?)]+alt="([^"]+)"[^>]+class="smiley"[^>]*>(\h?)~i',
+ fn ($match) => in_array(html_entity_decode($match[2]), $smiley_codes) ? $match[1] . html_entity_decode($match[2]) . $match[3] : $match[0],
+ $string,
+ );
+ }
+
+ /************************
+ * Public static methods.
+ ************************/
+
+ /**
+ * Returns a reusable instance of this class.
+ *
+ * Using this method to get a SmileyParser instance saves memory by avoiding
+ * creating redundant instances.
+ *
+ * @return object An instance of this class.
+ */
+ public static function load(): object
+ {
+ if (!isset(self::$parser)) {
+ self::$parser = new self();
+ }
+
+ return self::$parser;
+ }
+
+ /**
+ * Loads data for the requested smiley set from the database.
+ *
+ * @param string $set The name of the smiley set.
+ * @return array Data for all the smileys in the specified set.
+ */
+ public static function loadData(string $set): array
+ {
+ if ($set === 'none') {
+ return [];
+ }
+
+ if (isset(self::$data[$set])) {
+ return self::$data[$set];
+ }
+
+ // Cache for longer when customized smiley codes aren't enabled
+ $cache_time = !self::$custom_smileys_enabled ? 7200 : 480;
+ $cache_key = 'parsing_smileys' . ($set !== '' ? '_' . $set : '');
+
+ if (is_array($data = CacheApi::get($cache_key, $cache_time))) {
+ self::$data[$set] = $data;
+
+ return self::$data[$set];
+ }
+
+ // Load the smileys in reverse order by length so they don't get parsed incorrectly.
+ self::$data[$set] = [];
+
+ $request = Db::$db->query(
+ '',
+ 'SELECT s.id_smiley, s.code, f.filename, s.description
+ FROM {db_prefix}smileys AS s
+ JOIN {db_prefix}smiley_files AS f ON (s.id_smiley = f.id_smiley)
+ WHERE ' . ($set !== '' ? 'f.smiley_set = {string:smiley_set}' : '1=1') . (!self::$custom_smileys_enabled ? '
+ AND s.code IN ({array_string:default_codes})' : '') . '
+ ORDER BY LENGTH(s.code) DESC',
+ [
+ 'default_codes' => ['>:D', ':D', '::)', '>:(', ':))', ':)', ';)', ';D', ':(', ':o', '8)', ':P', '???', ':-[', ':-X', ':-*', ':\'(', ':-\\', '^-^', 'O0', 'C:-)', 'O:-)'],
+ 'smiley_set' => $set,
+ ],
+ );
+
+ while ($row = Db::$db->fetch_assoc($request)) {
+ self::$data[$set][(int) $row['id_smiley']] = [
+ 'code' => $row['code'],
+ 'filename' => $row['filename'],
+ 'description' => !empty(Lang::$txt['icon_' . strtolower($row['description'])]) ? Lang::$txt['icon_' . strtolower($row['description'])] : $row['description'],
+ ];
+ }
+
+ Db::$db->free_result($request);
+
+ CacheApi::put($cache_key, self::$data[$set], $cache_time);
+
+ return self::$data[$set];
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/Sources/Parsers/index.php b/Sources/Parsers/index.php
new file mode 100644
index 0000000000..976d292448
--- /dev/null
+++ b/Sources/Parsers/index.php
@@ -0,0 +1,9 @@
+
\ No newline at end of file
diff --git a/Sources/PersonalMessage/DraftPM.php b/Sources/PersonalMessage/DraftPM.php
index 15c8488d42..94b8d3fa55 100644
--- a/Sources/PersonalMessage/DraftPM.php
+++ b/Sources/PersonalMessage/DraftPM.php
@@ -15,13 +15,12 @@
namespace SMF\PersonalMessage;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\Draft;
use SMF\Lang;
-use SMF\MarkdownParser;
use SMF\PageIndex;
+use SMF\Parser;
use SMF\Theme;
use SMF\Time;
use SMF\User;
@@ -273,11 +272,10 @@ public static function showInProfile(int $memID = -1): void
Lang::censorText($row['subject']);
// BBC-ilize the message.
- $row['body'] = BBCodeParser::load()->parse($row['body'], true, 'draft' . $row['id_draft']);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $row['body'] = MarkdownParser::load()->parse($row['body'], true);
- }
+ $row['body'] = Parser::transform(
+ string: $row['body'],
+ options: ['cache_id' => 'draft' . $row['id_draft']],
+ );
// Have they provide who this will go to?
$recipients = [
diff --git a/Sources/PersonalMessage/PM.php b/Sources/PersonalMessage/PM.php
index 2ef1ee86f5..8b112bba12 100644
--- a/Sources/PersonalMessage/PM.php
+++ b/Sources/PersonalMessage/PM.php
@@ -19,7 +19,6 @@
use SMF\Actions\PersonalMessage as PMAction;
use SMF\ArrayAccessHelper;
use SMF\Autolinker;
-use SMF\BBCodeParser;
use SMF\Cache\CacheApi;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
@@ -29,9 +28,9 @@
use SMF\IntegrationHook;
use SMF\Lang;
use SMF\Mail;
-use SMF\MarkdownParser;
use SMF\Menu;
use SMF\Msg;
+use SMF\Parser;
use SMF\Security;
use SMF\Theme;
use SMF\Time;
@@ -403,11 +402,10 @@ public function format(int $counter = 0, array $format_options = []): array
}
// Run BBC interpreter on the message.
- $this->formatted['body'] = BBCodeParser::load()->parse($this->formatted['body'], true, 'pm' . $this->id);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $this->formatted['body'] = MarkdownParser::load()->parse($this->formatted['body'], true);
- }
+ $this->formatted['body'] = Parser::transform(
+ string: $this->formatted['body'],
+ options: ['cache_id' => 'pm' . $this->id],
+ );
return $this->formatted;
}
@@ -538,7 +536,7 @@ public static function get(int|array $ids, array $query_customizations = []): \G
// There will never be an ID 0, but SMF doesn't like empty arrays when you tell it to expect an array of integers...
$params['ids'] = empty($ids) ? [0] : array_filter(array_unique(array_map('intval', $ids)));
- foreach(self::queryData($selects, $params, $joins, $where, $order, $group, $limit) as $row) {
+ foreach (self::queryData($selects, $params, $joins, $where, $order, $group, $limit) as $row) {
$id = (int) $row['id_pm'];
yield (new self($id, $row));
@@ -1006,11 +1004,10 @@ public static function compose2(): bool
Msg::preparsecode($message);
// Make sure there's still some content left without the tags.
- $temp = BBCodeParser::load()->parse(Utils::htmlspecialchars($message, ENT_QUOTES), false);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $temp = MarkdownParser::load()->parse($temp, true);
- }
+ $temp = Parser::transform(
+ string: Utils::htmlspecialchars($message, ENT_QUOTES),
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN,
+ );
if (Utils::htmlTrim(strip_tags($temp, '')) === '' && (!User::$me->allowedTo('bbc_html') || !str_contains($message, '[html]'))) {
$post_errors[] = 'no_message';
@@ -1040,11 +1037,7 @@ public static function compose2(): bool
Msg::preparsecode(Utils::$context['preview_message'], true);
// Parse out the BBC if it is enabled.
- Utils::$context['preview_message'] = BBCodeParser::load()->parse(Utils::$context['preview_message']);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- Utils::$context['preview_message'] = MarkdownParser::load()->parse(Utils::$context['preview_message'], true);
- }
+ Utils::$context['preview_message'] = Parser::transform(Utils::$context['preview_message']);
// Censor, as always.
Lang::censorText(Utils::$context['preview_subject']);
@@ -1584,7 +1577,22 @@ public static function send(array $recipients, string $subject, string $message,
Lang::censorText($notification_texts[$lang]['body']);
- $notification_texts[$lang]['body'] = trim(Utils::htmlspecialcharsDecode(strip_tags(strtr(BBCodeParser::load()->parse(Utils::htmlspecialchars($notification_texts[$lang]['body']), false), ['
' => "\n", '' => "\n", '' => "\n", '[' => '[', ']' => ']']))));
+ $notification_texts[$lang]['body'] = Parser::transform(
+ string: Utils::htmlspecialchars($notification_texts[$lang]['body']),
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN,
+ output_type: Parser::OUTPUT_TEXT,
+ options: [
+ 'text_replacements' => [
+ '
' => "\n",
+ '' => "\n",
+ '' => "\n",
+ '[' => '[',
+ ']' => ']',
+ ],
+ ],
+ );
+
+ $notification_texts[$lang]['body'] = trim(Utils::htmlspecialcharsDecode($notification_texts[$lang]['body']));
} else {
$notification_texts[$lang]['body'] = '';
}
@@ -2126,11 +2134,10 @@ public static function reportErrors(array $error_types, array $named_recipients,
Lang::censorText($row_quoted['subject']);
Lang::censorText($row_quoted['body']);
- $row['body'] = BBCodeParser::load()->parse($row_quoted['body'], true, 'pm' . $row_quoted['id_pm']);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $row['body'] = MarkdownParser::load()->parse($row['body'], true);
- }
+ $row_quoted['body'] = Parser::transform(
+ string: $row_quoted['body'],
+ options: ['cache_id' => 'pm' . $row_quoted['id_pm']],
+ );
Utils::$context['quoted_message'] = [
'id' => $row_quoted['id_pm'],
@@ -2145,7 +2152,7 @@ public static function reportErrors(array $error_types, array $named_recipients,
'subject' => $row_quoted['subject'],
'time' => Time::create('@' . $row_quoted['msgtime'])->format(),
'timestamp' => $row_quoted['msgtime'],
- 'body' => $row['body'],
+ 'body' => $row_quoted['body'],
];
}
diff --git a/Sources/Poll.php b/Sources/Poll.php
index cf6365645d..8dd588f377 100644
--- a/Sources/Poll.php
+++ b/Sources/Poll.php
@@ -362,16 +362,10 @@ public function format(array $format_options = []): array
Lang::censorText($this->question);
- $question = BBCodeParser::load()->parse($option->question);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $question = MarkdownParser::load()->parse($question, true);
- }
-
$this->formatted = [
'id' => $this->id ?? 0,
'image' => 'normal_' . (empty($this->voting_locked) ? 'poll' : 'locked_poll'),
- 'question' => $question,
+ 'question' => Parser::transform($this->question),
'max_votes' => $this->max_votes,
'total_votes' => $this->total_voters,
'guest_vote' => $this->guest_vote,
@@ -428,11 +422,7 @@ public function format(array $format_options = []): array
$bar = round(($option->votes * 100) / $divisor, $precision);
$barWide = $bar == 0 ? 1 : floor(($bar * 8) / 3);
- $label = BBCodeParser::load()->parse($option->label);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $label = MarkdownParser::load()->parse($label, true);
- }
+ $label = Parser::transform($option->label);
// Now add it to the poll's contextual theme data.
$this->formatted['choices'][$i] = [
diff --git a/Sources/Profile.php b/Sources/Profile.php
index fc5ded1f15..54e7976f6e 100644
--- a/Sources/Profile.php
+++ b/Sources/Profile.php
@@ -1117,7 +1117,7 @@ public function loadCustomFields(string $area = 'summary'): void
// Parse BBCode
if ($cf_def['bbc']) {
- $output_html = Utils::adjustHeadingLevels(BBCodeParser::load()->parse($output_html), null);
+ $output_html = Utils::adjustHeadingLevels(Parser::transform($output_html), null);
} elseif ($cf_def['field_type'] == 'textarea') {
// Allow for newlines at least
$output_html = strtr($output_html, ["\n" => '
']);
@@ -1350,11 +1350,15 @@ public function loadSignatureData(): bool
Lang::censorText($signature);
- Utils::$context['member']['signature_preview'] = Utils::adjustHeadingLevels(BBCodeParser::load()->parse($signature, true, 'sig' . $this->id, BBCodeParser::getSigTags()), null);
+ Utils::$context['member']['signature_preview'] = Parser::transform(
+ string: $signature,
+ options: [
+ 'cache_id' => 'sig' . $this->id,
+ 'parse_tags' => Parser::getSigTags(),
+ ],
+ );
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- Utils::$context['member']['signature_preview'] = MarkdownParser::load()->parse(Utils::$context['member']['signature_preview'], true);
- }
+ Utils::$context['member']['signature_preview'] = Utils::adjustHeadingLevels(Utils::$context['member']['signature_preview'], null);
Utils::$context['member']['signature'] = $_POST['signature'];
}
@@ -1930,8 +1934,8 @@ public static function validateSignature(string &$value): bool|string
return 'signature_max_image_count';
}
- // What about too many smileys!
- $smiley_parsed = BBCodeParser::load()->parseSmileys($unparsed_signature);
+ // What about too many smileys?
+ $smiley_parsed = Parser::transform($unparsed_signature, Parser::INPUT_SMILEYS);
$smiley_count = substr_count(strtolower($smiley_parsed), 'prepareString()
- */
- private BBCodeParser $bbcparser;
-
/****************
* Public methods
****************/
@@ -311,8 +303,7 @@ public function indexedWordQuery(array $words, array $search_data): mixed
}
} else {
foreach (
- array_values(array_intersect_key($this->wildcard_words, array_flip($words['all_words'])))
- as $key => $wildcard_word
+ array_values(array_intersect_key($this->wildcard_words, array_flip($words['all_words']))) as $key => $wildcard_word
) {
$wildcard_word = !empty($this->params['ignore_accents']) ? $this->removeAccents($wildcard_word) : $this->escapeAccents($wildcard_word);
@@ -1019,18 +1010,6 @@ protected function save(array $word_data): void
*/
protected function prepareString(string $string): string
{
- if (!isset($this->bbcparser)) {
- // BBCodeParser complains if User::$me is not set.
- if (!isset(User::$me)) {
- User::setMe(0);
- }
-
- $this->bbcparser = new BBCodeParser();
-
- // Leave out anything that would be skipped for printing.
- $this->bbcparser->for_print = true;
- }
-
// Disable image proxy because we want the original URLs.
$image_proxy_enabled = Config::$image_proxy_enabled ?? false;
Config::$image_proxy_enabled = false;
@@ -1045,13 +1024,18 @@ protected function prepareString(string $string): string
$images = $_GET['images'] ?? null;
unset($_GET['images']);
- // Parse the BBCode.
- $string = $this->bbcparser->parse($string, false);
-
- // Parse the Markdown.
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $string = MarkdownParser::load()->parse($string, true);
- }
+ // Parse the BBCode and Markdown.
+ $string = Parser::transform(
+ string: $string,
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN,
+ output_type: Parser::OUTPUT_TEXT,
+ options: [
+ 'for_print' => true,
+ 'preg_replace' => [
+ '/<[^>]+>/' => fn ($matches) => $matches[0] . ' ',
+ ],
+ ],
+ );
// Put stuff back the way we found it.
Config::$image_proxy_enabled = $image_proxy_enabled;
@@ -1061,9 +1045,6 @@ protected function prepareString(string $string): string
$_GET['images'] = $images;
}
- // Remove HTML.
- $string = strip_tags(is_string($string) ? preg_replace('/<[^>]+>/', '$0 ', $string) : '');
-
// Decode 4-byte Unicode characters.
$string = mb_decode_numericentity($string, [0x010000, 0x10FFFF, 0, 0xFFFFFF], 'UTF-8');
diff --git a/Sources/Search/SearchApi.php b/Sources/Search/SearchApi.php
index 1eac4d33bb..df7048ebc1 100644
--- a/Sources/Search/SearchApi.php
+++ b/Sources/Search/SearchApi.php
@@ -17,13 +17,13 @@
use SMF\Actions\Search;
use SMF\BackwardCompatibility;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\ErrorHandler;
use SMF\IntegrationHook;
use SMF\Lang;
use SMF\PackageManager\SubsPackage;
+use SMF\Parser;
use SMF\User;
use SMF\Utils;
@@ -1016,7 +1016,7 @@ protected function setBlacklistedWords(): void
// Blacklist the BBC tags.
$this->blacklisted_words = array_unique(array_merge(
$this->blacklisted_words,
- array_map(fn ($code) => $code['tag'], BBCodeParser::getCodes()),
+ array_map(fn ($code) => $code['tag'], Parser::getBBCodes()),
));
IntegrationHook::call('integrate_search_blacklisted_words', [&$this->blacklisted_words]);
diff --git a/Sources/Search/SearchResult.php b/Sources/Search/SearchResult.php
index 51b6dcc3b2..749d9e2a53 100644
--- a/Sources/Search/SearchResult.php
+++ b/Sources/Search/SearchResult.php
@@ -16,12 +16,11 @@
namespace SMF\Search;
use SMF\Autolinker;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\IP;
use SMF\Lang;
-use SMF\MarkdownParser;
+use SMF\Parser;
use SMF\Theme;
use SMF\Time;
use SMF\User;
@@ -210,12 +209,14 @@ public function format(int $counter = 0, array $format_options = []): array
// Set the number of characters before and after the searched keyword.
$charLimit = 50;
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $this->body = MarkdownParser::load(MarkdownParser::OUTPUT_BBC)->parse($this->body);
- }
-
$this->body = strtr($this->body, ["\n" => ' ', '
' => "\n", '
' => "\n", '
' => "\n"]);
- $this->body = BBCodeParser::load()->parse($this->body, $this->smileys_enabled, $this->id_msg);
+
+ $this->body = Parser::transform(
+ string: $this->body,
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN | ($this->smileys_enabled ? Parser::INPUT_SMILEYS : 0),
+ options: ['cache_id' => $this->id_msg],
+ );
+
$this->body = strip_tags(strtr($this->body, ['' => '
', '' => '
']), '
');
if (Utils::entityStrlen($this->body) > $charLimit) {
@@ -259,11 +260,11 @@ public function format(int $counter = 0, array $format_options = []): array
$this->body_highlighted = self::highlight($this->body, SearchApi::$loadedApi->searchArray);
} else {
// Run BBC interpreter on the message.
- $this->body = BBCodeParser::load()->parse($this->body, $this->smileys_enabled, $this->id_msg);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $this->body = MarkdownParser::load()->parse($this->body, true);
- }
+ $this->body = Parser::transform(
+ string: $this->body,
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN | ($this->smileys_enabled ? Parser::INPUT_SMILEYS : 0),
+ options: ['cache_id' => $this->id_msg],
+ );
$this->subject_highlighted = self::highlight($this->subject, SearchApi::$loadedApi->searchArray);
$this->body_highlighted = self::highlight($this->body, SearchApi::$loadedApi->searchArray);
@@ -480,7 +481,7 @@ public static function get(int|array $ids, array $query_customizations = []): \G
$params['message_list'] = self::$messages_to_get = array_filter(array_unique(array_map('intval', (array) $ids)));
}
- foreach(self::queryData($selects, $params, $joins, $where, $order, $group, $limit) as $row) {
+ foreach (self::queryData($selects, $params, $joins, $where, $order, $group, $limit) as $row) {
$id = (int) $row['id_msg'];
yield (new self($id, $row));
diff --git a/Sources/ServerSideIncludes.php b/Sources/ServerSideIncludes.php
index cf93a82f0b..f9fd7c99dd 100644
--- a/Sources/ServerSideIncludes.php
+++ b/Sources/ServerSideIncludes.php
@@ -522,11 +522,11 @@ public static function queryPosts(
$row['body'] = Autolinker::load(true)->makeLinks($row['body']);
}
- $row['body'] = BBCodeParser::load()->parse($row['body'], (bool) $row['smileys_enabled'], $row['id_msg']);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $row['body'] = MarkdownParser::load()->parse($row['body'], true);
- }
+ $row['body'] = Parser::transform(
+ string: $row['body'],
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN | ((bool) $row['smileys_enabled'] ? Parser::INPUT_SMILEYS : 0),
+ options: ['cache_id' => (int) $row['id_msg']],
+ );
$row['body'] = strtr($row['body'], [Utils::TAB_SUBSTITUTE => '' . "\t" . '']);
@@ -708,11 +708,18 @@ public static function recentTopics(int $num_recent = 8, ?array $exclude_boards
$posts = [];
while ($row = Db::$db->fetch_assoc($request)) {
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $row['body'] = MarkdownParser::load(MarkdownParser::OUTPUT_BBC)->parse($row['body']);
- }
-
- $row['body'] = strip_tags(strtr(BBCodeParser::load()->parse($row['body'], (bool) $row['smileys_enabled'], $row['id_msg']), ['
' => '
', Utils::TAB_SUBSTITUTE => ' ']));
+ $row['body'] = Parser::transform(
+ string: $row['body'],
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN | ((bool) $row['smileys_enabled'] ? Parser::INPUT_SMILEYS : 0),
+ output_type: Parser::OUTPUT_TEXT,
+ options: [
+ 'cache_id' => (int) $row['id_msg'],
+ 'str_replace' => [
+ '
' => '
',
+ Utils::TAB_SUBSTITUTE => ' ',
+ ],
+ ],
+ );
if (Utils::entityStrlen($row['body']) > 128) {
$row['body'] = Utils::entitySubstr($row['body'], 0, 128) . '...';
@@ -2249,11 +2256,11 @@ public static function boardNews(?int $board = null, ?int $limit = null, ?int $s
$row['body'] .= '...';
}
- $row['body'] = BBCodeParser::load()->parse($row['body'], (bool) $row['smileys_enabled'], $row['id_msg']);
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $row['body'] = MarkdownParser::load()->parse($row['body'], true);
- }
+ $row['body'] = Parser::transform(
+ string: $row['body'],
+ input_types: Parser::INPUT_BBC | Parser::INPUT_MARKDOWN | ((bool) $row['smileys_enabled'] ? Parser::INPUT_SMILEYS : 0),
+ options: ['cache_id' => (int) $row['id_msg']],
+ );
$row['body'] = strtr($row['body'], [Utils::TAB_SUBSTITUTE => '' . "\t" . '']);
diff --git a/Sources/Subs-Compat.php b/Sources/Subs-Compat.php
index bca208ddbf..bd3151ba23 100644
--- a/Sources/Subs-Compat.php
+++ b/Sources/Subs-Compat.php
@@ -57,11 +57,9 @@ function Activate()
}
/**
- * End
- * Actions\Activate
* Begin
* Actions\Admin\ACP
- * */
+ */
function AdminMain()
{
return Actions\Admin\ACP::call();
@@ -108,9 +106,6 @@ function adminLogin(string $type = 'admin'): void
}
/**
- * End
- * Actions\Admin\ACP
- *
* Begin
* Actions\Admin\AntiSpam
*/
@@ -120,9 +115,6 @@ function ModifyAntispamSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\AntiSpam
- *
* Begin
* Actions\Admin\Attachments
*/
@@ -192,9 +184,6 @@ function TransferAttachments(): void
}
/**
- * End
- * Actions\Admin\Attachments
- *
* Begin
* Actions\Admin\Bans
*/
@@ -234,9 +223,6 @@ function BanLog(): void
}
/**
- * End
- * Actions\Admin\Bans
- *
* Begin
* Actions\Admin\Boards
*/
@@ -251,9 +237,6 @@ function EditBoardSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Boards
- *
* Begin
* Actions\Admin\Calendar
*/
@@ -278,9 +261,6 @@ function ModifyCalendarSettings(bool $return_config = false): void
}
/**
- * End
- * Actions\Admin\Calendar
- *
* Begin
* Actions\Admin\EndSession
*/
@@ -290,9 +270,6 @@ function AdminEndSession(): void
}
/**
- * End
- * Actions\Admin\EndSession
- *
* Begin
* Actions\Admin\ErrorLog
*/
@@ -302,9 +279,6 @@ function ViewErrorLog(): void
}
/**
- * End
- * Actions\Admin\ErrorLog
- *
* Begin
* Actions\Admin\Features
*/
@@ -359,9 +333,6 @@ function ModifyAlertsSettings(): void
}
/**
- * End
- * Actions\Admin\Features
- *
* Begin
* Actions\Admin\Find
*/
@@ -371,9 +342,6 @@ function AdminSearch(): void
}
/**
- * End
- * Actions\Admin\Find
- *
* Begin
* Actions\Admin\Home
*/
@@ -383,9 +351,6 @@ function AdminHome(): void
}
/**
- * End
- * Actions\Admin\Home
- *
* Begin
* Actions\Admin\Languages
*/
@@ -420,9 +385,6 @@ function ModifyLanguage(): void
}
/**
- * End
- * Actions\Admin\Languages
- *
* Begin
* Actions\Admin\Logs
*/
@@ -432,9 +394,6 @@ function AdminLogs(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Logs
- *
* Begin
* Actions\Admin\Mail
*/
@@ -469,9 +428,6 @@ function TestMailSend(): void
}
/**
- * End
- * Actions\Admin\Mail
- *
* Begin
* Actions\Admin\Maintenance
*/
@@ -608,9 +564,6 @@ function MaintainRemoveOldDrafts(): void
}
/**
- * End
- * Actions\Admin\Maintainence
- *
* Begin
* Actions\Admin\Membergroups
*/
@@ -645,9 +598,6 @@ function ModifyMembergroupsettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Membergoups
- *
* Begin
* Actions\Admin\Members
*/
@@ -677,9 +627,6 @@ function SearchMembers(): void
}
/**
- * End
- * Actions\Admin\Members
- *
* Begin
* Actions\Admin\Mods
*/
@@ -689,9 +636,6 @@ function ModifyModSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Mods
- *
* Begin
* Actions\Admin\News
*/
@@ -731,9 +675,6 @@ function ModifyNewsSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\News
- *
* Begin
* Actions\Admin\Permissions
*/
@@ -828,9 +769,6 @@ function GeneralPermissionSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Permissions
- *
* Begin
* Actions\Admin\Post
*/
@@ -855,9 +793,6 @@ function ModifyDraftSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Posts
- *
* Begin
* Actions\Admin\Registration
*/
@@ -892,9 +827,6 @@ function ModifyRegistrationSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Registration
- *
* Begin
* Actions\Admin\RepairBoards
*/
@@ -904,9 +836,6 @@ function RepairBoards(): void
}
/**
- * End
- * Actions\Admin\RepairBoards
- *
* Begin
* Actions\Admin\Reports
*/
@@ -941,9 +870,6 @@ function StaffReport(): void
}
/**
- * End
- * Actions\Admin\Reports
- *
* Begin
* Actions\Admin\Search
*/
@@ -973,9 +899,6 @@ function CreateMessageIndex(): void
}
/**
- * End
- * Actions\Admin\Search
- *
* Begin
* Actions\Admin\SearchEngines
*/
@@ -1020,9 +943,6 @@ function EditSpider(): void
}
/**
- * End
- * Actions\Admin\SearchEngine
- *
* Begin
* Actions\Admin\Server
*/
@@ -1087,9 +1007,6 @@ function ShowPHPinfoSettings(): void
}
/**
- * End
- * Actions\Admin\Server
- *
* Begin
* Actions\Admin\Smileys
*/
@@ -1129,9 +1046,6 @@ function EditMessageIcons(): void
}
/**
- * End
- * Actions\Admin\Smileys
- *
* Begin
* Actions\Admin\Subscriptions
*/
@@ -1196,9 +1110,6 @@ function ModifySubscriptionSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Subscriptions
- *
* Begin
* Actions\Admin\Task
*/
@@ -1228,9 +1139,6 @@ function TaskSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Tasks
- *
* Begin
* Actions\Admin\Themes
*/
@@ -1280,9 +1188,6 @@ function CopyTemplate(): void
}
/**
- * End
- * Actions\Admin\Themes
- *
* Begin
* Actions\Admin\Warnings
*/
@@ -1292,9 +1197,6 @@ function ModifyWarningSettings(bool $return_config = false): ?array
}
/**
- * End
- * Actions\Admin\Warnings
- *
* Begin
* Actions\Moderation\EndSession
*/
@@ -1304,9 +1206,6 @@ function ModEndSession(): void
}
/**
- * End
- * Actions\Moderation\EndSession
- *
* Begin
* Actions\Moderation\Home
*/
@@ -1316,9 +1215,6 @@ function ModerationHome(): void
}
/**
- * End
- * Actions\Moderation\Home
- *
* Begin
* Actions\Moderation\Logs
*/
@@ -1328,9 +1224,6 @@ function ViewModlog(): void
}
/**
- * End
- * Actions\Moderation\Logs
- *
* Begin
* Actions\Moderation\Main
*/
@@ -1345,9 +1238,6 @@ function ModerationMail(bool $dont_call = false): void
}
/**
- * End
- * Actions\Moderation\Main
- *
* Begin
* Actions\Moderation\Posts
*/
@@ -1377,9 +1267,6 @@ function ApproveMessage(): void
}
/**
- * End
- * Actions\Moderation\Posts
- *
* Begin
* Actions\Moderation\ReportedContent
*/
@@ -1424,9 +1311,6 @@ function EditComment(): void
}
/**
- * End
- * Actions\Moderation\ReportedContent
- *
* Begin
* Actions\Moderation\ShowNotice
*/
@@ -1436,9 +1320,6 @@ function ShowNotice(): void
}
/**
- * End
- * Actions\Moderation\ShowNotice
- *
* Begin
* Actions\Moderation\Warnings
*/
@@ -1463,9 +1344,6 @@ function ModifyWarningTemplate(): void
}
/**
- * End
- * Actions\Moderation\Warnings
- *
* Begin
* Actions\Moderation\WatchedUsers
*/
@@ -1475,9 +1353,6 @@ function ViewWatchedUsers(): void
}
/**
- * End
- * Actions\Moderation\WatchedUsers
- *
* Begin
* Actions\Profile\Account
*/
@@ -1487,9 +1362,6 @@ function account(): void
}
/**
- * End
- * Actions\Profile\Account
- *
* Begin
* Actions\Profile\Activate
*/
@@ -1499,9 +1371,6 @@ function activateAccount(): void
}
/**
- * End
- * Actions\Profile\Activate
- *
* Begin
* Actions\Profile\AlertsPopup
*/
@@ -1511,9 +1380,6 @@ function alerts_popup(): void
}
/**
- * End
- * Actions\Profile\AlertsPopup
- *
* Begin
* Actions\Profile\BuddyIgnoreLists
*/
@@ -1543,9 +1409,6 @@ function editIgnoreList(int $memID): void
}
/**
- * End
- * Actions\Profile\BuddyIgnoreLists
- *
* Begin
* Actions\Profile\Delete
*/
@@ -1560,9 +1423,6 @@ function deleteAccount2(int $memID): void
}
/**
- * End
- * Actions\Profile\Delete
- *
* Begin
* Actions\Profile\Export
*/
@@ -1582,9 +1442,6 @@ function get_export_formats(): array
}
/**
- * End
- * Actions\Profile\Export
- *
* Begin
* Actions\Profile\ExportAttachment
*/
@@ -1594,9 +1451,6 @@ function export_attachment(): void
}
/**
- * End
- * Actions\Profile\ExportAttachment
- *
* Begin
* Actions\Profile\ExportDownload
*/
@@ -1606,9 +1460,6 @@ function download_export_file(): void
}
/**
- * End
- * Actions\Profile\ExportDownload
- *
* Begin
* Actions\Profile\ForumProfile
*/
@@ -1618,9 +1469,6 @@ function forumProfile(): void
}
/**
- * End
- * Actions\Profile\ForumProfile
- *
* Begin
* Actions\Profile\GroupMembership
*/
@@ -1635,9 +1483,6 @@ function groupMembership2(int $memID): string
}
/**
- * End
- * Actions\Profile\GroupMembership
- *
* Begin
* Actions\Profile\IgnoreBoards
*/
@@ -1647,9 +1492,6 @@ function ignoreboards(): void
}
/**
- * End
- * Actions\Profile\IgnoreBoards
- *
* Begin
* Actions\Profile\IssueWarning
*/
@@ -1662,9 +1504,6 @@ function issueWarning(int $memID): void
}
/**
- * End
- * Actions\Profile\IssueWarning
- *
* Begin
* Actions\Profile\Main
*/
@@ -1674,9 +1513,6 @@ function ModifyProfile(): void
}
/**
- * End
- * Actions\Profile\Main
- *
* Begin
* Actions\Profile\Notification
*/
@@ -1728,9 +1564,6 @@ function makeNotificationChanges(int $memID): void
}
/**
- * End
- * Actions\Profile\Notification
- *
* Begin
* Actions\Profile\PaidSubs
*/
@@ -1740,9 +1573,6 @@ function subscriptions(): void
}
/**
- * End
- * Actions\Profile\PaidSubs
- *
* Begin
* Actions\Profile\Popup
*/
@@ -1752,9 +1582,6 @@ function profile_popup(): void
}
/**
- * End
- * Actions\Profile\Popup
- *
* Begin
* Actions\Profile\ShowAlerts
*/
@@ -1767,9 +1594,6 @@ function showAlerts(int $memID): void
}
/**
- * End
- * Actions\Profile\ShowAlerts
- *
* Begin
* Actions\Profile\ShowPermissions
*/
@@ -1782,9 +1606,6 @@ function showPermissions(int $memID): void
}
/**
- * End
- * Actions\Profile\ShowPermissions
- *
* Begin
* Actions\Profile\ShowPost
*/
@@ -1804,9 +1625,6 @@ function showAttachments(int $memID): void
}
/**
- * End
- * Actions\Profile\ShowPosts
- *
* Begin
* Actions\Profile\StatPanel
*/
@@ -1816,9 +1634,6 @@ function statPanel(int $memID): void
}
/**
- * End
- * Actions\Profile\StatPanel
- *
* Begin
* Actions\Profile\Summary
*/
@@ -1828,9 +1643,6 @@ function summary(int $memID): void
}
/**
- * End
- * Actions\Profile\Summary
- *
* Begin
* Actions\Profile\TFADisable
*/
@@ -1840,9 +1652,6 @@ function tfadisable(): void
}
/**
- * End
- * Actions\Profile\TFDADisable
- *
* Begin
* Actions\Profile\TFASetup
*/
@@ -1852,9 +1661,6 @@ function tfasetup(): void
}
/**
- * End
- * Actions\Profile\TFASetup
- *
* Begin
* Actions\Profile\ThemeOptions
*/
@@ -1864,9 +1670,6 @@ function theme(): void
}
/**
- * End
- * Actions\Profile\ThemeOptions
- *
* Begin
* Actions\Profile\Tracking
*/
@@ -1900,9 +1703,6 @@ function TrackLogins(int $memID): void
}
/**
- * End
- * Actions\Profile\Tracking
- *
* Begin
* Actions\Profile\ViewWarning
*/
@@ -1912,9 +1712,6 @@ function viewWarning(int $memID): void
}
/**
- * End
- * Actions\Profile\ViewWarning
- *
* Begin
* Actions\Agreement
*/
@@ -1934,9 +1731,6 @@ function canRequirePrivacyPolicy(): bool
}
/**
- * End
- * Actions\Agreement
- *
* Begin
* Actions\AgreementAccept
*/
@@ -1946,9 +1740,6 @@ function AcceptAgreement(): void
}
/**
- * End
- * Actions\AgreementAccept
- *
* Begin
* Actions\Announce
*/
@@ -1968,9 +1759,6 @@ function AnnouncementSend(): void
}
/**
- * End
- * Actions\Announce
- *
* Begin
* Actions\AttachmentApprove
*/
@@ -1980,9 +1768,6 @@ function ApproveAttach(): void
}
/**
- * End
- * Actions\AttachmentApprove
- *
* Begin
* Actions\AttachmentDownload
*/
@@ -1992,9 +1777,6 @@ function showAttachment(): void
}
/**
- * End
- * Actions\AttachementDownload
- *
* Begin
* Actions\AutoSuggest
*/
@@ -2023,9 +1805,6 @@ function AutoSuggest_Search_SMFVersions(): void
}
/**
- * End
- * Actions\AutoSuggest
- *
* Begin
* Actions\BoardIndex
*/
@@ -2045,9 +1824,6 @@ function getBoardIndex(array $board_index_options): array
}
/**
- * End
- * Actions\BoardIndex
- *
* Begin
* Actions\BuddyListToggle
*/
@@ -2057,9 +1833,6 @@ function BuddyListToggle(): void
}
/**
- * End
- * Actions\BuddyListToggle
- *
* Begin
* Actions\Calendar
*/
@@ -2173,9 +1946,6 @@ function convertDateToEnglish(string $date): string
}
/**
- * End
- * Actions\Calendar
- *
* Begin
* Actions\CoppaForm
*/
@@ -2185,9 +1955,6 @@ function CoppaForm(): void
}
/**
- * End
- * Actions\CoppaForm
- *
* Begin
* Actions\Credits
*/
@@ -2197,9 +1964,6 @@ function Credits(bool $in_admin = false): void
}
/**
- * End
- * Actions\Credits
- *
* Begin
* Actions\Display
*/
@@ -2209,9 +1973,6 @@ function Display(): void
}
/**
- * End
- * Actions\Display
- *
* Begin
* Actions\DisplayAdminFile
*/
@@ -2221,9 +1982,6 @@ function DisplayAdminFile(): void
}
/**
- * End
- * Actions\DisplayAdminFile
- *
* Begin
* Actions\Feed
*/
@@ -2243,9 +2001,6 @@ function cdata_parse(string $data, string $ns = '', bool $force = false): string
}
/**
- * End
- * Actions\Feed
- *
* Begin
* Actions\FindMember
* @deprecated
@@ -2256,9 +2011,6 @@ function JSMembers(): void
}
/**
- * End
- * Actions\FindMember
- *
* Begin
* Actions\Groups
*/
@@ -2288,9 +2040,6 @@ function GroupRequests(): void
}
/**
- * End
- * Actions\Groups
- *
* Begin
* Actions\Help
*/
@@ -2305,9 +2054,6 @@ function HelpIndex(): void
}
/**
- * End
- * Actions\Help
- *
* Begin
* Actions\HelpAdmin
*/
@@ -2317,9 +2063,6 @@ function ShowAdminHelp(): void
}
/**
- * End
- * Actions\HelpAdmin
- *
* Begin
* Actions\JavaScriptModify
*/
@@ -2329,9 +2072,6 @@ function JavaScriptModify(): void
}
/**
- * End
- * Actions\JavaScriptModify
- *
* Begin
* Actions\Login
*/
@@ -2341,9 +2081,6 @@ function Login(): void
}
/**
- * End
- * Actions\Login
- *
* Begin
* Actions\Login2
*/
@@ -2374,9 +2111,6 @@ function validatePasswordFlood(
}
/**
- * End
- * Actions\Login2
- *
* Begin
* Actions\LoginTFA
*/
@@ -2386,9 +2120,6 @@ function LoginTFA(): void
}
/**
- * End
- * Actions\LoginTFA
- *
* Begin
* Actions\Logout
*/
@@ -2398,9 +2129,6 @@ function Logout(): void
}
/**
- * End
- * Actions\Logout
- *
* Begin
* Actions\Memberlist
*/
@@ -2430,9 +2158,6 @@ function getCustFieldsMList(): array
}
/**
- * End
- * Actions\Memberlist
- *
* Begin
* Actions\MessageIndex
*/
@@ -2452,9 +2177,6 @@ function buildTopicContext(array $row): void
}
/**
- * End
- * Actions\MessageIndex
- *
* Begin
* Actions\MsgDelete
*/
@@ -2464,9 +2186,6 @@ function DeleteMessage(): void
}
/**
- * End
- * Actions\MsgDelete
- *
* Begin
* Actions\Notify
*/
@@ -2496,9 +2215,6 @@ function createUnsubscribeToken(int $memID, string $email, string $type = '', in
}
/**
- * End
- * Actions\Notify
- *
* Begin
* Actions\NotifyAnnouncements
*/
@@ -2508,9 +2224,6 @@ function AnnouncementsNotify(): void
}
/**
- * End
- * Actions\NotifyAnnouncements
- *
* Begin
* Actions\NotifyBoard
*/
@@ -2520,9 +2233,6 @@ function BoardNotify(): void
}
/**
- * End
- * Actions\NotifyBoard
- *
* Begin
* Actions\NotifyTopic
*/
@@ -2532,9 +2242,6 @@ function TopicNotify(): void
}
/**
- * End
- * Actions\NotifyTopic
- *
* Begin
* Actions\PersonalMessage
*/
@@ -2614,9 +2321,6 @@ function MessageDrafts(): void
}
/**
- * End
- * Actions\PersonalMessage
- *
* Begin
* Actions\Post
*/
@@ -2626,9 +2330,6 @@ function Post(): void
}
/**
- * End
- * Actions\Post
- *
* Begin
* Actions\Post2
*/
@@ -2638,9 +2339,6 @@ function Post2(): void
}
/**
- * End
- * Actions\Post2
- *
* Begin
* Actions\QuickModeration
*/
@@ -2650,9 +2348,6 @@ function QuickModeration(): void
}
/**
- * End
- * Actions\QuickModeration
- *
* Begin
* Actions\QuickModerationInTopic
*/
@@ -2662,9 +2357,6 @@ function QuickInTopicModeration(): void
}
/**
- * End
- * Actions\QuickModerationInTopic
- *
* Begin
* Actions\QuoteFast
*/
@@ -2674,9 +2366,6 @@ function QuoteFast(): void
}
/**
- * End
- * Actions\QuoteFast
- *
* Begin
* Actions\Recent
*/
@@ -2691,9 +2380,6 @@ function getLastPost(): array
}
/**
- * End
- * Actions\Recent
- *
* Begin
* Actions\Register
*/
@@ -2703,9 +2389,6 @@ function Register(array $reg_errors = []): void
}
/**
- * End
- * Actions\Register
- *
* Begin
* Actions\Register2
*/
@@ -2720,9 +2403,6 @@ function registerMember(array &$reg_options, bool $return_errors = false): int|a
}
/**
- * End
- * Actions\Register2
- *
* Begin
* Actions\Reminder
*/
@@ -2732,9 +2412,6 @@ function RemindMe(): void
}
/**
- * End
- * Actions\Reminder
- *
* Begin
* Actions\ReportToMod
*/
@@ -2759,9 +2436,6 @@ function reportUser($id_member, $reason): void
}
/**
- * End
- * Actions\ReportToMod
- *
* Begin
* Actions\RequestMembers
*/
@@ -2771,9 +2445,6 @@ function RequestMembers(): void
}
/**
- * End
- * Actions\RequestMembers
- *
* Begin
* Actions\Search
*/
@@ -2783,9 +2454,6 @@ function PlushSearch1(): void
}
/**
- * End
- * Actions\Search
- *
* Begin
* Actions\Search2
*/
@@ -2795,9 +2463,6 @@ function PlushSearch2(): void
}
/**
- * End
- * Actions\Search2
- *
* Begin
* Actions\SendActivation
*/
@@ -2807,9 +2472,6 @@ function SendActivation(): void
}
/**
- * End
- * Actions\SendActivation
- *
* Begin
* Actions\SmStats
*/
@@ -2819,9 +2481,6 @@ function SMStats(): void
}
/**
- * End
- * Actions\SmStats
- *
* Begin
* Actions\Stats
*/
@@ -2831,9 +2490,6 @@ function DisplayStats(): void
}
/**
- * End
- * Actions\Stats
- *
* Begin
* Actions\TopicMerge
*/
@@ -2858,9 +2514,6 @@ function MergeDone(): void
}
/**
- * End
- * Actions\TopicMerge
- *
* Begin
* Actions\TopicMove
*/
@@ -2870,9 +2523,6 @@ function MoveTopic(): void
}
/**
- * End
- * Actions\TopicMove
- *
* Begin
* Actions\TopicMove2
*/
@@ -2887,9 +2537,6 @@ function moveTopicConcurrence()
}
/**
- * End
- * Actions\TopicMove2
- *
* Begin
* Actions\TopicPrint
*/
@@ -2899,9 +2546,6 @@ function PrintTopic(): void
}
/**
- * End
- * Actions\TopicPrint
- *
* Begin
* Actions\TopicRemove
*/
@@ -2921,9 +2565,6 @@ function RemoveOldTopics2()
}
/**
- * End
- * Actions\TopicRemove
- *
* Begin
* Actions\TopicRestore
*/
@@ -2933,9 +2574,6 @@ function RestoreTopic(): void
}
/**
- * End
- * Actions\TopicRestore
- *
* Begin
* Actions\TopicSplit
*/
@@ -2970,9 +2608,6 @@ function SplitSelectionExecute(): void
}
/**
- * End
- * Actions\TopicSplit
- *
* Begin
* Actions\TrackIP
*/
@@ -2983,9 +2618,6 @@ function TrackIP(int $memID = 0): void
}
/**
- * End
- * Actions\TrackIP
- *
* Begin
* Actions\Unread
*/
@@ -2995,9 +2627,6 @@ function UnreadTopics(): void
}
/**
- * End
- * Actions\Unread
- *
* Begin
* Actions\VerificationCode
*/
@@ -3007,9 +2636,6 @@ function VerificationCode(): void
}
/**
- * End
- * Actions\VerificationCode
- *
* Begin
* Actions\ViewQUery
*/
@@ -3019,9 +2645,6 @@ function ViewQuery(): void
}
/**
- * End
- * Actions\ViewQUery
- *
* Begin
* Actions\Who
*/
@@ -3036,9 +2659,6 @@ function determineActions(string|array $urls, string|bool $preferred_prefix = fa
}
/**
- * End
- * Actions\Who
- *
* Begin
* Actions\XmlHttp
*/
@@ -3063,10 +2683,6 @@ function RetrievePreview(): void
}
/**
- * End
- * Actions\XmlHttp
- * End Actions\*
- *
* Begin
* Cache\CacheApi
*/
@@ -3101,9 +2717,6 @@ function cache_get_data(string $key, int $ttl = 120): mixed
}
/**
- * End
- * Cache\CacheApi
- *
* Begin
* Db\DatabaseApi
*/
@@ -3118,9 +2731,6 @@ function db_extend()
}
/**
- * End
- * Db\DatabaseApi
- *
* Begin
* Graphics\Image
*/
@@ -3211,9 +2821,6 @@ function resizeImage(
}
/**
- * End
- * Graphics\Image
- *
* Begin
* Packagemanager\SubsPackage
*/
@@ -3413,9 +3020,6 @@ function package_validate_send(array $sendData): array
}
/**
- * End
- * PackageManager\SubsPackage
- *
* Begin
* PersonalMessage\DraftPM
*/
@@ -3430,9 +3034,6 @@ function showInProfile(int $memID = -1): void
}
/**
- * End
- * PersonalMessage\DraftPM
- *
* Begin
* PersonalMessage\PM
*/
@@ -3498,9 +3099,6 @@ function isAccessiblePM(int $pmID, string $folders = 'both'): bool
}
/**
- * End
- * PersonalMessage\PM
- *
* Begin
* PersonalMessage\Rule
*/
@@ -3525,9 +3123,6 @@ function manage(): void
}
/**
- * End
- * PersonalMessage\Rule
- *
* Begin
* Search\SearchApi
*/
@@ -3542,9 +3137,6 @@ function loadSearchAPIs(): array
}
/**
- * End
- * Search\SearchApi
- *
* Begin
* Search\SearchResult
*/
@@ -3554,9 +3146,6 @@ function highlight(string $text, array $words): string
}
/**
- * End
- * Search\SearchResult
- *
* Begin
* Unicode\Utf8String
* @see SMF\BackwardCompatibility
@@ -3627,9 +3216,6 @@ function utf8_sanitize_invisibles(string $string, int $level, string $substitute
}
/**
- * End
- * Unicode\Utf8String
- *
* Begin
* WebFetch\WebFetchApi
*/
@@ -3639,9 +3225,6 @@ function fetch_web_data(string $url, string|array $post_data = [], bool $keep_al
}
/**
- * End
- * WebFetch\WebFetchApi
- *
* Begin
* SMF\Alert
*/
@@ -3681,9 +3264,6 @@ function alert_purge(int $memID = 0, int $before = 0): void
}
/**
- * End
- * SMF\Alert
- *
* Begin
* SMF\Attachment
*/
@@ -3788,50 +3368,61 @@ function getAttachmentFilename(
}
/**
- * End
- * SMF\Attachment
- *
* Begin
- * SMF\BBCodeParser
+ * SMF\Parsers\BBCodeParser
*/
function get_signature_allowed_bbc_tags(): array
{
- return SMF\BBCodeParser::getSigTags();
+ return SMF\Parser::getSigTags();
}
function highlight_php_code(string $code): string
{
- return SMF\BBCodeParser::highlightPhpCode($code);
+ return SMF\Parser::highlightPhpCode($code);
}
function sanitizeMSCutPaste(string $string): string
{
- return SMF\BBCodeParser::sanitizeMSCutPaste($string);
+ return SMF\Parser::sanitizeMSCutPaste($string);
}
function parse_bbc(
string|bool $message,
- bool $smileys = true,
+ bool|string $smileys = true,
string $cache_id = '',
array $parse_tags = [],
): string|array {
- return SMF\BBCodeParser::backcompatParseBbc(
- $message,
- $smileys,
- $cache_id,
- $parse_tags,
+ if ($message === false) {
+ return SMF\Parser::getBBCodes();
+ }
+
+ return SMF\Parser::transform(
+ string: $message,
+ input_types: SMF\Parser::INPUT_BBC | SMF\Parser::INPUT_MARKDOWN | (!empty($smileys) ? SMF\Parser::INPUT_SMILEYS : 0),
+ options: [
+ 'cache_id' => $cache_id,
+ 'parse_tags' => $parse_tags,
+ 'for_print' => $smileys === 'print',
+ ],
);
}
function parseSmileys(string &$message): void
{
- SMF\BBCodeParser::backcompatParseSmileys($message);
+ $message = SMF\Parser::transform($message, SMF\Parser::INPUT_SMILEYS);
+ }
+
+ function html_to_bbc(string $string): string
+ {
+ // We want to ignore Markdown in this backward compatibility function.
+ return SMF\Parser::transform(
+ string: $string,
+ input_types: SMF\Parser::INPUT_BBC | SMF\Parser::INPUT_SMILEYS,
+ output_type: SMF\Parser::OUTPUT_BBC,
+ );
}
/**
- * End
- * SMF\BBCodeParser
- *
* Begin
* SMF\Board
*/
@@ -3906,9 +3497,6 @@ function getBoardParents(int $id_parent): array
}
/**
- * End
- * SMF\Board
- *
* Begin
* SMF\BrowserDetector
*/
@@ -3923,9 +3511,6 @@ function isBrowser(string $browser): bool
}
/**
- * End
- * SMF\BrowserDetector
- *
* Begin
* SMF\Category
*/
@@ -3965,9 +3550,6 @@ function recursiveBoards(&$list, &$tree): void
}
/**
- * End
- * SMF\Category
- *
* Begin
* SMF\Cookie
*/
@@ -4014,9 +3596,6 @@ function smf_setcookie(
}
/**
- * End
- * SMF\Cookie
- *
* Begin
* SMF\Draft
*/
@@ -4036,9 +3615,6 @@ function showProfileDrafts(int $memID): void
}
/**
- * End
- * SMF\Draft
- *
* Begin
* SMF\Editor
*/
@@ -4053,9 +3629,6 @@ function getMessageIcons(int $board_id): array
}
/**
- * End
- * SMF\Editor
- *
* Begin
* SMF\ErrorHandler
*/
@@ -4104,9 +3677,6 @@ function display_loadavg_error(): void
}
/**
- * End
- * SMF\ErrorHandler
- *
* Begin
* SMF\Event
*/
@@ -4126,9 +3696,6 @@ function removeEvent(int $id): void
}
/**
- * End
- * SMF\Event
- *
* Begin
* SMF\Group
*/
@@ -4170,9 +3737,6 @@ function cache_getMembergroupList(): array
}
/**
- * End
- * SMF\Group
- *
* Begin
* SMF\IntegrationHook
*/
@@ -4214,9 +3778,6 @@ function remove_integration_function(
}
/**
- * End
- * SMF\IntegrationHook
- *
* Begin
* SMF\IP
*/
@@ -4267,9 +3828,6 @@ function expandIPv6(string $ip, bool $return_bool_if_invalid = true): string|boo
}
/**
- * End
- * SMF\IP
- *
* Begin
* SMF\ItemList
*/
@@ -4279,9 +3837,6 @@ function createList(array $options): SMF\ItemList
}
/**
- * End
- * SMF\ItemList
- *
* Begin
* SMF\Lang
*/
@@ -4320,9 +3875,6 @@ function comma_format(int|float $number, ?int $decimals = null): string
}
/**
- * End
- * SMF\Lang
- *
* Begin
* SMF\Logging
*/
@@ -4367,9 +3919,6 @@ function displayDebug(): void
}
/**
- * End
- * SMF\Logging
- *
* Begin
* SMF\Mail
*/
@@ -4470,9 +4019,6 @@ function loadEmailTemplate(
}
/**
- * End
- * SMF\Mail
- *
* Begin
* SMF\Menu
*/
@@ -4487,9 +4033,6 @@ function destroyMenu(int|string $id = 'last'): void
}
/**
- * End
- * SMF\Menu
- *
* Begin
* SMF\Msg
*/
@@ -4557,9 +4100,6 @@ function removeMessage(int $message, bool $decreasePostCount = true): bool
}
/**
- * End
- * SMF\Msg
- *
* Begin
* SMF\PageIndex
*/
@@ -4582,9 +4122,6 @@ function constructPageIndex(
}
/**
- * End
- * SMF\PageIndex
- *
* Begin
* SMF\Poll
*/
@@ -4619,9 +4156,6 @@ function RemovePoll(): void
}
/**
- * End
- * SMF\Poll
- *
* Begin
* SMF\Profile
*/
@@ -4710,9 +4244,6 @@ function makeThemeChanges(int $id, int $id_theme): void
}
/**
- * End
- * SMF\Profile
- *
* Begin
* SMF\QueryString
*/
@@ -4737,9 +4268,6 @@ function matchIPtoCIDR(string $ip_address, string $cidr_address): bool
}
/**
- * End
- * SMF\QueryString
- *
* Begin
* SMF\Sapi
*/
@@ -4752,9 +4280,6 @@ function memoryReturnBytes(string $val): int
return Sapi::memoryReturnBytes($val);
}
/**
- * End
- * SMF\Sapi
- *
* Begin
* SMF\Security
*/
@@ -4809,9 +4334,6 @@ function KickGuest(): void
}
/**
- * End
- * SMF\Security
- *
* Begin
* SMF\SecurityToken
*/
@@ -4831,9 +4353,6 @@ function cleanTokens(bool $complete = false): void
}
/**
- * End
- * SMF\SecurityToken
- *
* BEgin
* SMF\ServerSideIncludes
*/
@@ -5093,9 +4612,6 @@ function ssi_recentAttachments(int $num_attachments = 10, array $attachment_ext
}
/**
- * End
- * SMF\ServerSideIncludes
- *
* Begin
* SMF\Session
*/
@@ -5105,9 +4621,6 @@ function loadSession(): void
}
/**
- * End
- * SMF\Session
- *
* Begin
* SMF\TaskRunner
*/
@@ -5117,9 +4630,6 @@ function CalculateNextTrigger(string|array $tasks = [], bool $force_update = fal
}
/**
- * End
- * SMF\TaskRunner
- *
* Begin
* SMF\Theme
*/
@@ -5229,9 +4739,6 @@ function PickTheme(): void
}
/**
- * End
- * SMF\Theme
- *
* Begin
* SMF\Time
*/
@@ -5267,9 +4774,6 @@ function forum_time(bool $use_user_offset = true, ?int $timestamp = null): int
}
/**
- * End
- * SMF\Time
- *
* Begin
* SMF\TimeZone
*/
@@ -5299,9 +4803,6 @@ function validate_iso_country_codes(array|string $country_codes, bool $as_csv =
}
/**
- * End
- * SMF\TimeZone
- *
* Begin
* SMF\Topic
*/
@@ -5340,9 +4841,6 @@ function prepareLikesContext(int $topic): array
}
/**
- * End
- * SMF\Topic
- *
* Begin
* SMF\Url
*/
@@ -5412,9 +4910,6 @@ function httpsRedirectActive(string $url): bool
}
/**
- * End
- * SMF\Url
- *
* Begin
* SMF\User
*/
@@ -5574,9 +5069,6 @@ function boardsAllowedTo(string|array $permission, bool $check_access = true, bo
}
/**
- * End
- * SMF\User
- *
* Begin
* SMF\Utils
*/
@@ -5771,9 +5263,6 @@ function entity_fix__callback(array $matches): string
}
/**
- * End
- * SMF\Utils
- *
* Begin
* SMF\Verifier
*/
@@ -5781,11 +5270,6 @@ function create_control_verification(array &$options, bool $do_test = false): bo
{
return SMF\Verifier::create($options, $do_test);
}
-
- /*
- * End
- * BackwardCompatibility function map
- */
}
/***************************
diff --git a/Sources/Tasks/CreatePost_Notify.php b/Sources/Tasks/CreatePost_Notify.php
index 1704628406..81cbbec92e 100644
--- a/Sources/Tasks/CreatePost_Notify.php
+++ b/Sources/Tasks/CreatePost_Notify.php
@@ -17,14 +17,13 @@
use SMF\Actions\Notify;
use SMF\Alert;
-use SMF\BBCodeParser;
use SMF\Config;
use SMF\Db\DatabaseApi as Db;
use SMF\ErrorHandler;
use SMF\Lang;
use SMF\Mail;
-use SMF\MarkdownParser;
use SMF\Mentions;
+use SMF\Parser;
use SMF\TaskRunner;
use SMF\Theme;
use SMF\User;
@@ -558,10 +557,11 @@ protected function handleWatchedNotifications(): void
$localization = implode('|', [$member_data['lngfile'], $member_data['time_offset'], $member_data['time_format']]);
if (empty($parsed_message[$localization])) {
- $bbcparser = new BBCodeParser();
- $bbcparser->time_offset = $member_data['time_offset'];
- $bbcparser->time_format = $member_data['time_format'];
- $bbcparser->smiley_set = $member_data['smiley_set'];
+ // Use the target member's localization settings.
+ Parser::$time_offset = $member_data['time_offset'];
+ Parser::$time_format = $member_data['time_format'];
+ Parser::$smiley_set = $member_data['smiley_set'];
+ Parser::$locale = Lang::$txt['lang_locale'];
$parsed_message[$localization]['subject'] = $msgOptions['subject'];
$parsed_message[$localization]['body'] = $msgOptions['body'];
@@ -569,13 +569,37 @@ protected function handleWatchedNotifications(): void
Lang::censorText($parsed_message[$localization]['subject']);
Lang::censorText($parsed_message[$localization]['body']);
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $parsed_message[$localization]['subject'] = MarkdownParser::load(MarkdownParser::OUTPUT_BBC)->parse($parsed_message[$localization]['subject'], false);
- $parsed_message[$localization]['body'] = MarkdownParser::load(MarkdownParser::OUTPUT_BBC)->parse($parsed_message[$localization]['body'], false);
+ $parsed_message[$localization]['subject'] = Utils::htmlspecialcharsDecode($parsed_message[$localization]['subject']);
+
+ $parsed_message[$localization]['body'] = strtr(
+ Parser::transform(
+ $parsed_message[$localization]['body'],
+ Parser::INPUT_BBC | Parser::INPUT_MARKDOWN,
+ ),
+ [
+ '
' => "\n",
+ '' => "\n",
+ '' => "\n",
+ '[' => '[',
+ ']' => ']',
+ ''' => '\'',
+ '' => "\n",
+ '' => "\t",
+ '
' => "\n" . str_repeat('-', 63) . "\n",
+ ],
+ );
+
+ $parsed_message[$localization]['body'] = trim(Utils::htmlspecialcharsDecode(strip_tags($parsed_message[$localization]['body'])));
+
+ // Go back to the default localization settings.
+ if (!isset(User::$me)) {
+ User::setMe(0);
}
- $parsed_message[$localization]['subject'] = Utils::htmlspecialcharsDecode($parsed_message[$localization]['subject']);
- $parsed_message[$localization]['body'] = trim(Utils::htmlspecialcharsDecode(strip_tags(strtr($bbcparser->parse($parsed_message[$localization]['body'], false), ['
' => "\n", '' => "\n", '' => "\n", '[' => '[', ']' => ']', ''' => '\'', '' => "\n", '' => "\t", '
' => "\n---------------------------------------------------------------\n"]))));
+ Parser::$time_offset = User::$me->time_offset;
+ Parser::$time_format = User::$me->$time_format;
+ Parser::$smiley_set = (!empty(User::$me->smiley_set) ? User::$me->smiley_set : (!empty(Config::$modSettings['smiley_sets_default']) ? Config::$modSettings['smiley_sets_default'] : 'none'));
+ Parser::$locale = Lang::getLocaleFromLanguageName(User::$me->$language);
}
// Bitwise check: Receiving an alert?
diff --git a/Sources/Tasks/ExportProfileData.php b/Sources/Tasks/ExportProfileData.php
index fa289f6bbc..70d1757feb 100644
--- a/Sources/Tasks/ExportProfileData.php
+++ b/Sources/Tasks/ExportProfileData.php
@@ -912,6 +912,7 @@ public function execute(): bool
// Use some temporary integration hooks to manipulate BBC parsing during export.
$hook_methods = [
+ 'parser_cache' => 'parser_cache',
'pre_parsebbc' => in_array($this->_details['format'], ['HTML', 'XML_XSLT']) ? 'pre_parsebbc_html' : 'pre_parsebbc_xml',
'post_parsebbc' => 'post_parsebbc',
'bbc_codes' => 'bbc_codes',
@@ -1877,16 +1878,23 @@ public static function add_dtd(
]);
}
+ /**
+ * Adds data to the cache key to distinguish parsing for exports from normal
+ * parsing.
+ */
+ public static function parser_cache(array &$cache_key_extras): void
+ {
+ $cache_key_extras[__CLASS__] = 1;
+ }
+
/**
* Adjusts some parse_bbc() parameters for the special case of HTML and
* XML_XSLT exports.
*/
- public static function pre_parsebbc_html(string &$message, bool &$smileys, string &$cache_id, array &$parse_tags, array &$cache_key_extras): void
+ public static function pre_parsebbc_html(string &$message, bool &$smileys, string &$cache_id, array &$parse_tags): void
{
$cache_id = '';
- $cache_key_extras[__CLASS__] = 1;
-
foreach (['smileys_url', 'attachmentThumbnails'] as $var) {
if (isset(Config::$modSettings[$var])) {
self::$real_modSettings[$var] = Config::$modSettings[$var];
@@ -1900,12 +1908,10 @@ public static function pre_parsebbc_html(string &$message, bool &$smileys, strin
/**
* Adjusts some parse_bbc() parameters for the special case of XML exports.
*/
- public static function pre_parsebbc_xml(string &$message, bool &$smileys, string &$cache_id, array &$parse_tags, array &$cache_key_extras): void
+ public static function pre_parsebbc_xml(string &$message, bool &$smileys, string &$cache_id, array &$parse_tags): void
{
$cache_id = '';
- $cache_key_extras[__CLASS__] = 1;
-
$smileys = false;
if (!isset(Config::$modSettings['disabledBBC'])) {
diff --git a/Sources/Theme.php b/Sources/Theme.php
index a89bdbfd44..5e5db5389f 100644
--- a/Sources/Theme.php
+++ b/Sources/Theme.php
@@ -774,7 +774,12 @@ public static function setupContext(bool $forceload = false): void
}
// Clean it up for presentation ;).
- Utils::$context['news_lines'][$i] = Utils::adjustHeadingLevels(BBCodeParser::load()->parse(stripslashes(trim(Utils::$context['news_lines'][$i])), true, 'news' . $i), null);
+ Utils::$context['news_lines'][$i] = Parser::transform(
+ string: stripslashes(trim(Utils::$context['news_lines'][$i])),
+ options: ['cache_id' => 'news' . $i],
+ );
+
+ Utils::$context['news_lines'][$i] = Utils::adjustHeadingLevels(Utils::$context['news_lines'][$i], null);
}
if (!empty(Utils::$context['news_lines']) && (!empty(Config::$modSettings['allow_guestAccess']) || User::$me->is_logged)) {
@@ -3005,7 +3010,7 @@ protected static function templateInclude(string $filename, bool $once = false):
// I know, I know... this is VERY COMPLICATED. Still, it's good.
if (preg_match('~ (\d+)
$~i', $error, $match) != 0) {
$data = file($filename);
- $data2 = BBCodeParser::highlightPhpCode(implode('', $data));
+ $data2 = Parser::highlightPhpCode(implode('', $data));
$data2 = preg_split('~\\
~', $data2);
// Fix the PHP code stuff...
diff --git a/Sources/User.php b/Sources/User.php
index 5d7c386044..3695e28e89 100644
--- a/Sources/User.php
+++ b/Sources/User.php
@@ -1218,11 +1218,13 @@ public function format(bool $display_custom_fields = false): array
Lang::censorText($this->formatted['blurb']);
Lang::censorText($this->formatted['signature']);
- $this->formatted['signature'] = BBCodeParser::load()->parse(str_replace(["\n", "\r"], ['
', ''], $this->formatted['signature']), true, 'sig' . $this->id, BBCodeParser::getSigTags());
-
- if (!empty(Config::$modSettings['enableMarkdown'])) {
- $this->formatted['signature'] = MarkdownParser::load()->parse($this->formatted['signature'], true);
- }
+ $this->formatted['signature'] = Parser::transform(
+ string: str_replace(["\n", "\r"], ['
', ''], $this->formatted['signature']),
+ options: [
+ 'cache_id' => 'sig' . $this->id,
+ 'parse_tags' => Parser::getSigTags(),
+ ],
+ );
$this->formatted['signature'] = Utils::adjustHeadingLevels($this->formatted['signature'], null);
}
@@ -1258,7 +1260,7 @@ public function format(bool $display_custom_fields = false): array
// BBC?
if ($custom['bbc']) {
- $value = Utils::adjustHeadingLevels(BBCodeParser::load()->parse($value), null);
+ $value = Utils::adjustHeadingLevels(Parser::transform($value), null);
}
// ... or checkbox?
elseif (isset($custom['type']) && $custom['type'] == 'check') {
@@ -3017,7 +3019,7 @@ public static function updateMemberData(int|array|null $members, array $data): v
foreach ($data as $var => $val) {
switch ($var) {
- case 'birthdate':
+ case 'birthdate':
$type = 'date';
break;
diff --git a/Sources/Verifier.php b/Sources/Verifier.php
index 7ca26947c1..87c2c65c8a 100644
--- a/Sources/Verifier.php
+++ b/Sources/Verifier.php
@@ -626,7 +626,7 @@ protected function setQuestions(): void
$this->questions[] = [
'id' => $q,
- 'q' => Utils::adjustHeadingLevels(BBCodeParser::load()->parse($row['question']), null),
+ 'q' => Utils::adjustHeadingLevels(Parser::transform($row['question']), null),
'is_error' => !empty($incorrectQuestions) && in_array($q, $incorrectQuestions),
// Remember a previous submission?
'a' => isset($_REQUEST[$this->id . '_vv'], $_REQUEST[$this->id . '_vv']['q'], $_REQUEST[$this->id . '_vv']['q'][$q]) ? Utils::htmlspecialchars($_REQUEST[$this->id . '_vv']['q'][$q]) : '',
diff --git a/other/upgrade_2-1_MySQL.sql b/other/upgrade_2-1_MySQL.sql
index da91c8dd63..f7779a37a2 100644
--- a/other/upgrade_2-1_MySQL.sql
+++ b/other/upgrade_2-1_MySQL.sql
@@ -201,8 +201,8 @@ if (version_compare(trim(strtolower(@Config::$modSettings['smfVersion'])), '2.1.
while ($row = Db::$db->fetch_assoc($request))
{
$inserts[] = array(
- 'name' => Utils::htmlspecialchars(strip_tags(SMF\BBCodeParser::load()->unparse($row['name']))),
- 'description' => Utils::htmlspecialchars(strip_tags(SMF\BBCodeParser::load()->unparse($row['description']))),
+ 'name' => Utils::htmlspecialchars(strip_tags(SMF\Parser::transform($row['name'], SMF\Parser::OUTPUT_BBC))),
+ 'description' => Utils::htmlspecialchars(strip_tags(SMF\Parser::transform($row['description'], SMF\Parser::OUTPUT_BBC))),
'id' => $row['id'],
);
}
diff --git a/other/upgrade_2-1_PostgreSQL.sql b/other/upgrade_2-1_PostgreSQL.sql
index 96e2fedced..0343dcdc2b 100644
--- a/other/upgrade_2-1_PostgreSQL.sql
+++ b/other/upgrade_2-1_PostgreSQL.sql
@@ -392,8 +392,8 @@ if (version_compare(trim(strtolower(@Config::$modSettings['smfVersion'])), '2.1.
while ($row = Db::$db->fetch_assoc($request))
{
$inserts[] = array(
- 'name' => Utils::htmlspecialchars(strip_tags(SMF\BBCodeParser::load()->unparse($row['name']))),
- 'description' => Utils::htmlspecialchars(strip_tags(SMF\BBCodeParser::load()->unparse($row['description']))),
+ 'name' => Utils::htmlspecialchars(strip_tags(SMF\Parser::transform($row['name'], SMF\Parser::OUTPUT_BBC)),
+ 'description' => Utils::htmlspecialchars(strip_tags(SMF\Parser::transform($row['description'], SMF\Parser::OUTPUT_BBC)),
'id' => $row['id'],
);
}