diff --git a/src/Content/Item.php b/src/Content/Item.php index 2e86fb82d6..25d27b26df 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -223,15 +223,13 @@ class Item // select someone by nick in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = ["`nick` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid]; + $condition = ['nick' => $name, 'network' => $network, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } // select someone by attag in the current network if (!DBA::isResult($contact) && ($network != '')) { - $condition = ["`attag` = ? AND `network` = ? AND `uid` = ?", - $name, $network, $profile_uid]; + $condition = ['attag' => $name, 'network' => $network, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } @@ -243,13 +241,13 @@ class Item // select someone by nick in any network if (!DBA::isResult($contact)) { - $condition = ["`nick` = ? AND `uid` = ?", $name, $profile_uid]; + $condition = ['nick' => $name, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } // select someone by attag in any network if (!DBA::isResult($contact)) { - $condition = ["`attag` = ? AND `uid` = ?", $name, $profile_uid]; + $condition = ['attag' => $name, 'uid' => $profile_uid]; $contact = DBA::selectFirst('contact', $fields, $condition); } @@ -271,7 +269,7 @@ class Item $replaced = true; // create profile link $profile = str_replace(',', '%2c', $profile); - $newtag = $tag_type.'[url=' . $profile . ']' . $newname . '[/url]'; + $newtag = $tag_type . '[url=' . $profile . ']' . $newname . '[/url]'; $body = str_replace($tag_type . $name, $newtag, $body); } } @@ -295,8 +293,10 @@ class Item $xmlhead = ''; if ($this->activity->match($item['verb'], Activity::TAG)) { - $fields = ['author-id', 'author-link', 'author-name', 'author-network', - 'verb', 'object-type', 'resource-id', 'body', 'plink']; + $fields = [ + 'author-id', 'author-link', 'author-name', 'author-network', + 'verb', 'object-type', 'resource-id', 'body', 'plink' + ]; $obj = Post::selectFirst($fields, ['uri' => $item['parent-uri']]); if (!DBA::isResult($obj)) { $this->profiler->stopRecording(); @@ -333,8 +333,8 @@ class Item default: if ($obj['resource-id']) { $post_type = $this->l10n->t('photo'); - $m=[]; preg_match("/\[url=([^]]*)\]/", $obj['body'], $m); - $rr['plink'] = $m[1]; + preg_match("/\[url=([^]]*)\]/", $obj['body'], $matches); + $rr['plink'] = $matches[1]; } else { $post_type = $this->l10n->t('status'); } @@ -433,7 +433,8 @@ class Item } if ((($cid == 0) || ($rel == Contact::FOLLOWER)) && - in_array($item['network'], Protocol::FEDERATED)) { + in_array($item['network'], Protocol::FEDERATED) + ) { $menu[$this->l10n->t('Connect/Follow')] = 'contact/follow?url=' . urlencode($item['author-link']) . '&auto=1'; } } else { @@ -891,7 +892,7 @@ class Item public function moveAttachmentsFromBodyToAttach(array $post): array { - if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$post['body'], $match)) { + if (!preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/', $post['body'], $match)) { return $post; } @@ -903,11 +904,17 @@ class Item if ($post['attach']) { $post['attach'] .= ','; } - $post['attach'] .= Post\Media::getAttachElement($this->baseURL . '/attach/' . $attachment['id'], - $attachment['filesize'], $attachment['filetype'], $attachment['filename'] ?? ''); + $post['attach'] .= Post\Media::getAttachElement( + $this->baseURL . '/attach/' . $attachment['id'], + $attachment['filesize'], + $attachment['filetype'], + $attachment['filename'] ?? '' + ); - $fields = ['allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'], - 'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid']]; + $fields = [ + 'allow_cid' => $post['allow_cid'], 'allow_gid' => $post['allow_gid'], + 'deny_cid' => $post['deny_cid'], 'deny_gid' => $post['deny_gid'] + ]; $condition = ['id' => $attachment_id]; Attach::update($fields, $condition); } @@ -925,8 +932,9 @@ class Item // embedded bookmark or attachment in post? set bookmark flag $data = BBCode::getAttachmentData($post['body']); - if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || isset($data['type'])) - && ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE)) { + if ((preg_match_all("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", $post['body'], $match, PREG_SET_ORDER) || !empty($data['type'])) + && ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE) + ) { $post['post-type'] = ItemModel::PT_PAGE; $post['object-type'] = Activity\ObjectType::BOOKMARK; } @@ -934,16 +942,6 @@ class Item // Setting the object type if not defined before if (empty($post['object-type'])) { $post['object-type'] = ($post['gravity'] == ItemModel::GRAVITY_PARENT) ? Activity\ObjectType::NOTE : Activity\ObjectType::COMMENT; - - $objectdata = BBCode::getAttachedData($post['body']); - - if ($objectdata['type'] == 'link') { - $post['object-type'] = Activity\ObjectType::BOOKMARK; - } elseif ($objectdata['type'] == 'video') { - $post['object-type'] = Activity\ObjectType::VIDEO; - } elseif ($objectdata['type'] == 'photo') { - $post['object-type'] = Activity\ObjectType::IMAGE; - } } return $post; } @@ -1039,8 +1037,14 @@ class Item continue; } - $this->emailer->send(new ItemCCEMail($this->app, $this->l10n, $this->baseURL, - $post, $address, $author['thumb'] ?? '')); + $this->emailer->send(new ItemCCEMail( + $this->app, + $this->l10n, + $this->baseURL, + $post, + $address, + $author['thumb'] ?? '' + )); } } } diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 949f9d9cf0..33f91b43d1 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -74,77 +74,6 @@ class BBCode const PREVIEW_LARGE = 2; const PREVIEW_SMALL = 3; - /** - * Fetches attachment data that were generated the old way - * - * @param string $body Message body - * @return array - * 'type' -> Message type ('link', 'video', 'photo') - * 'text' -> Text before the shared message - * 'after' -> Text after the shared message - * 'image' -> Preview image of the message - * 'url' -> Url to the attached message - * 'title' -> Title of the attachment - * 'description' -> Description of the attachment - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ - private static function getOldAttachmentData(string $body): array - { - $post = []; - - // Simplify image codes - $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); - - if (preg_match_all("(\[class=(.*?)\](.*?)\[\/class\])ism", $body, $attached, PREG_SET_ORDER)) { - foreach ($attached as $data) { - if (!in_array($data[1], ['type-link', 'type-video', 'type-photo'])) { - continue; - } - - $post['type'] = substr($data[1], 5); - - $pos = strpos($body, $data[0]); - if ($pos > 0) { - $post['text'] = trim(substr($body, 0, $pos)); - $post['after'] = trim(substr($body, $pos + strlen($data[0]))); - } else { - $post['text'] = trim(str_replace($data[0], '', $body)); - $post['after'] = ''; - } - - $attacheddata = $data[2]; - - if (preg_match("/\[img\](.*?)\[\/img\]/ism", $attacheddata, $matches)) { - - $picturedata = Images::getInfoFromURLCached($matches[1]); - - if ($picturedata) { - if (($picturedata[0] >= 500) && ($picturedata[0] >= $picturedata[1])) { - $post['image'] = $matches[1]; - } else { - $post['preview'] = $matches[1]; - } - } - } - - if (preg_match("/\[bookmark\=(.*?)\](.*?)\[\/bookmark\]/ism", $attacheddata, $matches)) { - $post['url'] = $matches[1]; - $post['title'] = $matches[2]; - } - if (!empty($post['url']) && (in_array($post['type'], ['link', 'video'])) - && preg_match("/\[url\=(.*?)\](.*?)\[\/url\]/ism", $attacheddata, $matches)) { - $post['url'] = $matches[1]; - } - - // Search for description - if (preg_match("/\[quote\](.*?)\[\/quote\]/ism", $attacheddata, $matches)) { - $post['description'] = $matches[1]; - } - } - } - return $post; - } - /** * Fetches attachment data that were generated with the "attachment" element * @@ -178,7 +107,7 @@ class BBCode if (!preg_match("/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism", $body, $match)) { DI::profiler()->stopRecording(); - return self::getOldAttachmentData($body); + return []; } $attributes = $match[2]; @@ -253,183 +182,6 @@ class BBCode return $data; } - public static function getAttachedData(string $body, array $item = []): array - { - /* - - text: - - type: link, video, photo - - title: - - url: - - image: - - description: - - (thumbnail) - */ - - DI::profiler()->startRecording('rendering'); - $has_title = !empty($item['title']); - $plink = $item['plink'] ?? ''; - $post = self::getAttachmentData($body); - - // 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 ($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]]; - } - } - if (!empty($post['images']) && !empty($post['images'][0]['description'])) { - $post['image_description'] = $post['images'][0]['description']; - } - } - - if (preg_match_all("/\[img\]([^\[\]]*)\[\/img\]/Usi", $body, $pictures, PREG_SET_ORDER)) { - foreach ($pictures as $picture) { - 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 (!isset($post['type'])) { - $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 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 && !Photo::isLocal($pictures[0][2])) { - if (!empty($item['object-type']) && ($item['object-type'] == Activity\ObjectType::IMAGE)) { - // Replace the preview picture with the real picture - $url = str_replace('-1.', '-0.', $pictures[0][2]); - $data = ['url' => $url, 'type' => 'photo']; - } else { - // Checking, if the link goes to a picture - $data = ParseUrl::getSiteinfoCached($pictures[0][1]); - } - - // 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/')) { - $data = ParseUrl::getSiteinfo($pictures[0][1]); - } - - if ($data['type'] == 'photo') { - $post['type'] = 'photo'; - if (isset($data['images'][0])) { - $post['image'] = $data['images'][0]['src']; - $post['url'] = $data['url']; - } else { - $post['image'] = $data['url']; - } - - $post['preview'] = $pictures[0][2]; - $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/') { - $post['type'] = 'photo'; - $post['image'] = $pictures[0][1]; - $post['preview'] = $pictures[0][2]; - $post['text'] = trim(str_replace($pictures[0][0], '', $post['text'])); - } - } - } elseif (count($pictures) > 0) { - if (count($pictures) > 4) { - $post['type'] = 'link'; - $post['url'] = $plink; - } else { - $post['type'] = 'photo'; - } - - $post['image'] = $pictures[0][2]; - - foreach ($pictures as $picture) { - $post['text'] = trim(str_replace($picture[0], '', $post['text'])); - } - } - } elseif (preg_match_all("(\[img\](.*?)\[\/img\])ism", $post['text'], $pictures, PREG_SET_ORDER)) { - if ($has_title) { - $post['type'] = 'link'; - $post['url'] = $plink; - } else { - $post['type'] = 'photo'; - } - - $post['image'] = $pictures[0][1]; - foreach ($pictures as $picture) { - $post['text'] = trim(str_replace($picture[0], '', $post['text'])); - } - } - - // Test for the external links - preg_match_all("(\[url\](.*?)\[\/url\])ism", $post['text'], $links1, PREG_SET_ORDER); - preg_match_all("(\[url\=(.*?)\].*?\[\/url\])ism", $post['text'], $links2, PREG_SET_ORDER); - - $links = array_merge($links1, $links2); - - // If there is only a single one, then use it. - // This should cover link posts via API. - if ((count($links) == 1) && !isset($post['preview']) && !$has_title) { - $post['type'] = 'link'; - $post['url'] = $links[0][1]; - } - - // Simplify "video" element - $post['text'] = preg_replace('(\[video.*?\ssrc\s?=\s?([^\s\]]+).*?\].*?\[/video\])ism', '[video]$1[/video]', $post['text']); - - // Now count the number of external media links - preg_match_all("(\[vimeo\](.*?)\[\/vimeo\])ism", $post['text'], $links1, PREG_SET_ORDER); - preg_match_all("(\[youtube\\](.*?)\[\/youtube\\])ism", $post['text'], $links2, PREG_SET_ORDER); - preg_match_all("(\[video\\](.*?)\[\/video\\])ism", $post['text'], $links3, PREG_SET_ORDER); - preg_match_all("(\[audio\\](.*?)\[\/audio\\])ism", $post['text'], $links4, PREG_SET_ORDER); - - // Add them to the other external links - $links = array_merge($links, $links1, $links2, $links3, $links4); - - // Are there more than one? - if (count($links) > 1) { - // The post will be the type "text", which means a blog post - unset($post['type']); - $post['url'] = $plink; - } - - if (!isset($post['type'])) { - $post['type'] = 'text'; - } - - if (($post['type'] == 'photo') && empty($post['images']) && !empty($post['remote_images'])) { - $post['images'] = $post['remote_images']; - $post['image'] = $post['images'][0]['url']; - if (!empty($post['images']) && !empty($post['images'][0]['description'])) { - $post['image_description'] = $post['images'][0]['description']; - } - } - unset($post['remote_images']); - } elseif (isset($post['url']) && ($post['type'] == 'video')) { - $data = ParseUrl::getSiteinfoCached($post['url']); - - 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(); - return $post; - } - /** * Remove [attachment] BBCode and replaces it with a regular [url] * @@ -439,7 +191,8 @@ class BBCode */ public static function replaceAttachment(string $body, bool $no_link_desc = false): string { - return preg_replace_callback("/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", + return preg_replace_callback( + "/\s*\[attachment (.*?)\](.*?)\[\/attachment\]\s*/ism", function ($match) use ($body, $no_link_desc) { $attach_data = self::getAttachmentData($match[0]); if (empty($attach_data['url'])) { @@ -451,7 +204,9 @@ class BBCode } else { return " \n[url=" . $attach_data['url'] . ']' . $attach_data['title'] . "[/url]\n"; } - }, $body); + }, + $body + ); } /** @@ -956,8 +711,11 @@ class BBCode // We're depending on the property of 'foreach' (specified on the PHP website) that // it loops over the array starting from the first element and going sequentially // to the last element - $newbody = str_replace('[$#saved_image' . $cnt . '#$]', - '' . DI::l10n()->t('Image/photo') . '', $newbody); + $newbody = str_replace( + '[$#saved_image' . $cnt . '#$]', + '' . DI::l10n()->t('Image/photo') . '', + $newbody + ); $cnt++; } @@ -1112,8 +870,7 @@ class BBCode $attributes[$field] = html_entity_decode($matches[2] ?? '', ENT_QUOTES, 'UTF-8'); } - $img_str = ' $value) { if (!empty($value)) { $img_str .= ' ' . $key . '="' . htmlspecialchars($value, ENT_COMPAT) . '"'; @@ -1150,13 +907,13 @@ class BBCode switch ($simplehtml) { case self::MASTODON_API: case self::TWITTER_API: - $text = ($is_quote_share? '
' : '') . - '' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ":
\n" . - '
' . $content . '
'; + $text = ($is_quote_share ? '
' : '') . + '' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author_contact['addr'] . ":
\n" . + '
' . $content . '
'; break; case self::DIASPORA: if (stripos(Strings::normaliseLink($attributes['link']), 'http://twitter.com/') === 0) { - $text = ($is_quote_share? '
' : '') . '

' . $attributes['link'] . '

' . "\n"; + $text = ($is_quote_share ? '
' : '') . '

' . $attributes['link'] . '

' . "\n"; } else { $headline = '

' . $attributes['author'] . ':

' . "\n"; @@ -1164,7 +921,7 @@ class BBCode $headline = '

' . $attributes['author'] . ' - ' . $attributes['posted'] . ' GMT

' . "\n"; } - $text = ($is_quote_share? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; + $text = ($is_quote_share ? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; if (empty($attributes['posted']) && !empty($attributes['link'])) { $text .= '

[Source]

' . "\n"; @@ -1177,18 +934,18 @@ class BBCode $headline .= DI::l10n()->t('%2$s %3$s', $attributes['link'], $mention, $attributes['posted']); $headline .= ':

' . "\n"; - $text = ($is_quote_share? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; + $text = ($is_quote_share ? '
' : '') . $headline . '
' . trim($content) . '
' . "\n"; break; case self::OSTATUS: - $text = ($is_quote_share? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; + $text = ($is_quote_share ? '
' : '') . '

' . html_entity_decode('♲ ', ENT_QUOTES, 'UTF-8') . ' @' . $author_contact['addr'] . ': ' . $content . '

' . "\n"; break; case self::ACTIVITYPUB: $author = '@' . $author_contact['addr'] . ':'; $text = '
' . html_entity_decode('♲', ENT_QUOTES, 'UTF-8') . ' ' . $author . '
' . $content . '
' . "\n"; break; default: - $text = ($is_quote_share? "\n" : ''); + $text = ($is_quote_share ? "\n" : ''); $contact = Contact::getByURL($attributes['profile'], false, ['network']); $network = $contact['network'] ?? Protocol::PHANTOM; @@ -1500,8 +1257,7 @@ class BBCode * $match[1] = $url * $match[2] = $title or absent */ - $try_oembed_callback = function (array $match) - { + $try_oembed_callback = function (array $match) { $url = $match[1]; $title = $match[2] ?? ''; @@ -1554,18 +1310,22 @@ class BBCode } // Remove linefeeds inside of the table elements. See issue #6799 - $search = ["\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ", + $search = [ + "\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ", "\n[td]", "[td]\n", " [td]", "\n[/td]", "[/td]\n", "[/td] ", "\n[tr]", "[tr]\n", " [tr]", "[tr] ", "\n[/tr]", "[/tr]\n", " [/tr]", "[/tr] ", "\n[hr]", "[hr]\n", " [hr]", "[hr] ", "\n[attachment ", " [attachment ", "\n[/attachment]", "[/attachment]\n", " [/attachment]", "[/attachment] ", - "[table]\n", "[table] ", " [table]", "\n[/table]", " [/table]", "[/table] "]; - $replace = ["[th]", "[th]", "[th]", "[/th]", "[/th]", "[/th]", + "[table]\n", "[table] ", " [table]", "\n[/table]", " [/table]", "[/table] " + ]; + $replace = [ + "[th]", "[th]", "[th]", "[/th]", "[/th]", "[/th]", "[td]", "[td]", "[td]", "[/td]", "[/td]", "[/td]", "[tr]", "[tr]", "[tr]", "[tr]", "[/tr]", "[/tr]", "[/tr]", "[/tr]", "[hr]", "[hr]", "[hr]", "[hr]", "[attachment ", "[attachment ", "[/attachment]", "[/attachment]", "[/attachment]", "[/attachment]", - "[table]", "[table]", "[table]", "[/table]", "[/table]", "[/table]"]; + "[table]", "[table]", "[table]", "[/table]", "[/table]", "[/table]" + ]; do { $oldtext = $text; $text = str_replace($search, $replace, $text); @@ -1581,10 +1341,14 @@ class BBCode // removing multiplicated newlines if (DI::config()->get('system', 'remove_multiplicated_lines')) { - $search = ["\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[*]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", - "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n"]; - $replace = ["\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[*]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", - "[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]"]; + $search = [ + "\n\n\n", "\n ", " \n", "[/quote]\n\n", "\n[/quote]", "[/li]\n", "\n[li]", "\n[*]", "\n[ul]", "[/ul]\n", "\n\n[share ", "[/attachment]\n", + "\n[h1]", "[/h1]\n", "\n[h2]", "[/h2]\n", "\n[h3]", "[/h3]\n", "\n[h4]", "[/h4]\n", "\n[h5]", "[/h5]\n", "\n[h6]", "[/h6]\n" + ]; + $replace = [ + "\n\n", "\n", "\n", "[/quote]\n", "[/quote]", "[/li]", "[li]", "[*]", "[ul]", "[/ul]", "\n[share ", "[/attachment]", + "[h1]", "[/h1]", "[h2]", "[/h2]", "[h3]", "[/h3]", "[h4]", "[/h4]", "[h5]", "[/h5]", "[h6]", "[/h6]" + ]; do { $oldtext = $text; $text = str_replace($search, $replace, $text); @@ -1702,9 +1466,9 @@ class BBCode $endlessloop = 0; while ((((strpos($text, "[/list]") !== false) && (strpos($text, "[list") !== false)) || - ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) || - ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) || - ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) { + ((strpos($text, "[/ol]") !== false) && (strpos($text, "[ol]") !== false)) || + ((strpos($text, "[/ul]") !== false) && (strpos($text, "[ul]") !== false)) || + ((strpos($text, "[/li]") !== false) && (strpos($text, "[li]") !== false))) && (++$endlessloop < 20)) { $text = preg_replace("/\[list\](.*?)\[\/list\]/ism", '', $text); $text = preg_replace("/\[list=\](.*?)\[\/list\]/ism", '', $text); $text = preg_replace("/\[list=1\](.*?)\[\/list\]/ism", '', $text); @@ -1750,10 +1514,12 @@ class BBCode // handle nested quotes $endlessloop = 0; - while ((strpos($text, "[/spoiler]")!== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { - $text = preg_replace("/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", + while ((strpos($text, "[/spoiler]") !== false) && (strpos($text, "[spoiler=") !== false) && (++$endlessloop < 20)) { + $text = preg_replace( + "/\[spoiler=[\"\']*(.*?)[\"\']*\](.*?)\[\/spoiler\]/ism", '
$1$2
', - $text); + $text + ); } // Declare the format for [quote] layout @@ -1772,10 +1538,12 @@ class BBCode // handle nested quotes $endlessloop = 0; - while ((strpos($text, "[/quote]")!== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) { - $text = preg_replace("/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", - "

" . $t_wrote . "

$2
", - $text); + while ((strpos($text, "[/quote]") !== false) && (strpos($text, "[quote=") !== false) && (++$endlessloop < 20)) { + $text = preg_replace( + "/\[quote=[\"\']*(.*?)[\"\']*\](.*?)\[\/quote\]/ism", + "

" . $t_wrote . "

$2
", + $text + ); } @@ -1796,13 +1564,15 @@ class BBCode $text = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '', $text); $text = preg_replace("/\[zmg\=([0-9]*)x([0-9]*)\](.*?)\[\/zmg\]/ism", '', $text); - $text = preg_replace_callback("/\[img\=(.*?)\](.*?)\[\/img\]/ism", + $text = preg_replace_callback( + "/\[img\=(.*?)\](.*?)\[\/img\]/ism", function ($matches) use ($simple_html, $uriid) { $matches[1] = self::proxyUrl($matches[1], $simple_html, $uriid); $matches[2] = htmlspecialchars($matches[2], ENT_COMPAT); return '' . $matches[2] . ''; }, - $text); + $text + ); // Images // [img]pathtoimage[/img] @@ -1824,8 +1594,8 @@ class BBCode $text = self::convertImages($text, $simple_html, $uriid); - $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); - $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); + $text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); + $text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); //$text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '
' . DI::l10n()->t('Encrypted content') . '
', $text); // Simplify "video" element @@ -1833,20 +1603,32 @@ class BBCode if ($try_oembed) { // html5 video and audio - $text = preg_replace("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", - '', $text); + $text = preg_replace( + "/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4).*?)\[\/video\]/ism", + '', + $text + ); $text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", $try_oembed_callback, $text); $text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text); - $text = preg_replace("/\[video\](.*?)\[\/video\]/ism", - '$1', $text); + $text = preg_replace( + "/\[video\](.*?)\[\/video\]/ism", + '$1', + $text + ); $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", '', $text); } else { - $text = preg_replace("/\[video\](.*?)\[\/video\]/ism", - '$1', $text); - $text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", - '$1', $text); + $text = preg_replace( + "/\[video\](.*?)\[\/video\]/ism", + '$1', + $text + ); + $text = preg_replace( + "/\[audio\](.*?)\[\/audio\]/ism", + '$1', + $text + ); } // Backward compatibility, [iframe] support has been removed in version 2020.12 @@ -1868,8 +1650,11 @@ class BBCode if ($try_oembed) { $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '', $text); } else { - $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", - 'https://www.youtube.com/watch?v=$1', $text); + $text = preg_replace( + "/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", + 'https://www.youtube.com/watch?v=$1', + $text + ); } if ($try_oembed) { @@ -1883,8 +1668,11 @@ class BBCode if ($try_oembed) { $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text); } else { - $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", - 'https://vimeo.com/$1', $text); + $text = preg_replace( + "/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", + 'https://vimeo.com/$1', + $text + ); } // oembed tag @@ -1920,27 +1708,39 @@ class BBCode // Handle mentions and hashtag links if ($simple_html == self::DIASPORA) { // The ! is converted to @ since Diaspora only understands the @ - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '@$3', - $text); + $text + ); } elseif (in_array($simple_html, [self::OSTATUS, self::ACTIVITYPUB])) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); - $text = preg_replace("/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text + ); + $text = preg_replace( + "/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', - $text); + $text + ); } elseif (in_array($simple_html, [self::INTERNAL, self::EXTERNAL, self::TWITTER_API])) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); + $text + ); } elseif ($simple_html == self::MASTODON_API) { - $text = preg_replace("/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text = preg_replace( + "/([@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', - $text); - $text = preg_replace("/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", + $text + ); + $text = preg_replace( + "/([#])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', - $text); + $text + ); } else { $text = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '$1$3', $text); } @@ -1958,8 +1758,11 @@ class BBCode // Bookmarks in red - will be converted to bookmarks in friendica $text = preg_replace("/#\^\[url\](.*?)\[\/url\]/ism", '[bookmark=$1]$1[/bookmark]', $text); $text = preg_replace("/#\^\[url\=(.*?)\](.*?)\[\/url\]/ism", '[bookmark=$1]$2[/bookmark]', $text); - $text = preg_replace("/#\[url\=.*?\]\^\[\/url\]\[url\=(.*?)\](.*?)\[\/url\]/i", - "[bookmark=$1]$2[/bookmark]", $text); + $text = preg_replace( + "/#\[url\=.*?\]\^\[\/url\]\[url\=(.*?)\](.*?)\[\/url\]/i", + "[bookmark=$1]$2[/bookmark]", + $text + ); if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) { $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", [self::class, 'expandLinksCallback'], $text); @@ -1979,20 +1782,22 @@ class BBCode "&\[url=/?posts/([^\[\]]*)\](.*)\[\/url\]&Usi", function ($match) { return "[url=" . DI::baseUrl() . "/display/" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text + }, + $text ); $text = preg_replace_callback( "&\[url=/people\?q\=(.*)\](.*)\[\/url\]&Usi", function ($match) { return "[url=" . DI::baseUrl() . "/search?search=%40" . $match[1] . "]" . $match[2] . "[/url]"; - }, $text + }, + $text ); // Server independent link to posts and comments // See issue: https://github.com/diaspora/diaspora_federation/issues/75 $expression = "=diaspora://.*?/post/([0-9A-Za-z\-_@.:]{15,254}[0-9A-Za-z])=ism"; - $text = preg_replace($expression, DI::baseUrl()."/display/$1", $text); + $text = preg_replace($expression, DI::baseUrl() . "/display/$1", $text); /* Tag conversion * Supports: @@ -2000,7 +1805,7 @@ class BBCode * - [url=]#[/url] */ self::performWithEscapedTags($text, ['url', 'share'], function ($text) use ($simple_html) { - $text = preg_replace_callback("/(?:#\[url\=[^\[\]]*\]|\[url\=[^\[\]]*\]#)(.*?)\[\/url\]/ism", function($matches) use ($simple_html) { + $text = preg_replace_callback("/(?:#\[url\=[^\[\]]*\]|\[url\=[^\[\]]*\]#)(.*?)\[\/url\]/ism", function ($matches) use ($simple_html) { if ($simple_html == self::ACTIVITYPUB) { return '#' @@ -2017,8 +1822,8 @@ class BBCode // We need no target="_blank" rel="noopener noreferrer" for local links // convert links start with DI::baseUrl() as local link without the target="_blank" rel="noopener noreferrer" attribute $escapedBaseUrl = preg_quote(DI::baseUrl(), '/'); - $text = preg_replace("/\[url\](".$escapedBaseUrl.".*?)\[\/url\]/ism", '$1', $text); - $text = preg_replace("/\[url\=(".$escapedBaseUrl.".*?)\](.*?)\[\/url\]/ism", '$2', $text); + $text = preg_replace("/\[url\](" . $escapedBaseUrl . ".*?)\[\/url\]/ism", '$1', $text); + $text = preg_replace("/\[url\=(" . $escapedBaseUrl . ".*?)\](.*?)\[\/url\]/ism", '$2', $text); $text = preg_replace("/\[url\](.*?)\[\/url\]/ism", '$1', $text); $text = preg_replace("/\[url\=(.*?)\](.*?)\[\/url\]/ism", '$2', $text); @@ -2049,10 +1854,15 @@ class BBCode // sanitizes src attributes (http and redir URLs for displaying in a web page, cid used for inline images in emails) $allowed_src_protocols = ['//', 'http://', 'https://', 'contact/redir/', 'cid:']; - array_walk($allowed_src_protocols, function(&$value) { $value = preg_quote($value, '#');}); + array_walk($allowed_src_protocols, function (&$value) { + $value = preg_quote($value, '#'); + }); - $text = preg_replace('#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism', - '<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">', $text); + $text = preg_replace( + '#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism', + '<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">', + $text + ); // sanitize href attributes (only allowlisted protocols URLs) // default value for backward compatibility @@ -2064,7 +1874,9 @@ class BBCode $allowed_link_protocols[] = 'https://'; $allowed_link_protocols[] = 'contact/redir/'; - array_walk($allowed_link_protocols, function(&$value) { $value = preg_quote($value, '#');}); + array_walk($allowed_link_protocols, function (&$value) { + $value = preg_quote($value, '#'); + }); $regex = '#<([^>]*?)(href)="(?!' . implode('|', $allowed_link_protocols) . ')(.*?)"(.*?)>#ism'; $text = preg_replace($regex, '<$1$2="javascript:void(0)"$4 data-original-href="$3" class="invalid-href" title="' . DI::l10n()->t('Invalid link protocol') . '">', $text); @@ -2074,7 +1886,8 @@ class BBCode $text, function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) { return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html); - }, $uriid + }, + $uriid ); $text = self::interpolateSavedImagesIntoItemBody($uriid, $text, $saved_image); @@ -2089,13 +1902,14 @@ class BBCode // Additionally, [pre] tags preserve spaces $text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", function ($match) { - return str_replace([' ', "\n"], [' ', "
"], htmlentities($match[1], ENT_NOQUOTES,'UTF-8')); + return str_replace([' ', "\n"], [' ', "
"], htmlentities($match[1], ENT_NOQUOTES, 'UTF-8')); }, $text); return $text; }); // Escaped code - $text = preg_replace_callback("#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism", + $text = preg_replace_callback( + "#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism", function ($matches) { if (strpos($matches[2], "\n") !== false) { $return = '
' . htmlentities(trim($matches[2], "\n\r"), ENT_NOQUOTES, 'UTF-8') . '
'; @@ -2111,8 +1925,8 @@ class BBCode // Default iframe allowed domains/path $allowedIframeDomains = [ DI::baseUrl()->getHost() - . (DI::baseUrl()->getPath() ? '/' . DI::baseUrl()->getPath() : '') - . '/oembed/', # The path part has to change with the source in Content\Oembed::iframe + . (DI::baseUrl()->getPath() ? '/' . DI::baseUrl()->getPath() : '') + . '/oembed/', # The path part has to change with the source in Content\Oembed::iframe 'www.youtube.com/embed/', 'player.vimeo.com/video/', ]; @@ -2225,7 +2039,8 @@ class BBCode * Transform #tags, strip off the [url] and replace spaces with underscore */ $url_search_string = "^\[\]"; - $text = preg_replace_callback("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i", + $text = preg_replace_callback( + "/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/i", function ($matches) { return '#' . str_replace(' ', '_', $matches[2]); }, @@ -2360,7 +2175,8 @@ class BBCode */ public static function expandTags(string $body): string { - return preg_replace_callback("/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/", + return preg_replace_callback( + "/(?<=\W|^)([!#@])([^\^ \x0D\x0A,;:?'\"]*[^\^ \x0D\x0A,;:?!'\".])/", function (array $match) { switch ($match[1]) { case '!': @@ -2377,7 +2193,9 @@ class BBCode default: return $match[1] . '[url=' . DI::baseUrl() . '/search?tag=' . $match[2] . ']' . $match[2] . '[/url]'; } - }, $body); + }, + $body + ); } /** diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index 9a7435f5b6..7e3263d127 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -122,14 +122,17 @@ class Plaintext $body = preg_replace("/([#@])\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", '$1$3', $item['body']); // Add an URL element if the text contains a raw link - $body = preg_replace('/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism', - '$1[url]$2[/url]', $body); + $body = preg_replace( + '/([^\]\=\'"]|^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\_\~\#\%\$\!\+\,]+)/ism', + '$1[url]$2[/url]', + $body + ); // Remove the abstract $body = BBCode::stripAbstract($body); // At first look at data that is attached via "type-..." stuff - $post = BBCode::getAttachedData($body, $item); + $post = BBCode::getAttachmentData($body, $item); if (($item['title'] != '') && ($post['text'] != '')) { $post['text'] = trim($item['title'] . "\n\n" . $post['text']); @@ -149,7 +152,7 @@ class Plaintext if (($limit == 0) && ($abstract == $default_abstract)) { $abstract = ''; } - } else {// Try to guess the correct target network + } else { // Try to guess the correct target network switch ($htmlmode) { case BBCode::TWITTER: $abstract = BBCode::getAbstract($item['body'], Protocol::TWITTER); diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php index dc46a77804..c0bad9beb6 100644 --- a/src/Factory/Api/Mastodon/Card.php +++ b/src/Factory/Api/Mastodon/Card.php @@ -39,45 +39,40 @@ class Card extends BaseFactory */ public function createFromUriId(int $uriId, array $history = []): \Friendica\Object\Api\Mastodon\Card { - $item = Post::selectFirst(['body'], ['uri-id' => $uriId]); - if (!empty($item['body'])) { - $data = BBCode::getAttachmentData($item['body']); - } else { - $data = []; + $media = Post\Media::getByURIId($uriId, [Post\Media::HTML]); + if (empty($media) || (empty($media[0]['description']) && empty($media[0]['image']) && empty($media[0]['preview']))) { + return new \Friendica\Object\Api\Mastodon\Card([], $history); } - foreach (Post\Media::getByURIId($uriId, [Post\Media::HTML]) as $attached) { - if ((empty($data['url']) || Strings::compareLink($data['url'], $attached['url'])) && - (!empty($attached['description']) || !empty($attached['image']) || !empty($attached['preview']))) { - $parts = parse_url($attached['url']); - if (!empty($parts['scheme']) && !empty($parts['host'])) { - if (empty($attached['publisher-name'])) { - $attached['publisher-name'] = $parts['host']; - } - if (empty($attached['publisher-url']) || empty(parse_url($attached['publisher-url'], PHP_URL_SCHEME))) { - $attached['publisher-url'] = $parts['scheme'] . '://' . $parts['host']; + $parts = parse_url($media[0]['url']); + if (!empty($parts['scheme']) && !empty($parts['host'])) { + if (empty($media[0]['publisher-name'])) { + $media[0]['publisher-name'] = $parts['host']; + } + if (empty($media[0]['publisher-url']) || empty(parse_url($media[0]['publisher-url'], PHP_URL_SCHEME))) { + $media[0]['publisher-url'] = $parts['scheme'] . '://' . $parts['host']; - if (!empty($parts['port'])) { - $attached['publisher-url'] .= ':' . $parts['port']; - } - } + if (!empty($parts['port'])) { + $media[0]['publisher-url'] .= ':' . $parts['port']; } - - $data['url'] = $attached['url']; - $data['title'] = $attached['name']; - $data['description'] = $attached['description']; - $data['type'] = 'link'; - $data['author_name'] = $attached['author-name']; - $data['author_url'] = $attached['author-url']; - $data['provider_name'] = $attached['publisher-name']; - $data['provider_url'] = $attached['publisher-url']; - $data['image'] = $attached['preview']; - $data['width'] = $attached['preview-width']; - $data['height'] = $attached['preview-height']; - $data['blurhash'] = $attached['blurhash']; } } + $data = []; + + $data['url'] = $media[0]['url']; + $data['title'] = $media[0]['name']; + $data['description'] = $media[0]['description']; + $data['type'] = 'link'; + $data['author_name'] = $media[0]['author-name']; + $data['author_url'] = $media[0]['author-url']; + $data['provider_name'] = $media[0]['publisher-name']; + $data['provider_url'] = $media[0]['publisher-url']; + $data['image'] = $media[0]['preview']; + $data['width'] = $media[0]['preview-width']; + $data['height'] = $media[0]['preview-height']; + $data['blurhash'] = $media[0]['blurhash']; + return new \Friendica\Object\Api\Mastodon\Card($data, $history); } } diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 5dfb227d64..ab17789724 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -162,8 +162,10 @@ class Media */ public static function getAttachElement(string $href, int $length, string $type, string $title = ''): string { - $media = self::fetchAdditionalData(['type' => self::DOCUMENT, 'url' => $href, - 'size' => $length, 'mimetype' => $type, 'description' => $title]); + $media = self::fetchAdditionalData([ + 'type' => self::DOCUMENT, 'url' => $href, + 'size' => $length, 'mimetype' => $type, 'description' => $title + ]); return '[attach]href="' . $media['url'] . '" length="' . $media['size'] . '" type="' . $media['mimetype'] . '" title="' . $media['description'] . '"[/attach]'; @@ -263,8 +265,10 @@ class Media return $media; } - if (!empty($item['plink']) && Strings::compareLink($item['plink'], $media['url']) && - parse_url($item['plink'], PHP_URL_HOST) != parse_url($item['uri'], PHP_URL_HOST)) { + if ( + !empty($item['plink']) && Strings::compareLink($item['plink'], $media['url']) && + parse_url($item['plink'], PHP_URL_HOST) != parse_url($item['uri'], PHP_URL_HOST) + ) { Logger::debug('Not a link to an activity', ['uri-id' => $media['uri-id'], 'url' => $media['url'], 'plink' => $item['plink'], 'uri' => $item['uri']]); return $media; } @@ -483,8 +487,10 @@ class Media } $body = str_replace($picture[0], '', $body); $image = str_replace('-1.', '-0.', $picture[2]); - $attachments[$image] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, - 'preview' => $picture[2], 'description' => $picture[3]]; + $attachments[$image] = [ + 'uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, + 'preview' => $picture[2], 'description' => $picture[3] + ]; } } @@ -502,8 +508,10 @@ class Media } $body = str_replace($picture[0], '', $body); $image = str_replace('-1.', '-0.', $picture[2]); - $attachments[$image] = ['uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, - 'preview' => $picture[2], 'description' => null]; + $attachments[$image] = [ + 'uri-id' => $uriid, 'type' => self::IMAGE, 'url' => $image, + 'preview' => $picture[2], 'description' => null + ]; } } @@ -631,7 +639,7 @@ class Media public static function insertFromAttachmentData(int $uriid, string $body) { $data = BBCode::getAttachmentData($body); - if (empty($data)) { + if (empty($data)) { return; } @@ -803,8 +811,10 @@ class Media continue; } - if (in_array($medium['type'], [self::AUDIO, self::IMAGE]) || - in_array($filetype, ['audio', 'image'])) { + if ( + in_array($medium['type'], [self::AUDIO, self::IMAGE]) || + in_array($filetype, ['audio', 'image']) + ) { $attachments['visual'][] = $medium; } elseif (($medium['type'] == self::VIDEO) || ($filetype == 'video')) { if (!empty($medium['height'])) { @@ -871,15 +881,15 @@ class Media if ($media['type'] == self::IMAGE) { if (!empty($media['preview'])) { if (!empty($media['description'])) { - $body .= "\n[url=" . $media['url'] . "][img=" . $media['preview'] . ']' . $media['description'] .'[/img][/url]'; + $body .= "\n[url=" . $media['url'] . "][img=" . $media['preview'] . ']' . $media['description'] . '[/img][/url]'; } else { - $body .= "\n[url=" . $media['url'] . "][img]" . $media['preview'] .'[/img][/url]'; + $body .= "\n[url=" . $media['url'] . "][img]" . $media['preview'] . '[/img][/url]'; } } else { if (!empty($media['description'])) { - $body .= "\n[img=" . $media['url'] . ']' . $media['description'] .'[/img]'; + $body .= "\n[img=" . $media['url'] . ']' . $media['description'] . '[/img]'; } else { - $body .= "\n[img]" . $media['url'] .'[/img]'; + $body .= "\n[img]" . $media['url'] . '[/img]'; } } } elseif ($media['type'] == self::AUDIO) { @@ -896,6 +906,13 @@ class Media return $body; } + /** + * Add an [attachment] element to the body for a given uri-id with a HTML media element + * + * @param integer $uriid + * @param string $body + * @return string + */ public static function addHTMLAttachmentToBody(int $uriid, string $body): string { if (preg_match("/.*(\[attachment.*?\].*?\[\/attachment\]).*/ism", $body, $match)) { @@ -929,6 +946,13 @@ class Media return $body; } + /** + * Add a link to the body for a given uri-id with a HTML media element + * + * @param integer $uriid + * @param string $body + * @return string + */ public static function addHTMLLinkToBody(int $uriid, string $body): string { $links = self::getByURIId($uriid, [self::HTML]); @@ -947,6 +971,12 @@ class Media } } + /** + * Add an [attachment] element to the body and a link to raw-body for a given uri-id with a HTML media element + * + * @param array $item + * @return array + */ public static function addHTMLAttachmentToItem(array $item): array { if (($item['gravity'] == Item::GRAVITY_ACTIVITY) || empty($item['uri-id'])) { diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index 91eb1cc2c4..5554af7d81 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -83,14 +83,21 @@ class Diaspora return $contacts; } - $items = Post::select(['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], - ['parent' => $item['parent'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]]); + $items = Post::select( + ['author-id', 'author-link', 'parent-author-link', 'parent-guid', 'guid'], + ['parent' => $item['parent'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]] + ); while ($item = Post::fetch($items)) { - $contact = DBA::selectFirst('contact', ['id', 'url', 'name', 'protocol', 'batch', 'network'], - ['id' => $item['author-id']]); - if (!DBA::isResult($contact) || empty($contact['batch']) || + $contact = DBA::selectFirst( + 'contact', + ['id', 'url', 'name', 'protocol', 'batch', 'network'], + ['id' => $item['author-id']] + ); + if ( + !DBA::isResult($contact) || empty($contact['batch']) || ($contact['network'] != Protocol::DIASPORA) || - Strings::compareLink($item['parent-author-link'], $item['author-link'])) { + Strings::compareLink($item['parent-author-link'], $item['author-link']) + ) { continue; } @@ -270,7 +277,7 @@ class Diaspora $basedom = XML::parseString($xml, true); if (!is_object($basedom)) { - Logger::notice('Received data does not seem to be an XML. Discarding. '.$xml); + Logger::notice('Received data does not seem to be an XML. Discarding. ' . $xml); if ($no_exit) { return false; } else { @@ -438,7 +445,7 @@ class Diaspora $alg = $base->alg; - $signed_data = $data.'.'.Strings::base64UrlEncode($type).'.'.Strings::base64UrlEncode($encoding).'.'.Strings::base64UrlEncode($alg); + $signed_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); // decode the data @@ -719,7 +726,8 @@ class Diaspora $signed_data .= $entry; } - if (!in_array($fieldname, ['parent_author_signature', 'target_author_signature']) + if ( + !in_array($fieldname, ['parent_author_signature', 'target_author_signature']) || ($orig_type == 'relayable_retraction') ) { XML::copy($entry, $fields, $fieldname); @@ -795,7 +803,7 @@ class Diaspora Logger::info('Fetching diaspora key', ['handle' => $uri->getAddr(), 'callstack' => System::callstack(20)]); try { return DI::dsprContact()->getByAddr($uri)->pubKey; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { return ''; } } @@ -1185,9 +1193,11 @@ class Diaspora */ private static function parentItem(int $uid, string $guid, WebFingerUri $author, array $contact) { - $fields = ['id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin', + $fields = [ + 'id', 'parent', 'body', 'wall', 'uri', 'guid', 'private', 'origin', 'author-name', 'author-link', 'author-avatar', 'gravity', - 'owner-name', 'owner-link', 'owner-avatar']; + 'owner-name', 'owner-link', 'owner-avatar' + ]; $condition = ['uid' => $uid, 'guid' => $guid]; $item = Post::selectFirst($fields, $condition); @@ -1435,7 +1445,7 @@ class Diaspora } elseif ($person_uri) { try { return DI::dsprContact()->selectOneByAddr($person_uri)->baseurl . '/objects/' . $guid; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { return ''; } } @@ -1472,7 +1482,6 @@ class Diaspora $contact = DI::dsprContact()->getByUrl(new Uri($match[3])); Tag::storeByHash($uriid, $match[1], $contact->name ?: $contact->nick, $contact->url); } catch (\Throwable $e) { - } } } @@ -1531,7 +1540,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -1783,7 +1792,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -1896,7 +1905,7 @@ class Diaspora try { $author = DI::dsprContact()->getByAddr($author_uri); - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find author details', ['author' => $author_uri->getAddr()]); return false; } @@ -1968,7 +1977,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('unable to find author details', ['author' => $author->getAddr()]); return false; } @@ -2013,8 +2022,10 @@ class Diaspora Logger::info('Participation stored', ['id' => $message_id, 'guid' => $guid, 'parent_guid' => $parent_guid, 'author' => $author]); // Send all existing comments and likes to the requesting server - $comments = Post::select(['id', 'uri-id', 'parent-author-network', 'author-network', 'verb', 'gravity'], - ['parent' => $toplevel_parent_item['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]]); + $comments = Post::select( + ['id', 'uri-id', 'parent-author-network', 'author-network', 'verb', 'gravity'], + ['parent' => $toplevel_parent_item['id'], 'gravity' => [Item::GRAVITY_COMMENT, Item::GRAVITY_ACTIVITY]] + ); while ($comment = Post::fetch($comments)) { if (($comment['gravity'] == Item::GRAVITY_ACTIVITY) && !in_array($comment['verb'], [Activity::LIKE, Activity::DISLIKE])) { Logger::info('Unsupported activities are not relayed', ['item' => $comment['id'], 'verb' => $comment['verb']]); @@ -2089,7 +2100,7 @@ class Diaspora return false; } - $name = XML::unescape($data->first_name).((strlen($data->last_name)) ? ' ' . XML::unescape($data->last_name) : ''); + $name = XML::unescape($data->first_name) . ((strlen($data->last_name)) ? ' ' . XML::unescape($data->last_name) : ''); $image_url = XML::unescape($data->image_url); $birthday = XML::unescape($data->birthday); $about = Markdown::toBBCode(XML::unescape($data->bio)); @@ -2136,10 +2147,12 @@ class Diaspora $birthday = $contact['bd']; } - $fields = ['name' => $name, 'location' => $location, + $fields = [ + 'name' => $name, 'location' => $location, 'name-date' => DateTimeFormat::utcNow(), 'about' => $about, 'addr' => $author->getAddr(), 'nick' => $author->getUser(), 'keywords' => $keywords, - 'unsearchable' => !$searchable, 'sensitive' => $nsfw]; + 'unsearchable' => !$searchable, 'sensitive' => $nsfw + ]; if (!empty($birthday)) { $fields['bd'] = $birthday; @@ -2249,7 +2262,7 @@ class Diaspora try { $author_url = (string)DI::dsprContact()->getByAddr($author)->url; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Cannot resolve diaspora handle for recipient', ['author' => $author->getAddr(), 'recipient' => $recipient]); return false; } @@ -2426,7 +2439,7 @@ class Diaspora try { $author = DI::dsprContact()->getByAddr($author_uri); - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { Logger::notice('Unable to find details for author', ['author' => $author_uri->getAddr()]); return false; } @@ -2561,7 +2574,7 @@ class Diaspora private static function storePhotoAsMedia(int $uriid, $photo) { // @TODO Need to find object type, roland@f.haeder.net - Logger::debug('photo='.get_class($photo)); + Logger::debug('photo=' . get_class($photo)); $data = []; $data['uri-id'] = $uriid; $data['type'] = Post\Media::IMAGE; @@ -2930,8 +2943,7 @@ class Diaspora try { $target = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr'])); $dest_url = $public_batch ? $target->batch : $target->notify; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { - + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { } if (empty($dest_url)) { @@ -3011,8 +3023,7 @@ class Diaspora if (!empty($contact['addr'])) { try { $pubkey = DI::dsprContact()->getByAddr(WebFingerUri::fromString($contact['addr']))->pubKey; - } catch (HTTPException\NotFoundException|\InvalidArgumentException $e) { - + } catch (HTTPException\NotFoundException | \InvalidArgumentException $e) { } } else { // The "addr" field should always be filled. @@ -3058,8 +3069,10 @@ class Diaspora // If the item belongs to a user, we take this user id. if ($item['uid'] == 0) { // @todo Possibly use an administrator account? - $condition = ['verified' => true, 'blocked' => false, - 'account_removed' => false, 'account_expired' => false, 'account-type' => User::ACCOUNT_TYPE_PERSON]; + $condition = [ + 'verified' => true, 'blocked' => false, + 'account_removed' => false, 'account_expired' => false, 'account-type' => User::ACCOUNT_TYPE_PERSON + ]; $first_user = DBA::selectFirst('user', ['uid'], $condition, ['order' => ['uid']]); $owner = User::getOwnerDataById($first_user['uid']); } else { @@ -3099,7 +3112,7 @@ class Diaspora $old_handle = DI::pConfig()->get($uid, 'system', 'previous_addr'); $profile = self::createProfileData($uid); - $signed_text = 'AccountMigration:'.$old_handle.':'.$profile['author']; + $signed_text = 'AccountMigration:' . $old_handle . ':' . $profile['author']; $signature = base64_encode(Crypto::rsaSign($signed_text, $owner['uprvkey'], 'sha256')); $message = [ @@ -3330,9 +3343,9 @@ class Diaspora // Fetch the title from an attached link - if there is one if (empty($item['title']) && DI::pConfig()->get($owner['uid'], 'system', 'attach_link_title')) { - $page_data = BBCode::getAttachmentData($item['body']); - if (!empty($page_data['type']) && !empty($page_data['title']) && ($page_data['type'] == 'link')) { - $title = $page_data['title']; + $media = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]); + if (!empty($media) && !empty($media[0]['name']) && ($media[0]['name'] != $media[0]['url'])) { + $title = $media[0]['name']; } } @@ -3388,9 +3401,11 @@ class Diaspora if (count($event)) { $message['event'] = $event; - if (!empty($event['location']['address']) && + if ( + !empty($event['location']['address']) && !empty($event['location']['lat']) && - !empty($event['location']['lng'])) { + !empty($event['location']['lng']) + ) { $message['location'] = $event['location']; } @@ -3453,7 +3468,8 @@ class Diaspora private static function prependParentAuthorMention(string $body, string $profile_url): string { $profile = Contact::getByURL($profile_url, false, ['addr', 'name']); - if (!empty($profile['addr']) + if ( + !empty($profile['addr']) && !strstr($body, $profile['addr']) && !strstr($body, $profile_url) ) { @@ -3908,9 +3924,9 @@ class Diaspora $kw = str_replace(' ', ' ', $kw); $arr = explode(' ', $kw); if (count($arr)) { - for ($x = 0; $x < 5; $x ++) { + for ($x = 0; $x < 5; $x++) { if (!empty($arr[$x])) { - $data['tag_string'] .= '#'. trim($arr[$x]) .' '; + $data['tag_string'] .= '#' . trim($arr[$x]) . ' '; } } } @@ -4095,7 +4111,7 @@ class Diaspora 'body' => '', 'quote-uri-id' => $UriId, 'allow_cid' => $owner['allow_cid'] ?? '', - 'allow_gid' => $owner['allow_gid']?? '', + 'allow_gid' => $owner['allow_gid'] ?? '', 'deny_cid' => $owner['deny_cid'] ?? '', 'deny_gid' => $owner['deny_gid'] ?? '', ]; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 625305161f..a83819742e 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -384,8 +384,10 @@ class Feed } if (!$dryRun) { - $condition = ["`uid` = ? AND `uri` = ? AND `network` IN (?, ?)", - $importer['uid'], $item['uri'], Protocol::FEED, Protocol::DFRN]; + $condition = [ + "`uid` = ? AND `uri` = ? AND `network` IN (?, ?)", + $importer['uid'], $item['uri'], Protocol::FEED, Protocol::DFRN + ]; $previous = Post::selectFirst(['id', 'created'], $condition); if (DBA::isResult($previous)) { // Use the creation date when the post had been stored. It can happen this date changes in the feed. @@ -644,8 +646,10 @@ class Feed if (!$notify) { Post\Delayed::publish($item, $notify, $taglist, $attachments); } else { - $postings[] = ['item' => $item, 'notify' => $notify, - 'taglist' => $taglist, 'attachments' => $attachments]; + $postings[] = [ + 'item' => $item, 'notify' => $notify, + 'taglist' => $taglist, 'attachments' => $attachments + ]; } } else { Logger::info('Post already created or exists in the delayed posts queue', ['uid' => $item['uid'], 'uri' => $item['uri']]); @@ -852,7 +856,7 @@ class Feed $min_poll_interval = max(1, DI::config()->get('system', 'min_poll_interval')); - $poll_intervals = [$min_poll_interval, 15, 30, 60, 120, 180, 360, 720 ,1440, 10080, 43200]; + $poll_intervals = [$min_poll_interval, 15, 30, 60, 120, 180, 360, 720, 1440, 10080, 43200]; //$poll_intervals = [$min_poll_interval . ' minute', '15 minute', '30 minute', // '1 hour', '2 hour', '3 hour', '6 hour', '12 hour' ,'1 day', '1 week', '1 month']; @@ -942,7 +946,7 @@ class Feed $previous_created = $last_update; // Don't cache when the last item was posted less then 15 minutes ago (Cache duration) - if ((time() - strtotime($owner['last-item'])) < 15*60) { + if ((time() - strtotime($owner['last-item'])) < 15 * 60) { $result = DI::cache()->get($cachekey); if (!$nocache && !is_null($result)) { Logger::info('Cached feed duration', ['seconds' => number_format(microtime(true) - $stamp, 3), 'nick' => $owner['nickname'], 'filter' => $filter, 'created' => $previous_created]); @@ -953,11 +957,13 @@ class Feed $check_date = empty($last_update) ? '' : DateTimeFormat::utc($last_update); $authorid = Contact::getIdForURL($owner['url']); - $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) + $condition = [ + "`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?, ?, ?)", $owner['uid'], $check_date, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::PRIVATE, Protocol::ACTIVITYPUB, - Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA]; + Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA + ]; if ($filter === 'comments') { $condition[0] .= " AND `gravity` = ? "; @@ -1130,8 +1136,15 @@ class Feed XML::addElement($doc, $entry, 'content', $body, ['type' => 'html']); - XML::addElement($doc, $entry, 'link', '', ['rel' => 'alternate', 'type' => 'text/html', - 'href' => DI::baseUrl() . '/display/' . $item['guid']] + XML::addElement( + $doc, + $entry, + 'link', + '', + [ + 'rel' => 'alternate', 'type' => 'text/html', + 'href' => DI::baseUrl() . '/display/' . $item['guid'] + ] ); XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); @@ -1173,12 +1186,14 @@ class Feed if (isset($parent_plink)) { $attributes = [ 'ref' => $item['thr-parent'], - 'href' => $parent_plink]; + 'href' => $parent_plink + ]; XML::addElement($doc, $entry, 'thr:in-reply-to', '', $attributes); $attributes = [ 'rel' => 'related', - 'href' => $parent_plink]; + 'href' => $parent_plink + ]; XML::addElement($doc, $entry, 'link', '', $attributes); } } @@ -1211,16 +1226,16 @@ class Feed } // Fetch information about the post - $siteinfo = BBCode::getAttachedData($item['body']); - if (isset($siteinfo['title'])) { - return $siteinfo['title']; + $media = Post\Media::getByURIId($item['uri-id'], [Post\Media::HTML]); + if (!empty($media) && !empty($media[0]['name']) && ($media[0]['name'] != $media[0]['url'])) { + return $media[0]['name']; } // If no bookmark is found then take the first line // Remove the share element before fetching the first line $title = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism", "\n$1\n", $item['body'])); - $title = BBCode::toPlaintext($title)."\n"; + $title = BBCode::toPlaintext($title) . "\n"; $pos = strpos($title, "\n"); $trailer = ''; if (($pos == 0) || ($pos > 100)) {