1
0
Fork 0
- added type-hints
- added some documentation
- added default: block for unknown 'rel' value
- changed return type void to empty array
This commit is contained in:
Roland Häder 2022-06-22 05:44:57 +02:00
commit abd0d9f3fd
Signed by: roland
GPG key ID: C82EDE5DDFA0BA77
5 changed files with 527 additions and 466 deletions

View file

@ -383,7 +383,7 @@ class DFRN
if ($public) { if ($public) {
// DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed. // DFRN itself doesn't uses this. But maybe someone else wants to subscribe to the public feed.
OStatus::hublinks($doc, $root, $owner["nick"]); OStatus::addHubLink($doc, $root, $owner["nick"]);
$attributes = ["rel" => "salmon", "href" => DI::baseUrl()."/salmon/".$owner["nick"]]; $attributes = ["rel" => "salmon", "href" => DI::baseUrl()."/salmon/".$owner["nick"]];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, "link", "", $attributes);

View file

@ -1040,7 +1040,7 @@ class Feed
$attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"]; $attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"];
XML::addElement($doc, $root, "link", "", $attributes); 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"]; $attributes = ["href" => DI::baseUrl() . $selfUri, "rel" => "self", "type" => "application/atom+xml"];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, "link", "", $attributes);

View file

@ -21,7 +21,9 @@
namespace Friendica\Protocol; namespace Friendica\Protocol;
use DOMAttr;
use DOMDocument; use DOMDocument;
use DOMElement;
use DOMXPath; use DOMXPath;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML; use Friendica\Content\Text\HTML;
@ -67,24 +69,24 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function fetchAuthor(DOMXPath $xpath, $context, array $importer, array &$contact = null, $onlyfetch) private static function fetchAuthor(DOMXPath $xpath, $context, array $importer, array &$contact = null, bool $onlyfetch): array
{ {
$author = []; $author = [];
$author["author-link"] = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); $author['author-link'] = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context);
$author["author-name"] = XML::getFirstNodeValue($xpath, 'atom:author/atom:name/text()', $context); $author['author-name'] = XML::getFirstNodeValue($xpath, 'atom:author/atom:name/text()', $context);
$addr = XML::getFirstNodeValue($xpath, 'atom:author/atom:email/text()', $context); $addr = XML::getFirstNodeValue($xpath, 'atom:author/atom:email/text()', $context);
$aliaslink = $author["author-link"]; $aliaslink = $author['author-link'];
$alternate_item = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0); $alternate_item = $xpath->query("atom:author/atom:link[@rel='alternate']", $context)->item(0);
if (is_object($alternate_item)) { if (is_object($alternate_item)) {
foreach ($alternate_item->attributes as $attributes) { foreach ($alternate_item->attributes as $attributes) {
if (($attributes->name == "href") && ($attributes->textContent != "")) { if (($attributes->name == 'href') && ($attributes->textContent != '')) {
$author["author-link"] = $attributes->textContent; $author['author-link'] = $attributes->textContent;
} }
} }
} }
$author["author-id"] = Contact::getIdForURL($author["author-link"]); $author['author-id'] = Contact::getIdForURL($author['author-link']);
$author['contact-id'] = ($contact['id'] ?? 0) ?: $author['author-id']; $author['contact-id'] = ($contact['id'] ?? 0) ?: $author['author-id'];
@ -94,34 +96,45 @@ class OStatus
This here would be better, but we would get problems with contacts from the statusnet addon This here would be better, but we would get problems with contacts from the statusnet addon
This is kept here as a reminder for the future This is kept here as a reminder for the future
$cid = Contact::getIdForURL($author["author-link"], $importer["uid"]); $cid = Contact::getIdForURL($author['author-link'], $importer['uid']);
if ($cid) { if ($cid) {
$contact = DBA::selectFirst('contact', [], ['id' => $cid]); $contact = DBA::selectFirst('contact', [], ['id' => $cid]);
} }
*/ */
if ($aliaslink != '') { if ($aliaslink != '') {
$condition = ["`uid` = ? AND `alias` = ? AND `network` != ? AND `rel` IN (?, ?)", $contact = DBA::selectFirst('contact', [], [
$importer["uid"], $aliaslink, Protocol::STATUSNET, "`uid` = ? AND `alias` = ? AND `network` != ? AND `rel` IN (?, ?)",
Contact::SHARING, Contact::FRIEND]; $importer['uid'],
$contact = DBA::selectFirst('contact', [], $condition); $aliaslink, Protocol::STATUSNET,
Contact::SHARING, Contact::FRIEND,
]);
} }
if (!DBA::isResult($contact) && $author["author-link"] != '') { if (!DBA::isResult($contact) && $author['author-link'] != '') {
if ($aliaslink == "") { if ($aliaslink == '') {
$aliaslink = $author["author-link"]; $aliaslink = $author['author-link'];
} }
$condition = ["`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)", $contact = DBA::selectFirst('contact', [], [
$importer["uid"], Strings::normaliseLink($author["author-link"]), Strings::normaliseLink($aliaslink), "`uid` = ? AND `nurl` IN (?, ?) AND `network` != ? AND `rel` IN (?, ?)",
Protocol::STATUSNET, Contact::SHARING, Contact::FRIEND]; $importer['uid'],
$contact = DBA::selectFirst('contact', [], $condition); Strings::normaliseLink($author['author-link']),
Strings::normaliseLink($aliaslink),
Protocol::STATUSNET,
Contact::SHARING,
Contact::FRIEND,
]);
} }
if (!DBA::isResult($contact) && ($addr != '')) { if (!DBA::isResult($contact) && ($addr != '')) {
$condition = ["`uid` = ? AND `addr` = ? AND `network` != ? AND `rel` IN (?, ?)", $contact = DBA::selectFirst('contact', [], [
$importer["uid"], $addr, Protocol::STATUSNET, "`uid` = ? AND `addr` = ? AND `network` != ? AND `rel` IN (?, ?)",
Contact::SHARING, Contact::FRIEND]; $importer['uid'],
$contact = DBA::selectFirst('contact', [], $condition); $addr,
Protocol::STATUSNET,
Contact::SHARING,
Contact::FRIEND,
]);
} }
if (DBA::isResult($contact)) { if (DBA::isResult($contact)) {
@ -130,40 +143,40 @@ class OStatus
} elseif (!empty(APContact::getByURL($contact['url'], false))) { } elseif (!empty(APContact::getByURL($contact['url'], false))) {
ActivityPub\Receiver::switchContact($contact['id'], $importer['uid'], $contact['url']); ActivityPub\Receiver::switchContact($contact['id'], $importer['uid'], $contact['url']);
} }
$author["contact-id"] = $contact["id"]; $author['contact-id'] = $contact['id'];
} }
$avatarlist = []; $avatarlist = [];
$avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context); $avatars = $xpath->query("atom:author/atom:link[@rel='avatar']", $context);
foreach ($avatars as $avatar) { foreach ($avatars as $avatar) {
$href = ""; $href = '';
$width = 0; $width = 0;
foreach ($avatar->attributes as $attributes) { foreach ($avatar->attributes as $attributes) {
if ($attributes->name == "href") { if ($attributes->name == 'href') {
$href = $attributes->textContent; $href = $attributes->textContent;
} }
if ($attributes->name == "width") { if ($attributes->name == 'width') {
$width = $attributes->textContent; $width = $attributes->textContent;
} }
} }
if ($href != "") { if ($href != '') {
$avatarlist[$width] = $href; $avatarlist[$width] = $href;
} }
} }
if (count($avatarlist) > 0) { if (count($avatarlist) > 0) {
krsort($avatarlist); krsort($avatarlist);
$author["author-avatar"] = Probe::fixAvatar(current($avatarlist), $author["author-link"]); $author['author-avatar'] = Probe::fixAvatar(current($avatarlist), $author['author-link']);
} }
$displayname = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context); $displayname = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context);
if ($displayname != "") { if ($displayname != '') {
$author["author-name"] = $displayname; $author['author-name'] = $displayname;
} }
$author["owner-id"] = $author["author-id"]; $author['owner-id'] = $author['author-id'];
// Only update the contacts if it is an OStatus contact // Only update the contacts if it is an OStatus contact
if (DBA::isResult($contact) && ($contact['id'] > 0) && !$onlyfetch && ($contact["network"] == Protocol::OSTATUS)) { if (DBA::isResult($contact) && ($contact['id'] > 0) && !$onlyfetch && ($contact['network'] == Protocol::OSTATUS)) {
// Update contact data // Update contact data
$current = $contact; $current = $contact;
@ -179,41 +192,41 @@ class OStatus
// if ($value != "") // if ($value != "")
// $contact["poll"] = $value; // $contact["poll"] = $value;
$contact['url'] = $author["author-link"]; $contact['url'] = $author['author-link'];
$contact['nurl'] = Strings::normaliseLink($contact['url']); $contact['nurl'] = Strings::normaliseLink($contact['url']);
$value = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context); $value = XML::getFirstNodeValue($xpath, 'atom:author/atom:uri/text()', $context);
if ($value != "") { if ($value != '') {
$contact["alias"] = $value; $contact['alias'] = $value;
} }
$value = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context); $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:displayName/text()', $context);
if ($value != "") { if ($value != '') {
$contact["name"] = $value; $contact['name'] = $value;
} }
$value = XML::getFirstNodeValue($xpath, 'atom:author/poco:preferredUsername/text()', $context); $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:preferredUsername/text()', $context);
if ($value != "") { if ($value != '') {
$contact["nick"] = $value; $contact['nick'] = $value;
} }
$value = XML::getFirstNodeValue($xpath, 'atom:author/poco:note/text()', $context); $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:note/text()', $context);
if ($value != "") { if ($value != '') {
$contact["about"] = HTML::toBBCode($value); $contact['about'] = HTML::toBBCode($value);
} }
$value = XML::getFirstNodeValue($xpath, 'atom:author/poco:address/poco:formatted/text()', $context); $value = XML::getFirstNodeValue($xpath, 'atom:author/poco:address/poco:formatted/text()', $context);
if ($value != "") { if ($value != '') {
$contact["location"] = $value; $contact['location'] = $value;
} }
$contact['name-date'] = DateTimeFormat::utcNow(); $contact['name-date'] = DateTimeFormat::utcNow();
Contact::update($contact, ['id' => $contact["id"]], $current); Contact::update($contact, ['id' => $contact['id']], $current);
if (!empty($author["author-avatar"]) && ($author["author-avatar"] != $current['avatar'])) { if (!empty($author['author-avatar']) && ($author['author-avatar'] != $current['avatar'])) {
Logger::info("Update profile picture for contact ".$contact["id"]); Logger::info("Update profile picture for contact ".$contact["id"]);
Contact::updateAvatar($contact["id"], $author["author-avatar"]); Contact::updateAvatar($contact['id'], $author['author-avatar']);
} }
// Ensure that we are having this contact (with uid=0) // Ensure that we are having this contact (with uid=0)
@ -224,20 +237,26 @@ class OStatus
$old_contact = DBA::selectFirst('contact', $fields, ['id' => $cid]); $old_contact = DBA::selectFirst('contact', $fields, ['id' => $cid]);
// Update it with the current values // Update it with the current values
$fields = ['url' => $author["author-link"], 'name' => $contact["name"], $fields = [
'nurl' => Strings::normaliseLink($author["author-link"]), 'url' => $author['author-link'],
'nick' => $contact["nick"], 'alias' => $contact["alias"], 'name' => $contact['name'],
'about' => $contact["about"], 'location' => $contact["location"], 'nurl' => Strings::normaliseLink($author['author-link']),
'success_update' => DateTimeFormat::utcNow(), 'last-update' => DateTimeFormat::utcNow()]; 'nick' => $contact['nick'],
'alias' => $contact['alias'],
'about' => $contact['about'],
'location' => $contact['location'],
'success_update' => DateTimeFormat::utcNow(),
'last-update' => DateTimeFormat::utcNow(),
];
Contact::update($fields, ['id' => $cid], $old_contact); Contact::update($fields, ['id' => $cid], $old_contact);
// Update the avatar // Update the avatar
if (!empty($author["author-avatar"])) { if (!empty($author['author-avatar'])) {
Contact::updateAvatar($cid, $author["author-avatar"]); Contact::updateAvatar($cid, $author['author-avatar']);
} }
} }
} elseif (empty($contact["network"]) || ($contact["network"] != Protocol::DFRN)) { } elseif (empty($contact['network']) || ($contact['network'] != Protocol::DFRN)) {
$contact = []; $contact = [];
} }
@ -254,10 +273,10 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function salmonAuthor($xml, array $importer) public static function salmonAuthor(string $xml, array $importer): array
{ {
if ($xml == "") { if (empty($xml)) {
return; return [];
} }
$doc = new DOMDocument(); $doc = new DOMDocument();
@ -273,7 +292,7 @@ class OStatus
$xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS); $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS);
$xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET); $xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET);
$contact = ["id" => 0]; $contact = ['id' => 0];
// Fetch the first author // Fetch the first author
$authordata = $xpath->query('//author')->item(0); $authordata = $xpath->query('//author')->item(0);
@ -285,10 +304,9 @@ class OStatus
* Read attributes from element * Read attributes from element
* *
* @param object $element Element object * @param object $element Element object
*
* @return array attributes * @return array attributes
*/ */
private static function readAttributes($element) private static function readAttributes($element): array
{ {
$attribute = []; $attribute = [];
@ -324,12 +342,12 @@ class OStatus
* @param string $hub Called by reference, returns the fetched hub data * @param string $hub Called by reference, returns the fetched hub data
* @param boolean $stored Is the post fresh imported or from the database? * @param boolean $stored Is the post fresh imported or from the database?
* @param boolean $initialize Is it the leading post so that data has to be initialized? * @param boolean $initialize Is it the leading post so that data has to be initialized?
* * @param integer $direction Direction, default UNKNOWN(0)
* @return boolean Could the XML be processed? * @return boolean Could the XML be processed?
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function process($xml, array $importer, array &$contact = null, &$hub, $stored = false, $initialize = true, $direction = Conversation::UNKNOWN) private static function process(string $xml, array $importer, array &$contact = null, string &$hub, bool $stored = false, bool $initialize = true, int $direction = Conversation::UNKNOWN)
{ {
if ($initialize) { if ($initialize) {
self::$itemlist = []; self::$itemlist = [];
@ -338,9 +356,10 @@ class OStatus
Logger::info('Import OStatus message for user ' . $importer['uid']); Logger::info('Import OStatus message for user ' . $importer['uid']);
if ($xml == "") { if (empty($xml)) {
return false; return false;
} }
$doc = new DOMDocument(); $doc = new DOMDocument();
@$doc->loadXML($xml); @$doc->loadXML($xml);
@ -354,26 +373,26 @@ class OStatus
$xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS); $xpath->registerNamespace('ostatus', ActivityNamespace::OSTATUS);
$xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET); $xpath->registerNamespace('statusnet', ActivityNamespace::STATUSNET);
$hub = ""; $hub = '';
$hub_items = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0); $hub_items = $xpath->query("/atom:feed/atom:link[@rel='hub']")->item(0);
if (is_object($hub_items)) { if (is_object($hub_items)) {
$hub_attributes = $hub_items->attributes; $hub_attributes = $hub_items->attributes;
if (is_object($hub_attributes)) { if (is_object($hub_attributes)) {
foreach ($hub_attributes as $hub_attribute) { foreach ($hub_attributes as $hub_attribute) {
if ($hub_attribute->name == "href") { if ($hub_attribute->name == 'href') {
$hub = $hub_attribute->textContent; $hub = $hub_attribute->textContent;
Logger::info("Found hub ".$hub); Logger::info("Found hub ", ['hub' => $hub]);
} }
} }
} }
} }
$header = []; $header = [];
$header["uid"] = $importer["uid"]; $header['uid'] = $importer['uid'];
$header["network"] = Protocol::OSTATUS; $header['network'] = Protocol::OSTATUS;
$header["wall"] = 0; $header['wall'] = 0;
$header["origin"] = 0; $header['origin'] = 0;
$header["gravity"] = GRAVITY_COMMENT; $header['gravity'] = GRAVITY_COMMENT;
if (!is_object($doc->firstChild) || empty($doc->firstChild->tagName)) { if (!is_object($doc->firstChild) || empty($doc->firstChild->tagName)) {
return false; return false;
@ -381,7 +400,7 @@ class OStatus
$first_child = $doc->firstChild->tagName; $first_child = $doc->firstChild->tagName;
if ($first_child == "feed") { if ($first_child == 'feed') {
$entries = $xpath->query('/atom:feed/atom:entry'); $entries = $xpath->query('/atom:feed/atom:entry');
} else { } else {
$entries = $xpath->query('/atom:entry'); $entries = $xpath->query('/atom:entry');
@ -395,9 +414,9 @@ class OStatus
$doc2->formatOutput = true; $doc2->formatOutput = true;
$xml2 = $doc2->saveXML(); $xml2 = $doc2->saveXML();
$header["protocol"] = Conversation::PARCEL_SALMON; $header['protocol'] = Conversation::PARCEL_SALMON;
$header["source"] = $xml2; $header['source'] = $xml2;
$header["direction"] = $direction; $header['direction'] = $direction;
} elseif (!$initialize) { } elseif (!$initialize) {
return false; return false;
} }
@ -427,67 +446,67 @@ class OStatus
$item = array_merge($header, $author); $item = array_merge($header, $author);
$item["uri"] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry); $item['uri'] = XML::getFirstNodeValue($xpath, 'atom:id/text()', $entry);
$item['uri-id'] = ItemURI::insert(['uri' => $item['uri']]); $item['uri-id'] = ItemURI::insert(['uri' => $item['uri']]);
$item["verb"] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $entry); $item['verb'] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $entry);
// Delete a message // Delete a message
if (in_array($item["verb"], ['qvitter-delete-notice', Activity::DELETE, 'delete'])) { if (in_array($item['verb'], ['qvitter-delete-notice', Activity::DELETE, 'delete'])) {
self::deleteNotice($item); self::deleteNotice($item);
continue; continue;
} }
if (in_array($item["verb"], [Activity::O_UNFAVOURITE, Activity::UNFAVORITE])) { if (in_array($item['verb'], [Activity::O_UNFAVOURITE, Activity::UNFAVORITE])) {
// Ignore "Unfavorite" message // Ignore "Unfavorite" message
Logger::info("Ignore unfavorite message ", ['item' => $item]); Logger::info("Ignore unfavorite message ", ['item' => $item]);
continue; continue;
} }
// Deletions come with the same uri, so we check for duplicates after processing deletions // Deletions come with the same uri, so we check for duplicates after processing deletions
if (Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]])) { if (Post::exists(['uid' => $importer['uid'], 'uri' => $item['uri']])) {
Logger::info('Post with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.'); Logger::info('Post with URI ' . $item['uri'] . ' already existed for user ' . $importer['uid'] . '.');
continue; continue;
} else { } else {
Logger::info('Processing post with URI '.$item["uri"].' for user '.$importer["uid"].'.'); Logger::info('Processing post with URI ' . $item['uri'] . ' for user ' . $importer['uid'] . '.');
} }
if ($item["verb"] == Activity::JOIN) { if ($item['verb'] == Activity::JOIN) {
// ignore "Join" messages // ignore "Join" messages
Logger::info("Ignore join message ", ['item' => $item]); Logger::info("Ignore join message ", ['item' => $item]);
continue; continue;
} }
if ($item["verb"] == "http://mastodon.social/schema/1.0/block") { if ($item['verb'] == 'http://mastodon.social/schema/1.0/block') {
// ignore mastodon "block" messages // ignore mastodon "block" messages
Logger::info("Ignore block message ", ['item' => $item]); Logger::info("Ignore block message ", ['item' => $item]);
continue; continue;
} }
if ($item["verb"] == Activity::FOLLOW) { if ($item['verb'] == Activity::FOLLOW) {
Contact::addRelationship($importer, $contact, $item); Contact::addRelationship($importer, $contact, $item);
continue; continue;
} }
if ($item["verb"] == Activity::O_UNFOLLOW) { if ($item['verb'] == Activity::O_UNFOLLOW) {
$dummy = null; $dummy = null;
Contact::removeFollower($contact); Contact::removeFollower($contact);
continue; continue;
} }
if ($item["verb"] == Activity::FAVORITE) { if ($item['verb'] == Activity::FAVORITE) {
$orig_uri = $xpath->query("activity:object/atom:id", $entry)->item(0)->nodeValue; $orig_uri = $xpath->query('activity:object/atom:id', $entry)->item(0)->nodeValue;
Logger::notice("Favorite", ['uri' => $orig_uri, 'item' => $item]); Logger::notice("Favorite", ['uri' => $orig_uri, 'item' => $item]);
$item["verb"] = Activity::LIKE; $item['verb'] = Activity::LIKE;
$item["thr-parent"] = $orig_uri; $item['thr-parent'] = $orig_uri;
$item["gravity"] = GRAVITY_ACTIVITY; $item['gravity'] = GRAVITY_ACTIVITY;
$item["object-type"] = Activity\ObjectType::NOTE; $item['object-type'] = Activity\ObjectType::NOTE;
} }
// http://activitystrea.ms/schema/1.0/rsvp-yes // http://activitystrea.ms/schema/1.0/rsvp-yes
if (!in_array($item["verb"], [Activity::POST, Activity::LIKE, Activity::SHARE])) { if (!in_array($item['verb'], [Activity::POST, Activity::LIKE, Activity::SHARE])) {
Logger::info("Unhandled verb", ['verb' => $item["verb"], 'item' => $item]); Logger::info("Unhandled verb", ['verb' => $item['verb'], 'item' => $item]);
} }
self::processPost($xpath, $entry, $item, $importer); self::processPost($xpath, $entry, $item, $importer);
@ -503,10 +522,10 @@ class OStatus
$valid = !$uid || DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_NONE; $valid = !$uid || DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_NONE;
if ($valid) { if ($valid) {
Logger::info("Item with uri ".self::$itemlist[0]['uri']." will be imported due to the system settings."); Logger::info("Item with uri " . self::$itemlist[0]['uri'] . " will be imported due to the system settings.");
} }
} else { } else {
Logger::info("Item with uri ".self::$itemlist[0]['uri']." belongs to a contact (".self::$itemlist[0]['contact-id']."). It will be imported."); Logger::info("Item with uri " . self::$itemlist[0]['uri'] . " belongs to a contact (" . self::$itemlist[0]['contact-id'] . "). It will be imported.");
} }
if ($valid && DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_LIKE) { if ($valid && DI::pConfig()->get($uid, 'system', 'accept_only_sharer') != Item::COMPLETION_LIKE) {
@ -519,7 +538,7 @@ class OStatus
} }
} }
if ($valid) { if ($valid) {
Logger::info("Item with uri ".self::$itemlist[0]['uri']." will be imported since the thread contains posts or shares."); Logger::info("Item with URI " . self::$itemlist[0]['uri'] . " will be imported since the thread contains posts or shares.");
} }
} }
} else { } else {
@ -536,20 +555,20 @@ class OStatus
} }
} }
foreach (self::$itemlist as $item) { foreach (self::$itemlist as $item) {
$found = Post::exists(['uid' => $importer["uid"], 'uri' => $item["uri"]]); $found = Post::exists(['uid' => $importer['uid'], 'uri' => $item['uri']]);
if ($found) { if ($found) {
Logger::notice("Item with uri ".$item["uri"]." for user ".$importer["uid"]." already exists."); Logger::notice("Item with uri " . $item['uri'] . " for user " . $importer['uid'] . " already exists.");
} elseif ($item['contact-id'] < 0) { } elseif ($item['contact-id'] < 0) {
Logger::notice("Item with uri ".$item["uri"]." is from a blocked contact."); Logger::notice("Item with uri " . $item['uri'] . " is from a blocked contact.");
} else { } else {
$ret = Item::insert($item); $ret = Item::insert($item);
Logger::info("Item with uri ".$item["uri"]." for user ".$importer["uid"].' stored. Return value: '.$ret); Logger::info("Item with uri " . $item['uri'] . " for user " . $importer['uid'] . " stored. Return value: " . $ret);
} }
} }
} }
self::$itemlist = []; self::$itemlist = [];
} }
Logger::info('Processing done for post with URI '.$item["uri"].' for user '.$importer["uid"].'.'); Logger::info('Processing done for post with URI ' . $item['uri'] . ' for user '.$importer['uid'] . '.');
} }
return true; return true;
} }
@ -565,13 +584,13 @@ class OStatus
{ {
$condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'uri' => $item['uri']]; $condition = ['uid' => $item['uid'], 'author-id' => $item['author-id'], 'uri' => $item['uri']];
if (!Post::exists($condition)) { if (!Post::exists($condition)) {
Logger::notice('Item from '.$item['author-link'].' with uri '.$item['uri'].' for user '.$item['uid']." wasn't found. We don't delete it."); Logger::notice('Item from ' . $item['author-link'] . ' with uri ' . $item['uri'] . ' for user ' . $item['uid'] . " wasn't found. We don't delete it.");
return; return;
} }
Item::markForDeletion($condition); Item::markForDeletion($condition);
Logger::notice('Deleted item with uri '.$item['uri'].' for user '.$item['uid']); Logger::notice('Deleted item with URI ' . $item['uri'] . ' for user ' . $item['uid']);
} }
/** /**
@ -587,40 +606,40 @@ class OStatus
*/ */
private static function processPost(DOMXPath $xpath, $entry, array &$item, array $importer) private static function processPost(DOMXPath $xpath, $entry, array &$item, array $importer)
{ {
$item["body"] = HTML::toBBCode(XML::getFirstNodeValue($xpath, 'atom:content/text()', $entry)); $item['body'] = HTML::toBBCode(XML::getFirstNodeValue($xpath, 'atom:content/text()', $entry));
$item["object-type"] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry); $item['object-type'] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $entry);
if (($item["object-type"] == Activity\ObjectType::BOOKMARK) || ($item["object-type"] == Activity\ObjectType::EVENT)) { if (($item['object-type'] == Activity\ObjectType::BOOKMARK) || ($item['object-type'] == Activity\ObjectType::EVENT)) {
$item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry);
$item["body"] = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry); $item['body'] = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry);
} elseif ($item["object-type"] == Activity\ObjectType::QUESTION) { } elseif ($item['object-type'] == Activity\ObjectType::QUESTION) {
$item["title"] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry); $item['title'] = XML::getFirstNodeValue($xpath, 'atom:title/text()', $entry);
} }
$item["created"] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry); $item['created'] = XML::getFirstNodeValue($xpath, 'atom:published/text()', $entry);
$item["edited"] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry); $item['edited'] = XML::getFirstNodeValue($xpath, 'atom:updated/text()', $entry);
$item['conversation-uri'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry); $item['conversation-uri'] = XML::getFirstNodeValue($xpath, 'ostatus:conversation/text()', $entry);
$conv = $xpath->query('ostatus:conversation', $entry); $conv = $xpath->query('ostatus:conversation', $entry);
if (is_object($conv->item(0))) { if (is_object($conv->item(0))) {
foreach ($conv->item(0)->attributes as $attributes) { foreach ($conv->item(0)->attributes as $attributes) {
if ($attributes->name == "ref") { if ($attributes->name == 'ref') {
$item['conversation-uri'] = $attributes->textContent; $item['conversation-uri'] = $attributes->textContent;
} }
if ($attributes->name == "href") { if ($attributes->name == 'href') {
$item['conversation-href'] = $attributes->textContent; $item['conversation-href'] = $attributes->textContent;
} }
} }
} }
$related = ""; $related = '';
$inreplyto = $xpath->query('thr:in-reply-to', $entry); $inreplyto = $xpath->query('thr:in-reply-to', $entry);
if (is_object($inreplyto->item(0))) { if (is_object($inreplyto->item(0))) {
foreach ($inreplyto->item(0)->attributes as $attributes) { foreach ($inreplyto->item(0)->attributes as $attributes) {
if ($attributes->name == "ref") { if ($attributes->name == 'ref') {
$item["thr-parent"] = $attributes->textContent; $item['thr-parent'] = $attributes->textContent;
} }
if ($attributes->name == "href") { if ($attributes->name == 'href') {
$related = $attributes->textContent; $related = $attributes->textContent;
} }
} }
@ -628,7 +647,7 @@ class OStatus
$georsspoint = $xpath->query('georss:point', $entry); $georsspoint = $xpath->query('georss:point', $entry);
if (!empty($georsspoint) && ($georsspoint->length > 0)) { if (!empty($georsspoint) && ($georsspoint->length > 0)) {
$item["coord"] = $georsspoint->item(0)->nodeValue; $item['coord'] = $georsspoint->item(0)->nodeValue;
} }
$categories = $xpath->query('atom:category', $entry); $categories = $xpath->query('atom:category', $entry);
@ -653,33 +672,33 @@ class OStatus
$add_body = $link_data['add_body']; $add_body = $link_data['add_body'];
} }
$repeat_of = ""; $repeat_of = '';
$notice_info = $xpath->query('statusnet:notice_info', $entry); $notice_info = $xpath->query('statusnet:notice_info', $entry);
if ($notice_info && ($notice_info->length > 0)) { if ($notice_info && ($notice_info->length > 0)) {
foreach ($notice_info->item(0)->attributes as $attributes) { foreach ($notice_info->item(0)->attributes as $attributes) {
if ($attributes->name == "source") { if ($attributes->name == 'source') {
$item["app"] = strip_tags($attributes->textContent); $item['app'] = strip_tags($attributes->textContent);
} }
if ($attributes->name == "repeat_of") { if ($attributes->name == 'repeat_of') {
$repeat_of = $attributes->textContent; $repeat_of = $attributes->textContent;
} }
} }
} }
// Is it a repeated post? // Is it a repeated post?
if (($repeat_of != "") || ($item["verb"] == Activity::SHARE)) { if (($repeat_of != '') || ($item['verb'] == Activity::SHARE)) {
$link_data = self::processRepeatedItem($xpath, $entry, $item, $importer); $link_data = self::processRepeatedItem($xpath, $entry, $item, $importer);
if (!empty($link_data['add_body'])) { if (!empty($link_data['add_body'])) {
$add_body .= $link_data['add_body']; $add_body .= $link_data['add_body'];
} }
} }
$item["body"] .= $add_body; $item['body'] .= $add_body;
Tag::storeFromBody($item['uri-id'], $item['body']); Tag::storeFromBody($item['uri-id'], $item['body']);
// Mastodon Content Warning // Mastodon Content Warning
if (($item["verb"] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) { if (($item['verb'] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $entry)) {
$clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry); $clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $entry);
if (!empty($clear_text)) { if (!empty($clear_text)) {
$item['content-warning'] = HTML::toBBCode($clear_text); $item['content-warning'] = HTML::toBBCode($clear_text);
@ -690,21 +709,21 @@ class OStatus
self::fetchSelf($self, $item); self::fetchSelf($self, $item);
} }
if (!empty($item["conversation-href"])) { if (!empty($item['conversation-href'])) {
self::fetchConversation($item['conversation-href'], $item['conversation-uri']); self::fetchConversation($item['conversation-href'], $item['conversation-uri']);
} }
if (isset($item["thr-parent"])) { if (isset($item['thr-parent'])) {
if (!Post::exists(['uid' => $importer["uid"], 'uri' => $item['thr-parent']])) { if (!Post::exists(['uid' => $importer['uid'], 'uri' => $item['thr-parent']])) {
if ($related != '') { if ($related != '') {
self::fetchRelated($related, $item["thr-parent"], $importer); self::fetchRelated($related, $item['thr-parent'], $importer);
} }
} else { } else {
Logger::info('Reply with URI '.$item["uri"].' already existed for user '.$importer["uid"].'.'); Logger::info('Reply with URI ' . $item['uri'] . ' already existed for user ' . $importer['uid'] . '.');
} }
} else { } else {
$item["thr-parent"] = $item["uri"]; $item['thr-parent'] = $item['uri'];
$item["gravity"] = GRAVITY_PARENT; $item['gravity'] = GRAVITY_PARENT;
} }
if (($item['author-link'] != '') && !empty($item['protocol'])) { if (($item['author-link'] != '') && !empty($item['protocol'])) {
@ -722,7 +741,7 @@ class OStatus
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function fetchConversation($conversation, $conversation_uri) private static function fetchConversation(string $conversation, string $conversation_uri)
{ {
// Ensure that we only store a conversation once in a process // Ensure that we only store a conversation once in a process
if (isset(self::$conv_list[$conversation])) { if (isset(self::$conv_list[$conversation])) {
@ -786,7 +805,7 @@ class OStatus
* @return void * @return void
* @throws \Exception * @throws \Exception
*/ */
private static function storeConversation($xml, $conversation = '', $conversation_uri = '') private static function storeConversation(string $xml, string $conversation = '', string $conversation_uri = '')
{ {
$doc = new DOMDocument(); $doc = new DOMDocument();
@$doc->loadXML($xml); @$doc->loadXML($xml);
@ -814,7 +833,7 @@ class OStatus
$inreplyto = $xpath->query('thr:in-reply-to', $entry); $inreplyto = $xpath->query('thr:in-reply-to', $entry);
if (is_object($inreplyto->item(0))) { if (is_object($inreplyto->item(0))) {
foreach ($inreplyto->item(0)->attributes as $attributes) { foreach ($inreplyto->item(0)->attributes as $attributes) {
if ($attributes->name == "ref") { if ($attributes->name == 'ref') {
$conv_data['reply-to-uri'] = $attributes->textContent; $conv_data['reply-to-uri'] = $attributes->textContent;
} }
} }
@ -825,10 +844,10 @@ class OStatus
$conv = $xpath->query('ostatus:conversation', $entry); $conv = $xpath->query('ostatus:conversation', $entry);
if (is_object($conv->item(0))) { if (is_object($conv->item(0))) {
foreach ($conv->item(0)->attributes as $attributes) { foreach ($conv->item(0)->attributes as $attributes) {
if ($attributes->name == "ref") { if ($attributes->name == 'ref') {
$conv_data['conversation-uri'] = $attributes->textContent; $conv_data['conversation-uri'] = $attributes->textContent;
} }
if ($attributes->name == "href") { if ($attributes->name == 'href') {
$conv_data['conversation-href'] = $attributes->textContent; $conv_data['conversation-href'] = $attributes->textContent;
} }
} }
@ -865,7 +884,7 @@ class OStatus
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function fetchSelf($self, array &$item) private static function fetchSelf(string $self, array &$item)
{ {
$condition = ['item-uri' => $self, 'protocol' => [Conversation::PARCEL_DFRN, $condition = ['item-uri' => $self, 'protocol' => [Conversation::PARCEL_DFRN,
Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN, Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN,
@ -888,9 +907,9 @@ class OStatus
$doc->formatOutput = true; $doc->formatOutput = true;
$xml = $doc->saveXML(); $xml = $doc->saveXML();
$item["protocol"] = Conversation::PARCEL_SALMON; $item['protocol'] = Conversation::PARCEL_SALMON;
$item["source"] = $xml; $item['source'] = $xml;
$item["direction"] = Conversation::PULL; $item['direction'] = Conversation::PULL;
Logger::info('Conversation '.$item['uri'].' is now fetched.'); Logger::info('Conversation '.$item['uri'].' is now fetched.');
} }
@ -905,11 +924,18 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function fetchRelated($related, $related_uri, $importer) private static function fetchRelated(string $related, string $related_uri, array $importer)
{ {
$condition = ['item-uri' => $related_uri, 'protocol' => [Conversation::PARCEL_DFRN, $condition = [
Conversation::PARCEL_DIASPORA_DFRN, Conversation::PARCEL_LOCAL_DFRN, 'item-uri' => $related_uri,
Conversation::PARCEL_DIRECT, Conversation::PARCEL_SALMON]]; 'protocol' => [
Conversation::PARCEL_DFRN,
Conversation::PARCEL_DIASPORA_DFRN,
Conversation::PARCEL_LOCAL_DFRN,
Conversation::PARCEL_DIRECT,
Conversation::PARCEL_SALMON,
],
];
$conversation = DBA::selectFirst('conversation', ['source', 'protocol'], $condition); $conversation = DBA::selectFirst('conversation', ['source', 'protocol'], $condition);
if (DBA::isResult($conversation)) { if (DBA::isResult($conversation)) {
$stored = true; $stored = true;
@ -1002,7 +1028,7 @@ class OStatus
if ($xml != '') { if ($xml != '') {
self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL); self::process($xml, $importer, $contact, $hub, $stored, false, Conversation::PULL);
} else { } else {
Logger::info("XML couldn't be fetched for URI: ".$related_uri." - href: ".$related); Logger::info("XML couldn't be fetched for URI: " . $related_uri . " - href: " . $related);
} }
return; return;
} }
@ -1019,7 +1045,7 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function processRepeatedItem(DOMXPath $xpath, $entry, array &$item, array $importer) private static function processRepeatedItem(DOMXPath $xpath, $entry, array &$item, array $importer): array
{ {
$activityobject = $xpath->query('activity:object', $entry)->item(0); $activityobject = $xpath->query('activity:object', $entry)->item(0);
@ -1031,7 +1057,7 @@ class OStatus
$orig_uri = XML::getFirstNodeValue($xpath, 'atom:id/text()', $activityobject); $orig_uri = XML::getFirstNodeValue($xpath, 'atom:id/text()', $activityobject);
$links = $xpath->query("atom:link", $activityobject); $links = $xpath->query('atom:link', $activityobject);
if ($links) { if ($links) {
$link_data = self::processLinks($links, $item); $link_data = self::processLinks($links, $item);
} }
@ -1042,22 +1068,22 @@ class OStatus
$orig_author = self::fetchAuthor($xpath, $activityobject, $importer, $dummy, false); $orig_author = self::fetchAuthor($xpath, $activityobject, $importer, $dummy, false);
$item["author-name"] = $orig_author["author-name"]; $item['author-name'] = $orig_author['author-name'];
$item["author-link"] = $orig_author["author-link"]; $item['author-link'] = $orig_author['author-link'];
$item["author-id"] = $orig_author["author-id"]; $item['author-id'] = $orig_author['author-id'];
$item["body"] = HTML::toBBCode($orig_body); $item['body'] = HTML::toBBCode($orig_body);
$item["created"] = $orig_created; $item['created'] = $orig_created;
$item["edited"] = $orig_edited; $item['edited'] = $orig_edited;
$item["uri"] = $orig_uri; $item['uri'] = $orig_uri;
$item["verb"] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $activityobject); $item['verb'] = XML::getFirstNodeValue($xpath, 'activity:verb/text()', $activityobject);
$item["object-type"] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $activityobject); $item['object-type'] = XML::getFirstNodeValue($xpath, 'activity:object-type/text()', $activityobject);
// Mastodon Content Warning // Mastodon Content Warning
if (($item["verb"] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $activityobject)) { if (($item['verb'] == Activity::POST) && $xpath->evaluate('boolean(atom:summary)', $activityobject)) {
$clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $activityobject); $clear_text = XML::getFirstNodeValue($xpath, 'atom:summary/text()', $activityobject);
if (!empty($clear_text)) { if (!empty($clear_text)) {
$item['content-warning'] = HTML::toBBCode($clear_text); $item['content-warning'] = HTML::toBBCode($clear_text);
@ -1067,8 +1093,8 @@ class OStatus
$inreplyto = $xpath->query('thr:in-reply-to', $activityobject); $inreplyto = $xpath->query('thr:in-reply-to', $activityobject);
if (is_object($inreplyto->item(0))) { if (is_object($inreplyto->item(0))) {
foreach ($inreplyto->item(0)->attributes as $attributes) { foreach ($inreplyto->item(0)->attributes as $attributes) {
if ($attributes->name == "ref") { if ($attributes->name == 'ref') {
$item["thr-parent"] = $attributes->textContent; $item['thr-parent'] = $attributes->textContent;
} }
} }
} }
@ -1081,10 +1107,9 @@ class OStatus
* *
* @param object $links The xml data that contain links * @param object $links The xml data that contain links
* @param array $item The item array * @param array $item The item array
*
* @return array with data from the links * @return array with data from the links
*/ */
private static function processLinks($links, array &$item) private static function processLinks($links, array &$item): array
{ {
$link_data = ['add_body' => '', 'self' => '']; $link_data = ['add_body' => '', 'self' => ''];
@ -1093,24 +1118,26 @@ class OStatus
if (!empty($attribute['rel']) && !empty($attribute['href'])) { if (!empty($attribute['rel']) && !empty($attribute['href'])) {
switch ($attribute['rel']) { switch ($attribute['rel']) {
case "alternate": case 'alternate':
$item["plink"] = $attribute['href']; $item['plink'] = $attribute['href'];
if (($item["object-type"] == Activity\ObjectType::QUESTION) if (($item['object-type'] == Activity\ObjectType::QUESTION)
|| ($item["object-type"] == Activity\ObjectType::EVENT) || ($item['object-type'] == Activity\ObjectType::EVENT)
) { ) {
Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::UNKNOWN, Post\Media::insert(['uri-id' => $item['uri-id'], 'type' => Post\Media::UNKNOWN,
'url' => $attribute['href'], 'mimetype' => $attribute['type'] ?? null, 'url' => $attribute['href'], 'mimetype' => $attribute['type'] ?? null,
'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
} }
break; break;
case "ostatus:conversation":
case 'ostatus:conversation':
$link_data['conversation'] = $attribute['href']; $link_data['conversation'] = $attribute['href'];
$item['conversation-href'] = $link_data['conversation']; $item['conversation-href'] = $link_data['conversation'];
if (!isset($item['conversation-uri'])) { if (!isset($item['conversation-uri'])) {
$item['conversation-uri'] = $item['conversation-href']; $item['conversation-uri'] = $item['conversation-href'];
} }
break; break;
case "enclosure":
case 'enclosure':
$filetype = strtolower(substr($attribute['type'], 0, strpos($attribute['type'], '/'))); $filetype = strtolower(substr($attribute['type'], 0, strpos($attribute['type'], '/')));
if ($filetype == 'image') { if ($filetype == 'image') {
$link_data['add_body'] .= "\n[img]".$attribute['href'].'[/img]'; $link_data['add_body'] .= "\n[img]".$attribute['href'].'[/img]';
@ -1120,10 +1147,11 @@ class OStatus
'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
} }
break; break;
case "related":
if ($item["object-type"] != Activity\ObjectType::BOOKMARK) { case 'related':
if (!isset($item["thr-parent"])) { if ($item['object-type'] != Activity\ObjectType::BOOKMARK) {
$item["thr-parent"] = $attribute['href']; if (!isset($item['thr-parent'])) {
$item['thr-parent'] = $attribute['href'];
} }
$link_data['related'] = $attribute['href']; $link_data['related'] = $attribute['href'];
} else { } else {
@ -1132,12 +1160,16 @@ class OStatus
'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]); 'size' => $attribute['length'] ?? null, 'description' => $attribute['title'] ?? null]);
} }
break; break;
case "self":
if (empty($item["plink"])) { case 'self':
$item["plink"] = $attribute['href']; if (empty($item['plink'])) {
$item['plink'] = $attribute['href'];
} }
$link_data['self'] = $attribute['href']; $link_data['self'] = $attribute['href'];
break; break;
default:
Logger::warning('Unsupported rel=' . $attribute['rel'] . ',href=' . $attribute['href'] . ',object-type=' . $attribute['object-type']);
} }
} }
} }
@ -1148,31 +1180,31 @@ class OStatus
* Create an url out of an uri * Create an url out of an uri
* *
* @param string $href URI in the format "parameter1:parameter1:..." * @param string $href URI in the format "parameter1:parameter1:..."
*
* @return string URL in the format http(s)://.... * @return string URL in the format http(s)://....
*/ */
private static function convertHref($href) private static function convertHref(string $href): string
{ {
$elements = explode(":", $href); $elements = explode(':', $href);
if ((count($elements) <= 2) || ($elements[0] != "tag")) { if ((count($elements) <= 2) || ($elements[0] != 'tag')) {
return $href; return $href;
} }
$server = explode(",", $elements[1]); $server = explode(',', $elements[1]);
$conversation = explode("=", $elements[2]); $conversation = explode('=', $elements[2]);
if ((count($elements) == 4) && ($elements[2] == "post")) { if ((count($elements) == 4) && ($elements[2] == 'post')) {
return "http://".$server[0]."/notice/".$elements[3]; return 'http://' . $server[0] . '/notice/' . $elements[3];
} }
if ((count($conversation) != 2) || ($conversation[1] =="")) { if ((count($conversation) != 2) || ($conversation[1] == '')) {
return $href; return $href;
} }
if ($elements[3] == "objectType=thread") {
return "http://".$server[0]."/conversation/".$conversation[1]; if ($elements[3] == 'objectType=thread') {
return 'http://' . $server[0] . '/conversation/' . $conversation[1];
} else { } else {
return "http://".$server[0]."/notice/".$conversation[1]; return 'http://' . $server[0] . '/notice/' . $conversation[1];
} }
} }
@ -1180,35 +1212,35 @@ class OStatus
* Cleans the body of a post if it contains picture links * Cleans the body of a post if it contains picture links
* *
* @param string $body The body * @param string $body The body
* * @param integer $uriid URI id
* @return string The cleaned body * @return string The cleaned body
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function formatPicturePost($body, $uriid) public static function formatPicturePost(string $body, int $uriid): string
{ {
$siteinfo = BBCode::getAttachedData($body); $siteinfo = BBCode::getAttachedData($body);
if (($siteinfo["type"] == "photo") && (!empty($siteinfo["preview"]) || !empty($siteinfo["image"]))) { if (($siteinfo['type'] == 'photo') && (!empty($siteinfo['preview']) || !empty($siteinfo['image']))) {
if (isset($siteinfo["preview"])) { if (isset($siteinfo['preview'])) {
$preview = $siteinfo["preview"]; $preview = $siteinfo['preview'];
} else { } else {
$preview = $siteinfo["image"]; $preview = $siteinfo['image'];
} }
// Is it a remote picture? Then make a smaller preview here // Is it a remote picture? Then make a smaller preview here
$preview = Post\Link::getByLink($uriid, $preview, Proxy::SIZE_SMALL); $preview = Post\Link::getByLink($uriid, $preview, Proxy::SIZE_SMALL);
// Is it a local picture? Then make it smaller here // Is it a local picture? Then make it smaller here
$preview = str_replace(["-0.jpg", "-0.png"], ["-2.jpg", "-2.png"], $preview); $preview = str_replace(['-0.jpg', '-0.png'], ['-2.jpg', '-2.png'], $preview);
$preview = str_replace(["-1.jpg", "-1.png"], ["-2.jpg", "-2.png"], $preview); $preview = str_replace(['-1.jpg', '-1.png'], ['-2.jpg', '-2.png'], $preview);
if (isset($siteinfo["url"])) { if (isset($siteinfo['url'])) {
$url = $siteinfo["url"]; $url = $siteinfo['url'];
} else { } else {
$url = $siteinfo["image"]; $url = $siteinfo['image'];
} }
$body = trim($siteinfo["text"])." [url]".$url."[/url]\n[img]".$preview."[/img]"; $body = trim($siteinfo['text']) . " [url]" . $url . "[/url]\n[img]" . $preview . "[/img]";
} }
return $body; return $body;
@ -1221,54 +1253,63 @@ class OStatus
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param string $filter The related feed filter (activity, posts or comments) * @param string $filter The related feed filter (activity, posts or comments)
* *
* @return object header root element * @return DOMAttr Header root element
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function addHeader(DOMDocument $doc, array $owner, $filter) private static function addHeader(DOMDocument $doc, array $owner, string $filter): DOMAttr
{ {
$root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed'); $root = $doc->createElementNS(ActivityNamespace::ATOM1, 'feed');
$doc->appendChild($root); $doc->appendChild($root);
$root->setAttribute("xmlns:thr", ActivityNamespace::THREAD); $root->setAttribute('xmlns:thr', ActivityNamespace::THREAD);
$root->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); $root->setAttribute('xmlns:georss', ActivityNamespace::GEORSS);
$root->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); $root->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY);
$root->setAttribute("xmlns:media", ActivityNamespace::MEDIA); $root->setAttribute('xmlns:media', ActivityNamespace::MEDIA);
$root->setAttribute("xmlns:poco", ActivityNamespace::POCO); $root->setAttribute('xmlns:poco', ActivityNamespace::POCO);
$root->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); $root->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS);
$root->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); $root->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET);
$root->setAttribute("xmlns:mastodon", ActivityNamespace::MASTODON); $root->setAttribute('xmlns:mastodon', ActivityNamespace::MASTODON);
$title = ''; $title = '';
$selfUri = '/feed/' . $owner["nick"] . '/'; $selfUri = '/feed/' . $owner['nick'] . '/';
switch ($filter) { switch ($filter) {
case 'activity': case 'activity':
$title = DI::l10n()->t('%s\'s timeline', $owner['name']); $title = DI::l10n()->t('%s\'s timeline', $owner['name']);
$selfUri .= $filter; $selfUri .= $filter;
break; break;
case 'posts': case 'posts':
$title = DI::l10n()->t('%s\'s posts', $owner['name']); $title = DI::l10n()->t('%s\'s posts', $owner['name']);
break; break;
case 'comments': case 'comments':
$title = DI::l10n()->t('%s\'s comments', $owner['name']); $title = DI::l10n()->t('%s\'s comments', $owner['name']);
$selfUri .= $filter; $selfUri .= $filter;
break; break;
} }
$selfUri = "/dfrn_poll/" . $owner["nick"]; $selfUri = '/dfrn_poll/' . $owner['nick'];
$attributes = ["uri" => "https://friendi.ca", "version" => FRIENDICA_VERSION . "-" . DB_UPDATE_VERSION]; $attributes = [
XML::addElement($doc, $root, "generator", FRIENDICA_PLATFORM, $attributes); 'uri' => 'https://friendi.ca',
XML::addElement($doc, $root, "id", DI::baseUrl() . "/profile/" . $owner["nick"]); 'version' => FRIENDICA_VERSION . '-' . DB_UPDATE_VERSION,
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, 'generator', FRIENDICA_PLATFORM, $attributes);
XML::addElement($doc, $root, "logo", User::getAvatarUrl($owner, Proxy::SIZE_SMALL)); XML::addElement($doc, $root, 'id', DI::baseUrl() . '/profile/' . $owner['nick']);
XML::addElement($doc, $root, "updated", DateTimeFormat::utcNow(DateTimeFormat::ATOM)); 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, true); $author = self::addAuthor($doc, $owner, true);
$root->appendChild($author); $root->appendChild($author);
$attributes = ["href" => $owner["url"], "rel" => "alternate", "type" => "text/html"]; $attributes = [
XML::addElement($doc, $root, "link", "", $attributes); 'href' => $owner['url'],
'rel' => 'alternate',
'type' => 'text/html',
];
XML::addElement($doc, $root, 'link', '', $attributes);
/// @TODO We have to find out what this is /// @TODO We have to find out what this is
/// $attributes = array("href" => DI::baseUrl()."/sup", /// $attributes = array("href" => DI::baseUrl()."/sup",
@ -1276,25 +1317,30 @@ class OStatus
/// "type" => "application/json"); /// "type" => "application/json");
/// XML::addElement($doc, $root, "link", "", $attributes); /// XML::addElement($doc, $root, "link", "", $attributes);
self::hublinks($doc, $root, $owner["nick"]); self::addHubLink($doc, $root, $owner['nick']);
$attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "salmon"]; $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'salmon'];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
$attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-replies"]; $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'http://salmon-protocol.org/ns/salmon-replies'];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
$attributes = ["href" => DI::baseUrl() . "/salmon/" . $owner["nick"], "rel" => "http://salmon-protocol.org/ns/salmon-mention"]; $attributes = ['href' => DI::baseUrl() . '/salmon/' . $owner['nick'], 'rel' => 'http://salmon-protocol.org/ns/salmon-mention'];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
$attributes = ["href" => DI::baseUrl() . $selfUri, "rel" => "self", "type" => "application/atom+xml"]; $attributes = ['href' => DI::baseUrl() . $selfUri, 'rel' => 'self', 'type' => 'application/atom+xml'];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
$condition = ['uid' => $owner['uid'], 'self' => false, 'pending' => false, $members = DBA::count('contact', [
'archive' => false, 'hidden' => false, 'blocked' => false]; 'uid' => $owner['uid'],
$members = DBA::count('contact', $condition); 'self' => false,
XML::addElement($doc, $root, "statusnet:group_info", "", ["member_count" => $members]); 'pending' => false,
'archive' => false,
'hidden' => false,
'blocked' => false,
]);
XML::addElement($doc, $root, 'statusnet:group_info', '', ['member_count' => $members]);
} }
return $root; return $root;
@ -1304,65 +1350,70 @@ class OStatus
* Add the link to the push hubs to the XML document * Add the link to the push hubs to the XML document
* *
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param object $root XML root element where the hub links are added * @param addHubLink $root XML root element where the hub links are added
* @param object $nick nick * @param string $nick Nickname
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function hublinks(DOMDocument $doc, $root, $nick) public static function addHubLink(DOMDocument $doc, DOMAttr $root, string $nick)
{ {
$h = DI::baseUrl() . '/pubsubhubbub/'.$nick; $h = DI::baseUrl() . '/pubsubhubbub/' . $nick;
XML::addElement($doc, $root, "link", "", ["href" => $h, "rel" => "hub"]); XML::addElement($doc, $root, 'link', '', ['href' => $h, 'rel' => 'hub']);
} }
/** /**
* Adds attachment data to the XML document * Adds attachment data to the XML document
* *
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param object $root XML root element where the hub links are added * @param DOMAttr $root XML root element where the hub links are added
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function getAttachment(DOMDocument $doc, $root, $item) public static function getAttachment(DOMDocument $doc, DOMAttr $root, array $item)
{ {
$siteinfo = BBCode::getAttachedData($item["body"]); $siteinfo = BBCode::getAttachedData($item['body']);
switch ($siteinfo["type"]) { switch ($siteinfo['type']) {
case 'photo': case 'photo':
if (!empty($siteinfo["image"])) { if (!empty($siteinfo['image'])) {
$imgdata = Images::getInfoFromURLCached($siteinfo["image"]); $imgdata = Images::getInfoFromURLCached($siteinfo['image']);
if ($imgdata) { if ($imgdata) {
$attributes = ["rel" => "enclosure", $attributes = [
"href" => $siteinfo["image"], 'rel' => 'enclosure',
"type" => $imgdata["mime"], 'href' => $siteinfo['image'],
"length" => intval($imgdata["size"])]; 'type' => $imgdata['mime'],
XML::addElement($doc, $root, "link", "", $attributes); 'length' => intval($imgdata['size']),
];
XML::addElement($doc, $root, 'link', '', $attributes);
} }
} }
break; break;
case 'video': case 'video':
$attributes = ["rel" => "enclosure", $attributes = [
"href" => $siteinfo["url"], 'rel' => 'enclosure',
"type" => "text/html; charset=UTF-8", 'href' => $siteinfo['url'],
"length" => "0", 'type' => 'text/html; charset=UTF-8',
"title" => ($siteinfo["title"] ?? '') ?: $siteinfo["url"], 'length' => '0',
'title' => ($siteinfo['title'] ?? '') ?: $siteinfo['url'],
]; ];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
break; break;
default: default:
break; break;
} }
if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo["type"] != "photo") && isset($siteinfo["image"])) { if (!DI::config()->get('system', 'ostatus_not_attach_preview') && ($siteinfo['type'] != 'photo') && isset($siteinfo['image'])) {
$imgdata = Images::getInfoFromURLCached($siteinfo["image"]); $imgdata = Images::getInfoFromURLCached($siteinfo['image']);
if ($imgdata) { if ($imgdata) {
$attributes = ["rel" => "enclosure", $attributes = [
"href" => $siteinfo["image"], 'rel' => 'enclosure',
"type" => $imgdata["mime"], 'href' => $siteinfo['image'],
"length" => intval($imgdata["size"])]; 'type' => $imgdata['mime'],
'length' => intval($imgdata['size']),
];
XML::addElement($doc, $root, "link", "", $attributes); XML::addElement($doc, $root, 'link', '', $attributes);
} }
} }
@ -1388,75 +1439,80 @@ class OStatus
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param bool $show_profile Whether to show profile * @param bool $show_profile Whether to show profile
* * @return DOMElement Author element
* @return \DOMElement author element
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function addAuthor(DOMDocument $doc, array $owner, $show_profile = true) private static function addAuthor(DOMDocument $doc, array $owner, bool $show_profile = true): DOMElement
{ {
$profile = DBA::selectFirst('profile', ['homepage', 'publish'], ['uid' => $owner['uid']]); $profile = DBA::selectFirst('profile', ['homepage', 'publish'], ['uid' => $owner['uid']]);
$author = $doc->createElement("author"); $author = $doc->createElement('author');
XML::addElement($doc, $author, "id", $owner["url"]); XML::addElement($doc, $author, 'id', $owner['url']);
if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
XML::addElement($doc, $author, "activity:object-type", Activity\ObjectType::GROUP); XML::addElement($doc, $author, 'activity:object-type', Activity\ObjectType::GROUP);
} else { } else {
XML::addElement($doc, $author, "activity:object-type", Activity\ObjectType::PERSON); XML::addElement($doc, $author, 'activity:object-type', Activity\ObjectType::PERSON);
} }
XML::addElement($doc, $author, "uri", $owner["url"]); XML::addElement($doc, $author, 'uri', $owner['url']);
XML::addElement($doc, $author, "name", $owner["nick"]); XML::addElement($doc, $author, 'name', $owner['nick']);
XML::addElement($doc, $author, "email", $owner["addr"]); XML::addElement($doc, $author, 'email', $owner['addr']);
if ($show_profile) { if ($show_profile) {
XML::addElement($doc, $author, "summary", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS)); XML::addElement($doc, $author, 'summary', BBCode::convertForUriId($owner['uri-id'], $owner['about'], BBCode::OSTATUS));
} }
$attributes = ["rel" => "alternate", "type" => "text/html", "href" => $owner["url"]];
XML::addElement($doc, $author, "link", "", $attributes);
$attributes = [ $attributes = [
"rel" => "avatar", 'rel' => 'alternate',
"type" => "image/jpeg", // To-Do? 'type' => 'text/html',
"media:width" => Proxy::PIXEL_SMALL, 'href' => $owner['url'],
"media:height" => Proxy::PIXEL_SMALL, ];
"href" => User::getAvatarUrl($owner, Proxy::SIZE_SMALL)]; XML::addElement($doc, $author, 'link', '', $attributes);
XML::addElement($doc, $author, "link", "", $attributes);
if (isset($owner["thumb"])) { $attributes = [
'rel' => 'avatar',
'type' => 'image/jpeg', // To-Do?
'media:width' => Proxy::PIXEL_SMALL,
'media:height' => Proxy::PIXEL_SMALL,
'href' => User::getAvatarUrl($owner, Proxy::SIZE_SMALL),
];
XML::addElement($doc, $author, 'link', '', $attributes);
if (isset($owner['thumb'])) {
$attributes = [ $attributes = [
"rel" => "avatar", 'rel' => 'avatar',
"type" => "image/jpeg", // To-Do? 'type' => 'image/jpeg', // To-Do?
"media:width" => Proxy::PIXEL_THUMB, 'media:width' => Proxy::PIXEL_THUMB,
"media:height" => Proxy::PIXEL_THUMB, 'media:height' => Proxy::PIXEL_THUMB,
"href" => User::getAvatarUrl($owner, Proxy::SIZE_THUMB)]; 'href' => User::getAvatarUrl($owner, Proxy::SIZE_THUMB),
XML::addElement($doc, $author, "link", "", $attributes); ];
XML::addElement($doc, $author, 'link', '', $attributes);
} }
XML::addElement($doc, $author, "poco:preferredUsername", $owner["nick"]); XML::addElement($doc, $author, 'poco:preferredUsername', $owner['nick']);
XML::addElement($doc, $author, "poco:displayName", $owner["name"]); XML::addElement($doc, $author, 'poco:displayName', $owner['name']);
if ($show_profile) { if ($show_profile) {
XML::addElement($doc, $author, "poco:note", BBCode::convertForUriId($owner['uri-id'], $owner["about"], BBCode::OSTATUS)); XML::addElement($doc, $author, 'poco:note', BBCode::convertForUriId($owner['uri-id'], $owner['about'], BBCode::OSTATUS));
if (trim($owner["location"]) != "") { if (trim($owner['location']) != '') {
$element = $doc->createElement("poco:address"); $element = $doc->createElement('poco:address');
XML::addElement($doc, $element, "poco:formatted", $owner["location"]); XML::addElement($doc, $element, 'poco:formatted', $owner['location']);
$author->appendChild($element); $author->appendChild($element);
} }
} }
if (DBA::isResult($profile) && !$show_profile) { if (DBA::isResult($profile) && !$show_profile) {
if (trim($profile["homepage"]) != "") { if (trim($profile['homepage']) != '') {
$urls = $doc->createElement("poco:urls"); $urls = $doc->createElement('poco:urls');
XML::addElement($doc, $urls, "poco:type", "homepage"); XML::addElement($doc, $urls, 'poco:type', 'homepage');
XML::addElement($doc, $urls, "poco:value", $profile["homepage"]); XML::addElement($doc, $urls, 'poco:value', $profile['homepage']);
XML::addElement($doc, $urls, "poco:primary", "true"); XML::addElement($doc, $urls, 'poco:primary', 'true');
$author->appendChild($urls); $author->appendChild($urls);
} }
XML::addElement($doc, $author, "followers", "", ["url" => DI::baseUrl() . "/profile/" . $owner["nick"] . "/contacts/followers"]); XML::addElement($doc, $author, 'followers', '', ['url' => DI::baseUrl() . '/profile/' . $owner['nick'] . '/contacts/followers']);
XML::addElement($doc, $author, "statusnet:profile_info", "", ["local_id" => $owner["uid"]]); XML::addElement($doc, $author, 'statusnet:profile_info', '', ['local_id' => $owner['uid']]);
if ($profile["publish"]) { if ($profile['publish']) {
XML::addElement($doc, $author, "mastodon:scope", "public"); XML::addElement($doc, $author, 'mastodon:scope', 'public');
} }
} }
@ -1473,10 +1529,9 @@ class OStatus
* Returns the given activity if present - otherwise returns the "post" activity * Returns the given activity if present - otherwise returns the "post" activity
* *
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
*
* @return string activity * @return string activity
*/ */
public static function constructVerb(array $item) public static function constructVerb(array $item): string
{ {
if (!empty($item['verb'])) { if (!empty($item['verb'])) {
return $item['verb']; return $item['verb'];
@ -1489,10 +1544,9 @@ class OStatus
* Returns the given object type if present - otherwise returns the "note" object type * Returns the given object type if present - otherwise returns the "note" object type
* *
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
*
* @return string Object type * @return string Object type
*/ */
private static function constructObjecttype(array $item) private static function constructObjecttype(array $item): string
{ {
if (!empty($item['object-type']) && in_array($item['object-type'], [Activity\ObjectType::NOTE, Activity\ObjectType::COMMENT])) { if (!empty($item['object-type']) && in_array($item['object-type'], [Activity\ObjectType::NOTE, Activity\ObjectType::COMMENT])) {
return $item['object-type']; return $item['object-type'];
@ -1509,15 +1563,15 @@ class OStatus
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param bool $toplevel optional default false * @param bool $toplevel optional default false
* *
* @return \DOMElement Entry element * @return DOMElement Entry element
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function entry(DOMDocument $doc, array $item, array $owner, $toplevel = false) private static function entry(DOMDocument $doc, array $item, array $owner, bool $toplevel = false): DOMElement
{ {
if ($item["verb"] == Activity::LIKE) { if ($item['verb'] == Activity::LIKE) {
return self::likeEntry($doc, $item, $owner, $toplevel); return self::likeEntry($doc, $item, $owner, $toplevel);
} elseif (in_array($item["verb"], [Activity::FOLLOW, Activity::O_UNFOLLOW])) { } elseif (in_array($item['verb'], [Activity::FOLLOW, Activity::O_UNFOLLOW])) {
return self::followEntry($doc, $item, $owner, $toplevel); return self::followEntry($doc, $item, $owner, $toplevel);
} else { } else {
return self::noteEntry($doc, $item, $owner, $toplevel); return self::noteEntry($doc, $item, $owner, $toplevel);
@ -1531,29 +1585,28 @@ class OStatus
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
* * @return DOMElement Entry element with "like"
* @return \DOMElement Entry element with "like"
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function likeEntry(DOMDocument $doc, array $item, array $owner, $toplevel) private static function likeEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement
{ {
if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
Logger::info("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting."); Logger::info("OStatus entry is from author " . $owner['url'] . " - not from " . $item['author-link'] . ". Quitting.");
} }
$entry = self::entryHeader($doc, $owner, $item, $toplevel); $entry = self::entryHeader($doc, $owner, $item, $toplevel);
$verb = ActivityNamespace::ACTIVITY_SCHEMA . "favorite"; $verb = ActivityNamespace::ACTIVITY_SCHEMA . 'favorite';
self::entryContent($doc, $entry, $item, $owner, "Favorite", $verb, false); self::entryContent($doc, $entry, $item, $owner, 'Favorite', $verb, false);
$parent = Post::selectFirst([], ['uri' => $item["thr-parent"], 'uid' => $item["uid"]]); $parent = Post::selectFirst([], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]);
if (DBA::isResult($parent)) { if (DBA::isResult($parent)) {
$as_object = $doc->createElement("activity:object"); $as_object = $doc->createElement('activity:object');
XML::addElement($doc, $as_object, "activity:object-type", self::constructObjecttype($parent)); XML::addElement($doc, $as_object, 'activity:object-type', self::constructObjecttype($parent));
self::entryContent($doc, $as_object, $parent, $owner, "New entry"); self::entryContent($doc, $as_object, $parent, $owner, 'New entry');
$entry->appendChild($as_object); $entry->appendChild($as_object);
} }
@ -1569,39 +1622,42 @@ class OStatus
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param array $contact Contact data of the target * @param array $contact Contact data of the target
* * @return DOMElement author element
* @return object author element
*/ */
private static function addPersonObject(DOMDocument $doc, array $owner, array $contact) private static function addPersonObject(DOMDocument $doc, array $owner, array $contact): DOMElement
{ {
$object = $doc->createElement("activity:object"); $object = $doc->createElement('activity:object');
XML::addElement($doc, $object, "activity:object-type", Activity\ObjectType::PERSON); XML::addElement($doc, $object, 'activity:object-type', Activity\ObjectType::PERSON);
if ($contact['network'] == Protocol::PHANTOM) { if ($contact['network'] == Protocol::PHANTOM) {
XML::addElement($doc, $object, "id", $contact['url']); XML::addElement($doc, $object, 'id', $contact['url']);
return $object; return $object;
} }
XML::addElement($doc, $object, "id", $contact["alias"]); XML::addElement($doc, $object, 'id', $contact['alias']);
XML::addElement($doc, $object, "title", $contact["nick"]); XML::addElement($doc, $object, 'title', $contact['nick']);
$attributes = ["rel" => "alternate", "type" => "text/html", "href" => $contact["url"]]; XML::addElement($doc, $object, 'link', '', [
XML::addElement($doc, $object, "link", "", $attributes); 'rel' => 'alternate',
'type' => 'text/html',
'href' => $contact['url'],
]);
$attributes = [ $attributes = [
"rel" => "avatar", 'rel' => 'avatar',
"type" => "image/jpeg", // To-Do? 'type' => 'image/jpeg', // To-Do?
"media:width" => 300, 'media:width' => 300,
"media:height" => 300, 'media:height' => 300,
"href" => $contact["photo"]]; 'href' => $contact['photo'],
XML::addElement($doc, $object, "link", "", $attributes); ];
XML::addElement($doc, $object, 'link', '', $attributes);
XML::addElement($doc, $object, "poco:preferredUsername", $contact["nick"]); XML::addElement($doc, $object, 'poco:preferredUsername', $contact['nick']);
XML::addElement($doc, $object, "poco:displayName", $contact["name"]); XML::addElement($doc, $object, 'poco:displayName', $contact['name']);
if (trim($contact["location"]) != "") { if (trim($contact['location']) != '') {
$element = $doc->createElement("poco:address"); $element = $doc->createElement('poco:address');
XML::addElement($doc, $element, "poco:formatted", $contact["location"]); XML::addElement($doc, $element, 'poco:formatted', $contact['location']);
$object->appendChild($element); $object->appendChild($element);
} }
@ -1615,16 +1671,15 @@ class OStatus
* @param array $item Data of the follow/unfollow message * @param array $item Data of the follow/unfollow message
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? * @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 \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function followEntry(DOMDocument $doc, array $item, array $owner, $toplevel) private static function followEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement
{ {
$item["id"] = $item['parent'] = 0; $item['id'] = $item['parent'] = 0;
$item["created"] = $item["edited"] = date("c"); $item['created'] = $item['edited'] = date('c');
$item["private"] = Item::PRIVATE; $item['private'] = Item::PRIVATE;
$contact = Contact::getByURL($item['follow']); $contact = Contact::getByURL($item['follow']);
$item['follow'] = $contact['url']; $item['follow'] = $contact['url'];
@ -1635,7 +1690,7 @@ class OStatus
$contact['alias'] = $contact['url']; $contact['alias'] = $contact['url'];
} }
$condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($contact["url"])]; $condition = ['uid' => $owner['uid'], 'nurl' => Strings::normaliseLink($contact['url'])];
$user_contact = DBA::selectFirst('contact', ['id'], $condition); $user_contact = DBA::selectFirst('contact', ['id'], $condition);
if (DBA::isResult($user_contact)) { if (DBA::isResult($user_contact)) {
@ -1647,19 +1702,19 @@ class OStatus
if ($item['verb'] == Activity::FOLLOW) { if ($item['verb'] == Activity::FOLLOW) {
$message = DI::l10n()->t('%s is now following %s.'); $message = DI::l10n()->t('%s is now following %s.');
$title = DI::l10n()->t('following'); $title = DI::l10n()->t('following');
$action = "subscription"; $action = 'subscription';
} else { } else {
$message = DI::l10n()->t('%s stopped following %s.'); $message = DI::l10n()->t('%s stopped following %s.');
$title = DI::l10n()->t('stopped following'); $title = DI::l10n()->t('stopped following');
$action = "unfollow"; $action = 'unfollow';
} }
$item["uri"] = $item['parent-uri'] = $item['thr-parent'] $item['uri'] = $item['parent-uri'] = $item['thr-parent']
= 'tag:' . DI::baseUrl()->getHostname(). = 'tag:' . DI::baseUrl()->getHostname().
','.date('Y-m-d').':'.$action.':'.$owner['uid']. ','.date('Y-m-d').':'.$action.':'.$owner['uid'].
':person:'.$connect_id.':'.$item['created']; ':person:'.$connect_id.':'.$item['created'];
$item["body"] = sprintf($message, $owner["nick"], $contact["nick"]); $item['body'] = sprintf($message, $owner['nick'], $contact['nick']);
$entry = self::entryHeader($doc, $owner, $item, $toplevel); $entry = self::entryHeader($doc, $owner, $item, $toplevel);
@ -1680,30 +1735,29 @@ class OStatus
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? * @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 \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private static function noteEntry(DOMDocument $doc, array $item, array $owner, $toplevel) private static function noteEntry(DOMDocument $doc, array $item, array $owner, bool $toplevel): DOMElement
{ {
if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item["author-link"]) != Strings::normaliseLink($owner["url"]))) { if (($item['gravity'] != GRAVITY_PARENT) && (Strings::normaliseLink($item['author-link']) != Strings::normaliseLink($owner['url']))) {
Logger::info("OStatus entry is from author ".$owner["url"]." - not from ".$item["author-link"].". Quitting."); Logger::info("OStatus entry is from author " . $owner['url'] . " - not from " . $item['author-link'] . ". Quitting.");
} }
if (!$toplevel) { if (!$toplevel) {
if (!empty($item['title'])) { if (!empty($item['title'])) {
$title = BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::OSTATUS); $title = BBCode::convertForUriId($item['uri-id'], $item['title'], BBCode::OSTATUS);
} else { } else {
$title = sprintf("New note by %s", $owner["nick"]); $title = sprintf("New note by %s", $owner['nick']);
} }
} else { } else {
$title = sprintf("New comment by %s", $owner["nick"]); $title = sprintf("New comment by %s", $owner['nick']);
} }
$entry = self::entryHeader($doc, $owner, $item, $toplevel); $entry = self::entryHeader($doc, $owner, $item, $toplevel);
XML::addElement($doc, $entry, "activity:object-type", Activity\ObjectType::NOTE); XML::addElement($doc, $entry, 'activity:object-type', Activity\ObjectType::NOTE);
self::entryContent($doc, $entry, $item, $owner, $title, '', true); self::entryContent($doc, $entry, $item, $owner, $title, '', true);
@ -1719,15 +1773,14 @@ class OStatus
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param array $item * @param array $item
* @param bool $toplevel Is it for en entry element (false) or a feed entry (true)? * @param bool $toplevel Is it for en entry element (false) or a feed entry (true)?
* * @return DOMElement The entry element where the elements are added
* @return \DOMElement The entry element where the elements are added
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function entryHeader(DOMDocument $doc, array $owner, array $item, $toplevel) public static function entryHeader(DOMDocument $doc, array $owner, array $item, bool $toplevel): DOMElement
{ {
if (!$toplevel) { if (!$toplevel) {
$entry = $doc->createElement("entry"); $entry = $doc->createElement('entry');
if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
$contact = Contact::getByURL($item['author-link']) ?: $owner; $contact = Contact::getByURL($item['author-link']) ?: $owner;
@ -1736,16 +1789,16 @@ class OStatus
$entry->appendChild($author); $entry->appendChild($author);
} }
} else { } else {
$entry = $doc->createElementNS(ActivityNamespace::ATOM1, "entry"); $entry = $doc->createElementNS(ActivityNamespace::ATOM1, 'entry');
$entry->setAttribute("xmlns:thr", ActivityNamespace::THREAD); $entry->setAttribute('xmlns:thr', ActivityNamespace::THREAD);
$entry->setAttribute("xmlns:georss", ActivityNamespace::GEORSS); $entry->setAttribute('xmlns:georss', ActivityNamespace::GEORSS);
$entry->setAttribute("xmlns:activity", ActivityNamespace::ACTIVITY); $entry->setAttribute('xmlns:activity', ActivityNamespace::ACTIVITY);
$entry->setAttribute("xmlns:media", ActivityNamespace::MEDIA); $entry->setAttribute('xmlns:media', ActivityNamespace::MEDIA);
$entry->setAttribute("xmlns:poco", ActivityNamespace::POCO); $entry->setAttribute('xmlns:poco', ActivityNamespace::POCO);
$entry->setAttribute("xmlns:ostatus", ActivityNamespace::OSTATUS); $entry->setAttribute('xmlns:ostatus', ActivityNamespace::OSTATUS);
$entry->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET); $entry->setAttribute('xmlns:statusnet', ActivityNamespace::STATUSNET);
$entry->setAttribute("xmlns:mastodon", ActivityNamespace::MASTODON); $entry->setAttribute('xmlns:mastodon', ActivityNamespace::MASTODON);
$author = self::addAuthor($doc, $owner); $author = self::addAuthor($doc, $owner);
$entry->appendChild($author); $entry->appendChild($author);
@ -1758,7 +1811,7 @@ class OStatus
* Adds elements to the XML document * Adds elements to the XML document
* *
* @param DOMDocument $doc XML document * @param DOMDocument $doc XML document
* @param \DOMElement $entry Entry element where the content is added * @param DOMElement $entry Entry element where the content is added
* @param array $item Data of the item that is to be posted * @param array $item Data of the item that is to be posted
* @param array $owner Contact data of the poster * @param array $owner Contact data of the poster
* @param string $title Title for the post * @param string $title Title for the post
@ -1767,38 +1820,40 @@ class OStatus
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function entryContent(DOMDocument $doc, \DOMElement $entry, array $item, array $owner, $title, $verb = "", $complete = true) private static function entryContent(DOMDocument $doc, DOMElement $entry, array $item, array $owner, string $title, string $verb = '', bool $complete = true)
{ {
if ($verb == "") { if ($verb == '') {
$verb = self::constructVerb($item); $verb = self::constructVerb($item);
} }
XML::addElement($doc, $entry, "id", $item["uri"]); XML::addElement($doc, $entry, 'id', $item['uri']);
XML::addElement($doc, $entry, "title", html_entity_decode($title, ENT_QUOTES, 'UTF-8')); XML::addElement($doc, $entry, 'title', html_entity_decode($title, ENT_QUOTES, 'UTF-8'));
$body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']); $body = Post\Media::addAttachmentsToBody($item['uri-id'], $item['body']);
$body = self::formatPicturePost($body, $item['uri-id']); $body = self::formatPicturePost($body, $item['uri-id']);
if (!empty($item['title'])) { if (!empty($item['title'])) {
$body = "[b]".$item['title']."[/b]\n\n".$body; $body = "[b]" . $item['title'] . "[/b]\n\n" . $body;
} }
$body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::OSTATUS); $body = BBCode::convertForUriId($item['uri-id'], $body, BBCode::OSTATUS);
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", XML::addElement($doc, $entry, 'link', '', [
"href" => DI::baseUrl()."/display/".$item["guid"]] 'rel' => 'alternate',
); 'type' => 'text/html',
'href' => DI::baseUrl() . '/display/' . $item['guid'],
]);
if ($complete && ($item["id"] > 0)) { if ($complete && ($item['id'] > 0)) {
XML::addElement($doc, $entry, "status_net", "", ["notice_id" => $item["id"]]); XML::addElement($doc, $entry, 'status_net', '', ['notice_id' => $item['id']]);
} }
XML::addElement($doc, $entry, "activity:verb", $verb); XML::addElement($doc, $entry, 'activity:verb', $verb);
XML::addElement($doc, $entry, "published", DateTimeFormat::utc($item["created"]."+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)); XML::addElement($doc, $entry, 'updated', DateTimeFormat::utc($item['edited'] . '+00:00', DateTimeFormat::ATOM));
} }
/** /**
@ -1812,7 +1867,7 @@ class OStatus
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
private static function entryFooter(DOMDocument $doc, $entry, array $item, array $owner, $complete = true) private static function entryFooter(DOMDocument $doc, $entry, array $item, array $owner, bool $complete = true)
{ {
$mentioned = []; $mentioned = [];
@ -1861,14 +1916,15 @@ class OStatus
} }
} }
XML::addElement($doc, $entry, "link", "", ["rel" => "ostatus:conversation", "href" => $conversation_href]); XML::addElement($doc, $entry, 'link', '', ['rel' => 'ostatus:conversation', 'href' => $conversation_href]);
$attributes = [ $attributes = [
"href" => $conversation_href, 'href' => $conversation_href,
"local_id" => $item['parent'], 'local_id' => $item['parent'],
"ref" => $conversation_uri]; 'ref' => $conversation_uri,
];
XML::addElement($doc, $entry, "ostatus:conversation", $conversation_uri, $attributes); XML::addElement($doc, $entry, 'ostatus:conversation', $conversation_uri, $attributes);
} }
// uri-id isn't present for follow entry pseudo-items // uri-id isn't present for follow entry pseudo-items
@ -1880,72 +1936,70 @@ class OStatus
// Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS) // Make sure that mentions are accepted (GNU Social has problems with mixing HTTP and HTTPS)
$newmentions = []; $newmentions = [];
foreach ($mentioned as $mention) { foreach ($mentioned as $mention) {
$newmentions[str_replace("http://", "https://", $mention)] = str_replace("http://", "https://", $mention); $newmentions[str_replace('http://', 'https://', $mention)] = str_replace('http://', 'https://', $mention);
$newmentions[str_replace("https://", "http://", $mention)] = str_replace("https://", "http://", $mention); $newmentions[str_replace('https://', 'http://', $mention)] = str_replace('https://', 'http://', $mention);
} }
$mentioned = $newmentions; $mentioned = $newmentions;
foreach ($mentioned as $mention) { foreach ($mentioned as $mention) {
$contact = Contact::getByURL($mention, false, ['contact-type']); $contact = Contact::getByURL($mention, false, ['contact-type']);
if (!empty($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) { if (!empty($contact) && ($contact['contact-type'] == Contact::TYPE_COMMUNITY)) {
XML::addElement($doc, $entry, "link", "", XML::addElement($doc, $entry, 'link', '', [
[ 'rel' => 'mentioned',
"rel" => "mentioned", 'ostatus:object-type' => Activity\ObjectType::GROUP,
"ostatus:object-type" => Activity\ObjectType::GROUP, 'href' => $mention,
"href" => $mention] ]);
);
} else { } else {
XML::addElement($doc, $entry, "link", "", XML::addElement($doc, $entry, 'link', '', [
[ 'rel' => 'mentioned',
"rel" => "mentioned", 'ostatus:object-type' => Activity\ObjectType::PERSON,
"ostatus:object-type" => Activity\ObjectType::PERSON, 'href' => $mention,
"href" => $mention] ]);
);
} }
} }
if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) { if ($owner['contact-type'] == Contact::TYPE_COMMUNITY) {
XML::addElement($doc, $entry, "link", "", [ XML::addElement($doc, $entry, 'link', '', [
"rel" => "mentioned", 'rel' => 'mentioned',
"ostatus:object-type" => "http://activitystrea.ms/schema/1.0/group", 'ostatus:object-type' => 'http://activitystrea.ms/schema/1.0/group',
"href" => $owner['url'] 'href' => $owner['url']
]); ]);
} }
if ($item['private'] != Item::PRIVATE) { if ($item['private'] != Item::PRIVATE) {
XML::addElement($doc, $entry, "link", "", ["rel" => "ostatus:attention", XML::addElement($doc, $entry, 'link', '', ['rel' => 'ostatus:attention',
"href" => "http://activityschema.org/collection/public"]); 'href' => 'http://activityschema.org/collection/public']);
XML::addElement($doc, $entry, "link", "", ["rel" => "mentioned", XML::addElement($doc, $entry, 'link', '', ['rel' => 'mentioned',
"ostatus:object-type" => "http://activitystrea.ms/schema/1.0/collection", 'ostatus:object-type' => 'http://activitystrea.ms/schema/1.0/collection',
"href" => "http://activityschema.org/collection/public"]); 'href' => 'http://activityschema.org/collection/public']);
XML::addElement($doc, $entry, "mastodon:scope", "public"); XML::addElement($doc, $entry, 'mastodon:scope', 'public');
} }
foreach ($tags as $tag) { foreach ($tags as $tag) {
if ($tag['type'] == Tag::HASHTAG) { if ($tag['type'] == Tag::HASHTAG) {
XML::addElement($doc, $entry, "category", "", ["term" => $tag['name']]); XML::addElement($doc, $entry, 'category', '', ['term' => $tag['name']]);
} }
} }
self::getAttachment($doc, $entry, $item); self::getAttachment($doc, $entry, $item);
if ($complete && ($item["id"] > 0)) { if ($complete && ($item['id'] > 0)) {
$app = $item["app"]; $app = $item['app'];
if ($app == "") { if ($app == '') {
$app = "web"; $app = 'web';
} }
$attributes = ["local_id" => $item["id"], "source" => $app]; $attributes = ['local_id' => $item['id'], 'source' => $app];
if (isset($parent["id"])) { if (isset($parent['id'])) {
$attributes["repeat_of"] = $parent["id"]; $attributes['repeat_of'] = $parent['id'];
} }
if ($item["coord"] != "") { if ($item['coord'] != '') {
XML::addElement($doc, $entry, "georss:point", $item["coord"]); XML::addElement($doc, $entry, 'georss:point', $item['coord']);
} }
XML::addElement($doc, $entry, "statusnet:notice_info", "", $attributes); XML::addElement($doc, $entry, 'statusnet:notice_info', '', $attributes);
} }
} }
@ -1965,21 +2019,20 @@ class OStatus
* @param integer $max_items Number of maximum items to fetch * @param integer $max_items Number of maximum items to fetch
* @param string $filter Feed items filter (activity, posts or comments) * @param string $filter Feed items filter (activity, posts or comments)
* @param boolean $nocache Wether to bypass caching * @param boolean $nocache Wether to bypass caching
* * @return string XML feed or empty string on error
* @return string XML feed
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function feed($owner_nick, &$last_update, $max_items = 300, $filter = 'activity', $nocache = false) public static function feed(string $owner_nick, string &$last_update, int $max_items = 300, string $filter = 'activity', bool $nocache = false): string
{ {
$stamp = microtime(true); $stamp = microtime(true);
$owner = User::getOwnerDataByNick($owner_nick); $owner = User::getOwnerDataByNick($owner_nick);
if (!$owner) { if (!$owner) {
return; return '';
} }
$cachekey = "ostatus:feed:" . $owner_nick . ":" . $filter . ":" . $last_update; $cachekey = 'ostatus:feed:' . $owner_nick . ':' . $filter . ':' . $last_update;
$previous_created = $last_update; $previous_created = $last_update;
@ -1998,11 +2051,16 @@ class OStatus
} }
$check_date = DateTimeFormat::utc($last_update); $check_date = DateTimeFormat::utc($last_update);
$authorid = Contact::getIdForURL($owner["url"]); $authorid = Contact::getIdForURL($owner['url']);
$condition = ["`uid` = ? AND `received` > ? AND NOT `deleted` $condition = [
AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)", "`uid` = ? AND `received` > ? AND NOT `deleted` AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)",
$owner["uid"], $check_date, Item::PRIVATE, Protocol::OSTATUS, Protocol::DFRN]; $owner['uid'],
$check_date,
Item::PRIVATE,
Protocol::OSTATUS,
Protocol::DFRN,
];
if ($filter === 'comments') { if ($filter === 'comments') {
$condition[0] .= " AND `object-type` = ? "; $condition[0] .= " AND `object-type` = ? ";
@ -2011,7 +2069,7 @@ class OStatus
if ($owner['contact-type'] != Contact::TYPE_COMMUNITY) { if ($owner['contact-type'] != Contact::TYPE_COMMUNITY) {
$condition[0] .= " AND `contact-id` = ? AND `author-id` = ?"; $condition[0] .= " AND `contact-id` = ? AND `author-id` = ?";
$condition[] = $owner["id"]; $condition[] = $owner['id'];
$condition[] = $authorid; $condition[] = $authorid;
} }
@ -2035,7 +2093,7 @@ class OStatus
$item['body'] .= '🍼'; $item['body'] .= '🍼';
} }
if (in_array($item["verb"], [Activity::FOLLOW, Activity::O_UNFOLLOW, Activity::LIKE])) { if (in_array($item['verb'], [Activity::FOLLOW, Activity::O_UNFOLLOW, Activity::LIKE])) {
continue; continue;
} }
@ -2067,7 +2125,7 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function salmon(array $item, array $owner) public static function salmon(array $item, array $owner): string
{ {
$doc = new DOMDocument('1.0', 'utf-8'); $doc = new DOMDocument('1.0', 'utf-8');
$doc->formatOutput = true; $doc->formatOutput = true;
@ -2091,7 +2149,7 @@ class OStatus
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
public static function isSupportedByContactUrl($url) public static function isSupportedByContactUrl(string $url): bool
{ {
$probe = Probe::uri($url, Protocol::OSTATUS); $probe = Probe::uri($url, Protocol::OSTATUS);
return $probe['network'] == Protocol::OSTATUS; return $probe['network'] == Protocol::OSTATUS;

View file

@ -55,7 +55,7 @@ class Relay
* @param string $url * @param string $url
* @return boolean "true" is the post is wanted by the system * @return boolean "true" is the post is wanted by the system
*/ */
public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = '') public static function isSolicitedPost(array $tags, string $body, int $authorid, string $url, string $network = ''): bool
{ {
$config = DI::config(); $config = DI::config();
@ -139,6 +139,7 @@ class Relay
* *
* @param array $gserver Global server record * @param array $gserver Global server record
* @param array $fields Optional network specific fields * @param array $fields Optional network specific fields
* @return void
* @throws \Exception * @throws \Exception
*/ */
public static function updateContact(array $gserver, array $fields = []) public static function updateContact(array $gserver, array $fields = [])
@ -198,6 +199,7 @@ class Relay
* The relay contact is a technical contact entry that exists once per server. * The relay contact is a technical contact entry that exists once per server.
* *
* @param array $contact of the relay contact * @param array $contact of the relay contact
* @return void
*/ */
public static function markForArchival(array $contact) public static function markForArchival(array $contact)
{ {
@ -229,15 +231,14 @@ class Relay
* @param integer $item_id id of the item that is sent * @param integer $item_id id of the item that is sent
* @param array $contacts Previously fetched contacts * @param array $contacts Previously fetched contacts
* @param array $networks Networks of the relay servers * @param array $networks Networks of the relay servers
*
* @return array of relay servers * @return array of relay servers
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function getDirectRelayList(int $item_id) public static function getDirectRelayList(int $item_id): array
{ {
$serverlist = []; $serverlist = [];
if (!DI::config()->get("system", "relay_directly", false)) { if (!DI::config()->get('system', 'relay_directly', false)) {
return []; return [];
} }
@ -302,10 +303,10 @@ class Relay
* Return a list of relay servers * Return a list of relay servers
* *
* @param array $fields Field list * @param array $fields Field list
* @return array * @return array List of relay servers
* @throws Exception * @throws Exception
*/ */
public static function getList($fields = []):array public static function getList(array $fields = []): array
{ {
return DBA::selectToArray('apcontact', $fields, return DBA::selectToArray('apcontact', $fields,
["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 0, Contact::FRIEND]); ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 0, Contact::FRIEND]);
@ -316,7 +317,7 @@ class Relay
* *
* @param array $gserver Global server record * @param array $gserver Global server record
* @param array $fields Fieldlist * @param array $fields Fieldlist
* @return array with the contact * @return array|bool Array with the contact or false on error
* @throws \Exception * @throws \Exception
*/ */
private static function getContact(array $gserver, array $fields = ['batch', 'id', 'url', 'name', 'network', 'protocol', 'archive', 'blocked']) private static function getContact(array $gserver, array $fields = ['batch', 'id', 'url', 'name', 'network', 'protocol', 'archive', 'blocked'])
@ -344,6 +345,8 @@ class Relay
/** /**
* Resubscribe to all relay servers * Resubscribe to all relay servers
*
* @return void
*/ */
public static function reSubscribe() public static function reSubscribe()
{ {

View file

@ -40,10 +40,10 @@ class Salmon
/** /**
* @param string $uri Uniform Resource Identifier * @param string $uri Uniform Resource Identifier
* @param string $keyhash encoded key * @param string $keyhash encoded key
* @return mixed * @return string Key or empty string on any errors
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */
public static function getKey(string $uri, string $keyhash) public static function getKey(string $uri, string $keyhash): string
{ {
$ret = []; $ret = [];
@ -83,13 +83,13 @@ class Salmon
Logger::notice('Key located', ['ret' => $ret]); Logger::notice('Key located', ['ret' => $ret]);
if (count($ret) == 1) { if (count($ret) == 1) {
// We only found one one key so we don't care if the hash matches. /* We only found one one key so we don't care if the hash matches.
// If it's the wrong key we'll find out soon enough because * If it's the wrong key we'll find out soon enough because
// message verification will fail. This also covers some older * message verification will fail. This also covers some older
// software which don't supply a keyhash. As long as they only * software which don't supply a keyhash. As long as they only
// have one key we'll be right. * have one key we'll be right.
*/
return $ret[0]; return (string) $ret[0];
} else { } else {
foreach ($ret as $a) { foreach ($ret as $a) {
$hash = Strings::base64UrlEncode(hash('sha256', $a)); $hash = Strings::base64UrlEncode(hash('sha256', $a));