X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FContent%2FText%2FBBCode.php;h=e95ed0675983e48f238c6930f99c9f5db5faf1a3;hb=7e618856ab09ac74a3760e238c73ecb9515f6701;hp=8a3eb3d570f540fbc25666a8ab7f6c4789b456b7;hpb=c4ec80e839cae1105191fb2c1d394590f9938c3f;p=friendica.git
diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php
index 8a3eb3d570..e95ed06759 100644
--- a/src/Content/Text/BBCode.php
+++ b/src/Content/Text/BBCode.php
@@ -1,6 +1,6 @@
';
const BOTTOM_ANCHOR = '
';
+
+ const PREVIEW_NONE = 0;
+ const PREVIEW_NO_IMAGE = 1;
+ const PREVIEW_LARGE = 2;
+ const PREVIEW_SMALL = 3;
+
/**
* Fetches attachment data that were generated the old way
*
@@ -81,7 +88,7 @@ class BBCode
* 'description' -> Description of the attachment
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- private static function getOldAttachmentData($body)
+ private static function getOldAttachmentData(string $body): array
{
$post = [];
@@ -152,7 +159,7 @@ class BBCode
* 'description' -> Description of the attachment
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function getAttachmentData($body)
+ public static function getAttachmentData(string $body): array
{
DI::profiler()->startRecording('rendering');
$data = [
@@ -187,26 +194,31 @@ class BBCode
case 'publisher_name':
$data['provider_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
+
case 'publisher_url':
$data['provider_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
+
case 'author_name':
$data['author_name'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
if ($data['provider_name'] == $data['author_name']) {
$data['author_name'] = '';
}
break;
+
case 'author_url':
$data['author_url'] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
if ($data['provider_url'] == $data['author_url']) {
$data['author_url'] = '';
}
break;
+
case 'title':
$value = self::convert(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), false, true);
$value = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
$value = str_replace(['[', ']'], ['[', ']'], $value);
$data['title'] = $value;
+
default:
$data[$field] = html_entity_decode($value, ENT_QUOTES, 'UTF-8');
break;
@@ -241,7 +253,7 @@ class BBCode
return $data;
}
- public static function getAttachedData($body, $item = [])
+ public static function getAttachedData(string $body, array $item = []): array
{
/*
- text:
@@ -261,8 +273,8 @@ class BBCode
// Get all linked images with alternative image description
if (preg_match_all("/\[img=(http[^\[\]]*)\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) {
- if (Photo::isLocal($picture[1])) {
- $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2]];
+ if ($id = Photo::getIdForName($picture[1])) {
+ $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => $picture[2], 'id' => $id];
} else {
$post['remote_images'][] = ['url' => $picture[1], 'description' => $picture[2]];
}
@@ -274,22 +286,25 @@ class BBCode
if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) {
foreach ($pictures as $picture) {
- if (Photo::isLocal($picture[1])) {
- $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => ''];
+ if ($id = Photo::getIdForName($picture[1])) {
+ $post['images'][] = ['url' => str_replace('-1.', '-0.', $picture[1]), 'description' => '', 'id' => $id];
} else {
$post['remote_images'][] = ['url' => $picture[1], 'description' => ''];
}
}
}
- // if nothing is found, it maybe having an image.
if (!isset($post['type'])) {
- // Simplify image codes
- $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body);
- $body = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $body);
$post['text'] = $body;
+ }
+
+ // Simplify image codes
+ $post['text'] = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $post['text']);
+ $post['text'] = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", '[img]$1[/img]', $post['text']);
- if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) {
+ // if nothing is found, it maybe having an image.
+ if (!isset($post['type'])) {
+ if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) {
if ((count($pictures) == 1) && !$has_title) {
if (!empty($item['object-type']) && ($item['object-type'] == Activity\ObjectType::IMAGE)) {
// Replace the preview picture with the real picture
@@ -303,7 +318,7 @@ class BBCode
// Workaround:
// Sometimes photo posts to the own album are not detected at the start.
// So we seem to cannot use the cache for these cases. That's strange.
- if (($data['type'] != 'photo') && strstr($pictures[0][1], "/photos/")) {
+ if (($data['type'] != 'photo') && strstr($pictures[0][1], '/photos/')) {
$data = ParseUrl::getSiteinfo($pictures[0][1]);
}
@@ -317,14 +332,14 @@ class BBCode
}
$post['preview'] = $pictures[0][2];
- $post['text'] = trim(str_replace($pictures[0][0], '', $body));
+ $post['text'] = trim(str_replace($pictures[0][0], '', $post['text']));
} else {
$imgdata = Images::getInfoFromURLCached($pictures[0][1]);
- if ($imgdata && substr($imgdata['mime'], 0, 6) == 'image/') {
+ if (($imgdata) && substr($imgdata['mime'], 0, 6) == 'image/') {
$post['type'] = 'photo';
$post['image'] = $pictures[0][1];
$post['preview'] = $pictures[0][2];
- $post['text'] = trim(str_replace($pictures[0][0], '', $body));
+ $post['text'] = trim(str_replace($pictures[0][0], '', $post['text']));
}
}
} elseif (count($pictures) > 0) {
@@ -336,13 +351,12 @@ class BBCode
}
$post['image'] = $pictures[0][2];
- $post['text'] = $body;
foreach ($pictures as $picture) {
$post['text'] = trim(str_replace($picture[0], '', $post['text']));
}
}
- } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $body, $pictures, PREG_SET_ORDER)) {
+ } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $post['text'], $pictures, PREG_SET_ORDER)) {
if ($has_title) {
$post['type'] = 'link';
$post['url'] = $plink;
@@ -351,7 +365,6 @@ class BBCode
}
$post['image'] = $pictures[0][1];
- $post['text'] = $body;
foreach ($pictures as $picture) {
$post['text'] = trim(str_replace($picture[0], '', $post['text']));
}
@@ -390,8 +403,7 @@ class BBCode
}
if (!isset($post['type'])) {
- $post['type'] = "text";
- $post['text'] = trim($body);
+ $post['type'] = 'text';
}
if (($post['type'] == 'photo') && empty($post['images']) && !empty($post['remote_images'])) {
@@ -408,6 +420,10 @@ class BBCode
if (isset($data['images'][0])) {
$post['image'] = $data['images'][0]['src'];
}
+ } elseif (preg_match_all("#\[url=([^\]]+?)\]\s*\[img\]([^\[]+?)\[/img\]\s*\[/url\]#ism", $post['text'], $pictures, PREG_SET_ORDER)) {
+ foreach ($pictures as $picture) {
+ $post['text'] = trim(str_replace($picture[0], '', $post['text']));
+ }
}
DI::profiler()->stopRecording();
@@ -419,10 +435,9 @@ class BBCode
*
* @param string $body
* @param boolean $no_link_desc No link description
- *
* @return string with replaced body
*/
- public static function removeAttachment($body, $no_link_desc = false)
+ public static function removeAttachment(string $body, bool $no_link_desc = false): string
{
return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism",
function ($match) use ($body, $no_link_desc) {
@@ -442,12 +457,11 @@ class BBCode
/**
* Converts a BBCode text into plaintext
*
- * @param $text
+ * @param string $text
* @param bool $keep_urls Whether to keep URLs in the resulting plaintext
- *
* @return string
*/
- public static function toPlaintext($text, $keep_urls = true)
+ public static function toPlaintext(string $text, bool $keep_urls = true): string
{
DI::profiler()->startRecording('rendering');
// Remove pictures in advance to avoid unneeded proxy calls
@@ -463,10 +477,10 @@ class BBCode
return $naked_text;
}
- private static function proxyUrl($image, $simplehtml = self::INTERNAL, $uriid = 0, $size = '')
+ private static function proxyUrl(string $image, int $simplehtml = self::INTERNAL, int $uriid = 0, string $size = ''): string
{
// Only send proxied pictures to API and for internal display
- if (!in_array($simplehtml, [self::INTERNAL, self::API])) {
+ if (!in_array($simplehtml, [self::INTERNAL, self::MASTODON_API, self::TWITTER_API])) {
return $image;
} elseif ($uriid > 0) {
return Post\Link::getByLink($uriid, $image, $size);
@@ -483,7 +497,7 @@ class BBCode
* @param string $srctext The body with images
* @return string The body with possibly scaled images
*/
- public static function scaleExternalImages(string $srctext)
+ public static function scaleExternalImages(string $srctext): string
{
DI::profiler()->startRecording('rendering');
$s = $srctext;
@@ -495,7 +509,7 @@ class BBCode
$c = preg_match_all('/\[img.*?\](.*?)\[\/img\]/ism', $s, $matches, PREG_SET_ORDER);
if ($c) {
foreach ($matches as $mtch) {
- Logger::info('scale_external_image', ['image' => $mtch[1]]);
+ Logger::debug('scale_external_image', ['image' => $mtch[1]]);
$hostname = str_replace('www.', '', substr(DI::baseUrl(), strpos(DI::baseUrl(), '://') + 3));
if (stristr($mtch[1], $hostname)) {
@@ -523,14 +537,14 @@ class BBCode
$Image->scaleDown(640);
$new_width = $Image->getWidth();
$new_height = $Image->getHeight();
- Logger::info('External images scaled', ['orig_width' => $orig_width, 'new_width' => $new_width, 'orig_height' => $orig_height, 'new_height' => $new_height, 'match' => $mtch[0]]);
+ Logger::debug('External images scaled', ['orig_width' => $orig_width, 'new_width' => $new_width, 'orig_height' => $orig_height, 'new_height' => $new_height, 'match' => $mtch[0]]);
$s = str_replace(
$mtch[0],
'[img=' . $new_width . 'x' . $new_height. ']' . $mtch[1] . '[/img]'
. "\n",
$s
);
- Logger::info('New string', ['image' => $s]);
+ Logger::debug('New string', ['image' => $s]);
}
}
}
@@ -551,7 +565,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function limitBodySize($body)
+ public static function limitBodySize(string $body): string
{
DI::profiler()->startRecording('rendering');
$maxlen = DI::config()->get('config', 'max_import_size', 0);
@@ -580,7 +594,7 @@ class BBCode
if (($textlen + $img_start) > $maxlen) {
if ($textlen < $maxlen) {
- Logger::info('the limit happens before an embedded image');
+ Logger::debug('the limit happens before an embedded image');
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
@@ -594,7 +608,7 @@ class BBCode
if (($textlen + $img_end) > $maxlen) {
if ($textlen < $maxlen) {
- Logger::info('the limit happens before the end of a non-embedded image');
+ Logger::debug('the limit happens before the end of a non-embedded image');
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
$textlen = $maxlen;
}
@@ -617,11 +631,11 @@ class BBCode
if (($textlen + strlen($orig_body)) > $maxlen) {
if ($textlen < $maxlen) {
- Logger::info('the limit happens after the end of the last image');
+ Logger::debug('the limit happens after the end of the last image');
$new_body = $new_body . substr($orig_body, 0, $maxlen - $textlen);
}
} else {
- Logger::info('the text size with embedded images extracted did not violate the limit');
+ Logger::debug('the text size with embedded images extracted did not violate the limit');
$new_body = $new_body . $orig_body;
}
@@ -646,7 +660,7 @@ class BBCode
* @return string
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
- public static function convertAttachment($text, $simplehtml = self::INTERNAL, $tryoembed = true, array $data = [], $uriid = 0)
+ public static function convertAttachment(string $text, int $simplehtml = self::INTERNAL, bool $tryoembed = true, array $data = [], int $uriid = 0, int $preview_mode = self::PREVIEW_LARGE): string
{
DI::profiler()->startRecording('rendering');
$data = $data ?: self::getAttachmentData($text);
@@ -659,10 +673,10 @@ class BBCode
$data['title'] = strip_tags($data['title']);
$data['title'] = str_replace(['http://', 'https://'], '', $data['title']);
} else {
- $data['title'] = null;
+ $data['title'] = '';
}
- if (((strpos($data['text'], "[img=") !== false) || (strpos($data['text'], "[img]") !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) {
+ if (((strpos($data['text'], '[img=') !== false) || (strpos($data['text'], '[img]') !== false) || DI::config()->get('system', 'always_show_preview')) && !empty($data['image'])) {
$data['preview'] = $data['image'];
$data['image'] = '';
}
@@ -681,12 +695,18 @@ class BBCode
$return = sprintf('
' . $content . ''; @@ -1198,7 +1267,7 @@ class BBCode return $text; } - private static function removePictureLinksCallback($match) + private static function removePictureLinksCallback(array $match): string { $cache_key = 'remove:' . $match[1]; $text = DI::cache()->get($cache_key); @@ -1212,9 +1281,9 @@ class BBCode } if (substr($mimetype, 0, 6) == 'image/') { - $text = "[url=" . $match[1] . ']' . $match[1] . "[/url]"; + $text = '[url=' . $match[1] . ']' . $match[1] . '[/url]'; } else { - $text = "[url=" . $match[2] . ']' . $match[2] . "[/url]"; + $text = '[url=' . $match[2] . ']' . $match[2] . '[/url]'; // if its not a picture then look if its a page that contains a picture link $body = DI::httpClient()->fetch($match[1], HttpClientAccept::HTML, 0); @@ -1226,7 +1295,7 @@ class BBCode $doc = new DOMDocument(); @$doc->loadHTML($body); $xpath = new DOMXPath($doc); - $list = $xpath->query("//meta[@name]"); + $list = $xpath->query('//meta[@name]'); foreach ($list as $node) { $attr = []; @@ -1247,16 +1316,28 @@ class BBCode return $text; } - private static function expandLinksCallback($match) + /** + * Callback: Expands links from given $match array + * + * @param array $match Array with link match + * @return string BBCode + */ + private static function expandLinksCallback(array $match): string { if (($match[3] == '') || ($match[2] == $match[3]) || stristr($match[2], $match[3])) { - return ($match[1] . "[url]" . $match[2] . "[/url]"); + return ($match[1] . '[url]' . $match[2] . '[/url]'); } else { - return ($match[1] . $match[3] . " [url]" . $match[2] . "[/url]"); + return ($match[1] . $match[3] . ' [url]' . $match[2] . '[/url]'); } } - private static function cleanPictureLinksCallback($match) + /** + * Callback: Cleans picture links + * + * @param array $match Array with link match + * @return string BBCode + */ + private static function cleanPictureLinksCallback(array $match): string { // When the picture link is the own photo path then we can avoid fetching the link $own_photo_url = preg_quote(Strings::normaliseLink(DI::baseUrl()->get()) . '/photos/'); @@ -1302,7 +1383,7 @@ class BBCode $doc = new DOMDocument(); @$doc->loadHTML($body); $xpath = new DOMXPath($doc); - $list = $xpath->query("//meta[@name]"); + $list = $xpath->query('//meta[@name]'); foreach ($list as $node) { $attr = []; if ($node->attributes->length) { @@ -1325,16 +1406,28 @@ class BBCode return $text; } - public static function cleanPictureLinks($text) + /** + * Cleans picture links + * + * @param string $text HTML/BBCode string + * @return string Cleaned HTML/BBCode + */ + public static function cleanPictureLinks(string $text): string { DI::profiler()->startRecording('rendering'); - $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $text); - $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", 'self::cleanPictureLinksCallback', $return); + $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img=(.*)\](.*)\[\/img\]\[\/url\]&Usi", [self::class, 'cleanPictureLinksCallback'], $text); + $return = preg_replace_callback("&\[url=([^\[\]]*)\]\[img\](.*)\[\/img\]\[\/url\]&Usi", [self::class, 'cleanPictureLinksCallback'], $return); DI::profiler()->stopRecording(); return $return; } - public static function removeLinks(string $bbcode) + /** + * Removes links + * + * @param string $text HTML/BBCode string + * @return string Cleaned HTML/BBCode + */ + public static function removeLinks(string $bbcode): string { DI::profiler()->startRecording('rendering'); $bbcode = preg_replace("/\[img\=(.*?)\](.*?)\[\/img\]/ism", ' $1 ', $bbcode); @@ -1350,14 +1443,14 @@ class BBCode /** * Replace names in mentions with nicknames * - * @param string $body + * @param string $body HTML/BBCode * @return string Body with replaced mentions */ - public static function setMentionsToNicknames(string $body):string + public static function setMentionsToNicknames(string $body): string { DI::profiler()->startRecording('rendering'); $regexp = "/([@!])\[url\=([^\[\]]*)\].*?\[\/url\]/ism"; - $body = preg_replace_callback($regexp, ['self', 'mentionCallback'], $body); + $body = preg_replace_callback($regexp, [self::class, 'mentionCallback'], $body); DI::profiler()->stopRecording(); return $body; } @@ -1366,10 +1459,10 @@ class BBCode * Callback function to replace a Friendica style mention in a mention with the nickname * * @param array $match Matching values for the callback - * @return string Replaced mention + * @return string Replaced mention or empty string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function mentionCallback($match) + private static function mentionCallback(array $match): string { if (empty($match[2])) { return ''; @@ -1407,7 +1500,7 @@ class BBCode * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL) + public static function convertForUriId(int $uriid = null, string $text = null, int $simple_html = self::INTERNAL): string { $try_oembed = ($simple_html == self::INTERNAL); @@ -1437,10 +1530,10 @@ class BBCode * @param int $simple_html * @param bool $for_plaintext * @param int $uriid - * @return string + * @return string Converted code or empty string * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public static function convert(string $text = null, $try_oembed = true, $simple_html = self::INTERNAL, $for_plaintext = false, $uriid = 0) + public static function convert(string $text = null, bool $try_oembed = true, int $simple_html = self::INTERNAL, bool $for_plaintext = false, int $uriid = 0): string { // Accounting for null default column values if (is_null($text) || $text === '') { @@ -1462,10 +1555,10 @@ class BBCode * $match[1] = $url * $match[2] = $title or absent */ - $try_oembed_callback = function ($match) + $try_oembed_callback = function (array $match) { $url = $match[1]; - $title = $match[2] ?? null; + $title = $match[2] ?? ''; try { $return = OEmbed::getHTML($url, $title); @@ -1507,8 +1600,8 @@ class BBCode $text = str_replace(">", ">", $text); // remove some newlines before the general conversion - $text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "[share$1]$2[/share]", $text); - $text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism", "[quote$1]$2[/quote]", $text); + $text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1]$2[/share]\n", $text); + $text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism", "\n[quote$1]$2[/quote]\n", $text); // when the content is meant exporting to other systems then remove the avatar picture since this doesn't really look good on these systems if (!$try_oembed) { @@ -1555,7 +1648,7 @@ class BBCode /// @todo Have a closer look at the different html modes // Handle attached links or videos - if (in_array($simple_html, [self::API, self::ACTIVITYPUB])) { + if (in_array($simple_html, [self::MASTODON_API, self::TWITTER_API, self::ACTIVITYPUB])) { $text = self::removeAttachment($text); } elseif (!in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::CONNECTORS])) { $text = self::removeAttachment($text, true); @@ -1788,7 +1881,7 @@ class BBCode $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '