X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FProtocol%2FFeed.php;h=cbffd810c1d03b444faeedac9cd9ae201b2d623c;hb=b761760d6537a64b74d41bbe3a9e75a58254e947;hp=15c522040d636d0b1607b22f02332211e57ef2f1;hpb=0c12e947dd9f5f1db26b4c9eed43319ab364581b;p=friendica.git diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index 15c522040d..cbffd810c1 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -1,6 +1,6 @@ query('/rdf:RDF/rss:channel')->length > 0) { + $protocol = Conversation::PARCEL_RDF; $author['author-link'] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:link/text()'); $author['author-name'] = XML::getFirstNodeValue($xpath, '/rdf:RDF/rss:channel/rss:title/text()'); @@ -111,6 +118,7 @@ class Feed // Is it Atom? if ($xpath->query('/atom:feed')->length > 0) { + $protocol = Conversation::PARCEL_ATOM; $alternate = XML::getFirstAttributes($xpath, "atom:link[@rel='alternate']"); if (is_object($alternate)) { foreach ($alternate as $attribute) { @@ -194,6 +202,7 @@ class Feed // Is it RSS? if ($xpath->query('/rss/channel')->length > 0) { + $protocol = Conversation::PARCEL_RSS; $author['author-link'] = XML::getFirstNodeValue($xpath, '/rss/channel/link/text()'); $author['author-name'] = XML::getFirstNodeValue($xpath, '/rss/channel/title/text()'); @@ -246,18 +255,21 @@ class Feed $author['owner-avatar'] = $contact['thumb']; } - $header = []; - $header['uid'] = $importer['uid'] ?? 0; - $header['network'] = Protocol::FEED; - $header['wall'] = 0; - $header['origin'] = 0; - $header['gravity'] = GRAVITY_PARENT; - $header['private'] = Item::PUBLIC; - $header['verb'] = Activity::POST; - $header['object-type'] = Activity\ObjectType::NOTE; - $header['post-type'] = Item::PT_ARTICLE; - - $header['contact-id'] = $contact['id'] ?? 0; + $header = [ + 'uid' => $importer['uid'] ?? 0, + 'network' => Protocol::FEED, + 'wall' => 0, + 'origin' => 0, + 'gravity' => Item::GRAVITY_PARENT, + 'private' => Item::PUBLIC, + 'verb' => Activity::POST, + 'object-type' => Activity\ObjectType::NOTE, + 'post-type' => Item::PT_ARTICLE, + 'contact-id' => $contact['id'] ?? 0, + ]; + + $datarray['protocol'] = $protocol; + $datarray['direction'] = Conversation::PULL; if (!is_object($entries)) { Logger::info("There are no entries in this feed."); @@ -312,7 +324,7 @@ class Feed $item['uri'] = $guid; // Don't use the GUID value directly but instead use it as a basis for the GUID - $item['guid'] = Item::guidFromUri($guid, parse_url($guid, PHP_URL_HOST) ?? parse_url($item['plink'], PHP_URL_HOST) ?? ''); + $item['guid'] = Item::guidFromUri($guid, parse_url($guid, PHP_URL_HOST) ?? parse_url($item['plink'], PHP_URL_HOST)); } if (empty($item['uri'])) { @@ -364,11 +376,11 @@ class Feed } if ($published != '') { - $item['created'] = $published; + $item['created'] = trim($published); } if ($updated != '') { - $item['edited'] = $updated; + $item['edited'] = trim($updated); } if (!$dryRun) { @@ -378,7 +390,7 @@ class Feed if (DBA::isResult($previous)) { // Use the creation date when the post had been stored. It can happen this date changes in the feed. $creation_dates[] = $previous['created']; - Logger::info("Item with uri " . $item["uri"] . " for user " . $importer["uid"] . " already existed under id " . $previous["id"]); + Logger::info('Item with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . ' already existed under id ' . $previous['id']); continue; } $creation_dates[] = DateTimeFormat::utc($item['created']); @@ -427,7 +439,7 @@ class Feed } if (!empty($href)) { - $attachment = ['type' => Post\Media::UNKNOWN, 'url' => $href, 'mimetype' => $type, 'size' => $length]; + $attachment = ['uri-id' => -1, 'type' => Post\Media::UNKNOWN, 'url' => $href, 'mimetype' => $type, 'size' => $length]; $attachment = Post\Media::fetchAdditionalData($attachment); @@ -612,17 +624,19 @@ class Feed Logger::info('Stored feed', ['item' => $item]); $notify = Item::isRemoteSelf($contact, $item); + $item['wall'] = (bool)$notify; - // Distributed items should have a well formatted URI. - // Additionally we have to avoid conflicts with identical URI between imported feeds and these items. + // Distributed items should have a well-formatted URI. + // Additionally, we have to avoid conflicts with identical URI between imported feeds and these items. if ($notify) { - $item['guid'] = Item::guidFromUri($orig_plink, DI::baseUrl()->getHostname()); - $item['uri'] = Item::newURI($item['uid'], $item['guid']); + $item['guid'] = Item::guidFromUri($orig_plink, DI::baseUrl()->getHost()); + $item['uri'] = Item::newURI($item['guid']); + unset($item['plink']); unset($item['thr-parent']); unset($item['parent-uri']); // Set the delivery priority for "remote self" to "medium" - $notify = PRIORITY_MEDIUM; + $notify = Worker::PRIORITY_MEDIUM; } $condition = ['uid' => $item['uid'], 'uri' => $item['uri']]; @@ -683,7 +697,7 @@ class Feed /** * Automatically adjust the poll frequency according to the post frequency * - * @param array $contact + * @param array $contact Contact array * @param array $creation_dates * @return void */ @@ -803,7 +817,7 @@ class Feed * @param array $contact * @return int Poll interval in minutes */ - public static function getPollInterval(array $contact) + public static function getPollInterval(array $contact): int { if (in_array($contact['network'], [Protocol::MAIL, Protocol::FEED])) { $ratings = [0, 3, 7, 8, 9, 10]; @@ -852,39 +866,39 @@ class Feed * @param array $tags * @return string tag string */ - private static function tagToString(array $tags) + private static function tagToString(array $tags): string { $tagstr = ''; foreach ($tags as $tag) { - if ($tagstr != "") { - $tagstr .= ", "; + if ($tagstr != '') { + $tagstr .= ', '; } - $tagstr .= "#[url=" . DI::baseUrl() . "/search?tag=" . urlencode($tag) . "]" . $tag . "[/url]"; + $tagstr .= '#[url=' . DI::baseUrl() . '/search?tag=' . urlencode($tag) . ']' . $tag . '[/url]'; } return $tagstr; } - private static function titleIsBody($title, $body) + private static function titleIsBody(string $title, string $body): bool { $title = strip_tags($title); $title = trim($title); $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8'); - $title = str_replace(["\n", "\r", "\t", " "], ["", "", "", ""], $title); + $title = str_replace(["\n", "\r", "\t", " "], ['', '', '', ''], $title); $body = strip_tags($body); $body = trim($body); $body = html_entity_decode($body, ENT_QUOTES, 'UTF-8'); - $body = str_replace(["\n", "\r", "\t", " "], ["", "", "", ""], $body); + $body = str_replace(["\n", "\r", "\t", " "], ['', '', '', ''], $body); if (strlen($title) < strlen($body)) { $body = substr($body, 0, strlen($title)); } - if (($title != $body) && (substr($title, -3) == "...")) { - $pos = strrpos($title, "..."); + if (($title != $body) && (substr($title, -3) == '...')) { + $pos = strrpos($title, '...'); if ($pos > 0) { $title = substr($title, 0, $pos); $body = substr($body, 0, $pos); @@ -904,28 +918,23 @@ class Feed * Updates the provided last_update parameter if the result comes from the * cache or it is empty * - * @param string $owner_nick Nickname of the feed owner + * @param array $owner owner-view record of the feed owner * @param string $last_update Date of the last update * @param integer $max_items Number of maximum items to fetch * @param string $filter Feed items filter (activity, posts or comments) * @param boolean $nocache Wether to bypass caching * * @return string Atom feed - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function atom($owner_nick, $last_update, $max_items = 300, $filter = 'activity', $nocache = false) + public static function atom(array $owner, string $last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false) { $stamp = microtime(true); - $owner = User::getOwnerDataByNick($owner_nick); - if (!$owner) { - return; - } - - $cachekey = "feed:feed:" . $owner_nick . ":" . $filter . ":" . $last_update; + $cachekey = 'feed:feed:' . $owner['nickname'] . ':' . $filter . ':' . $last_update; - // Display events in the users's timezone + // Display events in the user's timezone if (strlen($owner['timezone'])) { DI::app()->setTimeZone($owner['timezone']); } @@ -936,28 +945,28 @@ class Feed 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_nick, 'filter' => $filter, 'created' => $previous_created]); + Logger::info('Cached feed duration', ['seconds' => number_format(microtime(true) - $stamp, 3), 'nick' => $owner['nickname'], 'filter' => $filter, 'created' => $previous_created]); return $result['feed']; } } $check_date = empty($last_update) ? '' : DateTimeFormat::utc($last_update); - $authorid = Contact::getIdForURL($owner["url"]); + $authorid = Contact::getIdForURL($owner['url']); $condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` AND `gravity` IN (?, ?) AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?, ?, ?)", - $owner["uid"], $check_date, GRAVITY_PARENT, GRAVITY_COMMENT, + $owner['uid'], $check_date, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, Item::PRIVATE, Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DFRN, Protocol::DIASPORA]; if ($filter === 'comments') { $condition[0] .= " AND `gravity` = ? "; - $condition[] = GRAVITY_COMMENT; + $condition[] = Item::GRAVITY_COMMENT; } if ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY) { $condition[0] .= " AND `contact-id` = ? AND `author-id` = ?"; - $condition[] = $owner["id"]; + $condition[] = $owner['id']; $condition[] = $authorid; } @@ -990,7 +999,7 @@ class Feed $msg = ['feed' => $feeddata, 'last_update' => $last_update]; DI::cache()->set($cachekey, $msg, Duration::QUARTER_HOUR); - Logger::info('Feed duration', ['seconds' => number_format(microtime(true) - $stamp, 3), 'nick' => $owner_nick, 'filter' => $filter, 'created' => $previous_created]); + Logger::info('Feed duration', ['seconds' => number_format(microtime(true) - $stamp, 3), 'nick' => $owner['nickname'], 'filter' => $filter, 'created' => $previous_created]); return $feeddata; } @@ -1002,16 +1011,16 @@ class Feed * @param array $owner Contact data of the poster * @param string $filter The related feed filter (activity, posts or comments) * - * @return object header root element + * @return DOMElement Header root element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addHeader(DOMDocument $doc, array $owner, $filter) + private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMElement { $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $doc->appendChild($root); $title = ''; - $selfUri = '/feed/' . $owner["nick"] . '/'; + $selfUri = '/feed/' . $owner['nick'] . '/'; switch ($filter) { case 'activity': $title = DI::l10n()->t('%s\'s timeline', $owner['name']); @@ -1026,24 +1035,24 @@ class Feed break; } - $attributes = ["uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION]; - XML::addElement($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); - XML::addElement($doc, $root, "id", DI::baseUrl() . "/profile/" . $owner["nick"]); - XML::addElement($doc, $root, "title", $title); - XML::addElement($doc, $root, "subtitle", sprintf("Updates from %s on %s", $owner["name"], DI::config()->get('config', 'sitename'))); - XML::addElement($doc, $root, "logo", User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); - XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM)); + $attributes = ['uri' => 'https://friendi.ca', 'version' => App::VERSION . '-' . DB_UPDATE_VERSION]; + XML::addElement($doc, $root, 'generator', App::PLATFORM, $attributes); + XML::addElement($doc, $root, 'id', DI::baseUrl() . '/profile/' . $owner['nick']); + XML::addElement($doc, $root, 'title', $title); + XML::addElement($doc, $root, 'subtitle', sprintf("Updates from %s on %s", $owner['name'], DI::config()->get('config', 'sitename'))); + XML::addElement($doc, $root, 'logo', User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); + XML::addElement($doc, $root, 'updated', DateTimeFormat::utcNow(DateTimeFormat::ATOM)); $author = self::addAuthor($doc, $owner); $root->appendChild($author); - $attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => $owner['url'], 'rel' => 'alternate', 'type' => 'text/html']; + XML::addElement($doc, $root, 'link', '', $attributes); - OStatus::hublinks($doc, $root, $owner["nick"]); + OStatus::addHubLink($doc, $root, $owner['nick']); - $attributes = ["href" => DI::baseUrl() . $selfUri, "rel" => "self", "type" => "application/atom+xml"]; - XML::addElement($doc, $root, "link", "", $attributes); + $attributes = ['href' => DI::baseUrl() . $selfUri, 'rel' => 'self', 'type' => 'application/atom+xml']; + XML::addElement($doc, $root, 'link', '', $attributes); return $root; } @@ -1053,16 +1062,15 @@ class Feed * * @param DOMDocument $doc XML document * @param array $owner Contact data of the poster - * - * @return \DOMElement author element + * @return DOMElement author element * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function addAuthor(DOMDocument $doc, array $owner) + private static function addAuthor(DOMDocument $doc, array $owner): DOMElement { - $author = $doc->createElement("author"); - XML::addElement($doc, $author, "uri", $owner["url"]); - XML::addElement($doc, $author, "name", $owner["nick"]); - XML::addElement($doc, $author, "email", $owner["addr"]); + $author = $doc->createElement('author'); + XML::addElement($doc, $author, 'uri', $owner['url']); + XML::addElement($doc, $author, 'name', $owner['nick']); + XML::addElement($doc, $author, 'email', $owner['addr']); return $author; } @@ -1074,15 +1082,14 @@ class Feed * @param array $item Data of the item that is to be posted * @param array $owner Contact data of the poster * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? - * - * @return \DOMElement Entry element + * @return DOMElement Entry element * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function noteEntry(DOMDocument $doc, array $item, array $owner) + private static function noteEntry(DOMDocument $doc, array $item, array $owner): DOMElement { - if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { - Logger::info('Feed entry author does not match feed owner', ['owner' => $owner["url"], 'author' => $item["author-link"]]); + if (($item['gravity'] != Item::GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) { + Logger::info('Feed entry author does not match feed owner', ['owner' => $owner['url'], 'author' => $item['author-link']]); } $entry = OStatus::entryHeader($doc, $owner, $item, false); @@ -1104,31 +1111,31 @@ class Feed * @param string $title Title for the post * @param string $verb The activity verb * @param bool $complete Add the "status_net" element? - * @param bool $feed_mode Behave like a regular feed for users if true * @return void * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - private static function entryContent(DOMDocument $doc, \DOMElement $entry, array $item, $title, $verb = "", $complete = true) + private static function entryContent(DOMDocument $doc, DOMElement $entry, array $item, $title, string $verb = '', bool $complete = true) { - if ($verb == "") { + if ($verb == '') { $verb = OStatus::constructVerb($item); } - XML::addElement($doc, $entry, "id", $item["uri"]); - XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); + XML::addElement($doc, $entry, 'id', $item['uri']); + XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8')); - $body = OStatus::formatPicturePost($item['body'], $item['uri-id']); + $body = Post\Media::addAttachmentsToBody($item['uri-id'], DI::contentItem()->addSharedPost($item)); + $body = Post\Media::addHTMLAttachmentToBody($item['uri-id'], $body); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::ACTIVITYPUB); - XML::addElement($doc, $entry, "content", $body, ["type" => "html"]); + 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)); - XML::addElement($doc, $entry, "updated", DateTimeFormat::utc($item["edited"]."+00:00", DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'published', DateTimeFormat::utc($item['created'] . '+00:00', DateTimeFormat::ATOM)); + XML::addElement($doc, $entry, 'updated', DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM)); } /** @@ -1146,7 +1153,7 @@ class Feed { $mentioned = []; - if ($item['gravity'] != GRAVITY_PARENT) { + if ($item['gravity'] != Item::GRAVITY_PARENT) { $parent = Post::selectFirst(['guid', 'author-link', 'owner-link'], ['id' => $item['parent']]); $thrparent = Post::selectFirst(['guid', 'author-link', 'owner-link', 'plink'], ['uid' => $owner['uid'], 'uri' => $item['thr-parent']]); @@ -1197,28 +1204,28 @@ class Feed * @param array $item * @return string title */ - private static function getTitle(array $item) + private static function getTitle(array $item): string { if ($item['title'] != '') { return BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::ACTIVITYPUB); } // Fetch information about the post - $siteinfo = BBCode::getAttachedData($item["body"]); - if (isset($siteinfo["title"])) { - return $siteinfo["title"]; + $siteinfo = BBCode::getAttachedData($item['body']); + if (isset($siteinfo['title'])) { + return $siteinfo['title']; } // 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 = trim(preg_replace("/\[share.*?\](.*?)\[\/share\]/ism", "\n$1\n", $item['body'])); $title = BBCode::toPlaintext($title)."\n"; $pos = strpos($title, "\n"); - $trailer = ""; + $trailer = ''; if (($pos == 0) || ($pos > 100)) { $pos = 100; - $trailer = "..."; + $trailer = '...'; } return substr($title, 0, $pos) . $trailer;