X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=lib%2Factivityutils.php;h=8a2be350225140d6198128ad33d97a42a305c39b;hb=refs%2Fheads%2Fupstream-changes%2Fgoogle-analytics-removal;hp=dd38d4e14222b8da15030918d8d2ef187d5bdb8d;hpb=dbb5e9e1914c9dc67019a4abb1948d40171df0d4;p=quix0rs-gnu-social.git diff --git a/lib/activityutils.php b/lib/activityutils.php index dd38d4e142..8a2be35022 100644 --- a/lib/activityutils.php +++ b/lib/activityutils.php @@ -46,7 +46,6 @@ if (!defined('STATUSNET')) { * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 * @link http://status.net/ */ - class ActivityUtils { const ATOM = 'http://www.w3.org/2005/Atom'; @@ -66,7 +65,6 @@ class ActivityUtils * * @return string related link, if any */ - static function getPermalink($element) { return self::getLink($element, 'alternate', 'text/html'); @@ -79,19 +77,16 @@ class ActivityUtils * * @return string related link, if any */ - static function getLink(DOMNode $element, $rel, $type=null) { $els = $element->childNodes; foreach ($els as $link) { - if (!($link instanceof DOMElement)) { continue; } if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); $linkType = $link->getAttribute(self::TYPE); @@ -109,10 +104,10 @@ class ActivityUtils { $els = $element->childNodes; $out = array(); - - foreach ($els as $link) { + + for ($i = 0; $i < $els->length; $i++) { + $link = $els->item($i); if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { - $linkRel = $link->getAttribute(self::REL); $linkType = $link->getAttribute(self::TYPE); @@ -135,7 +130,6 @@ class ActivityUtils * * @return DOMElement found element or null */ - static function child(DOMNode $element, $tag, $namespace=self::ATOM) { $els = $element->childNodes; @@ -151,6 +145,34 @@ class ActivityUtils } } + /** + * Gets all immediate child elements with the given tag + * + * @param DOMElement $element element to pick at + * @param string $tag tag to look for + * @param string $namespace Namespace to look under + * + * @return array found element or null + */ + + static function children(DOMNode $element, $tag, $namespace=self::ATOM) + { + $results = array(); + + $els = $element->childNodes; + + if (!empty($els) && $els->length > 0) { + for ($i = 0; $i < $els->length; $i++) { + $el = $els->item($i); + if ($el->localName == $tag && $el->namespaceURI == $namespace) { + $results[] = $el; + } + } + } + + return $results; + } + /** * Grab the text content of a DOM element child of the current element * @@ -160,7 +182,6 @@ class ActivityUtils * * @return string content of the child */ - static function childContent(DOMNode $element, $tag, $namespace=self::ATOM) { $el = self::child($element, $tag, $namespace); @@ -194,7 +215,6 @@ class ActivityUtils * @todo handle embedded XML mime types * @todo handle base64-encoded non-XML and non-text mime types */ - static function getContent($element) { return self::childHtmlContent($element, self::CONTENT, self::ATOM); @@ -205,6 +225,7 @@ class ActivityUtils $src = $el->getAttribute(self::SRC); if (!empty($src)) { + // TRANS: Client exception thrown when there is no source attribute. throw new ClientException(_("Can't handle remote content yet.")); } @@ -241,10 +262,12 @@ class ActivityUtils return trim($text); } else if (in_array($type, array('text/xml', 'application/xml')) || preg_match('#(+|/)xml$#', $type)) { + // TRANS: Client exception thrown when there embedded XML content is found that cannot be processed yet. throw new ClientException(_("Can't handle embedded XML content yet.")); } else if (strncasecmp($type, 'text/', 5)) { return $el->textContent; } else { + // TRANS: Client exception thrown when base64 encoded content is found that cannot be processed yet. throw new ClientException(_("Can't handle embedded Base64 content yet.")); } } @@ -258,22 +281,173 @@ class ActivityUtils static function validateUri($uri) { // Check mailto: URIs first + $validate = new Validate(); if (preg_match('/^mailto:(.*)$/', $uri, $match)) { - return Validate::email($match[1], common_config('email', 'check_domain')); + return $validate->email($match[1], common_config('email', 'check_domain')); } - if (Validate::uri($uri)) { + if ($validate->uri($uri)) { return true; } // Possibly an upstream bug; tag: URIs aren't validated properly // unless you explicitly ask for them. All other schemes are accepted // for basic URI validation without asking. - if (Validate::uri($uri, array('allowed_scheme' => array('tag')))) { + if ($validate->uri($uri, array('allowed_scheme' => array('tag')))) { return true; } return false; } + + static function getFeedAuthor($feedEl) + { + // Try old and deprecated activity:subject + + $subject = ActivityUtils::child($feedEl, Activity::SUBJECT, Activity::SPEC); + + if (!empty($subject)) { + return new ActivityObject($subject); + } + + // Try the feed author + + $author = ActivityUtils::child($feedEl, Activity::AUTHOR, Activity::ATOM); + + if (!empty($author)) { + return new ActivityObject($author); + } + + // Sheesh. Not a very nice feed! Let's try fingerpoken in the + // entries. + + $entries = $feedEl->getElementsByTagNameNS(Activity::ATOM, 'entry'); + + if (!empty($entries) && $entries->length > 0) { + + $entry = $entries->item(0); + + // Try the (deprecated) activity:actor + + $actor = ActivityUtils::child($entry, Activity::ACTOR, Activity::SPEC); + + if (!empty($actor)) { + return new ActivityObject($actor); + } + + // Try the author + + $author = ActivityUtils::child($entry, Activity::AUTHOR, Activity::ATOM); + + if (!empty($author)) { + return new ActivityObject($author); + } + } + + return null; + } + + static function compareTypes($type, $objects) + { + $type = self::resolveUri($type); + foreach ((array)$objects as $object) { + if ($type === self::resolveUri($object)) { + return true; + } + } + return false; + } + + static function compareVerbs($type, $objects) + { + return self::compareTypes($type, $objects); + } + + static function resolveUri($uri, $make_relative=false) + { + if (empty($uri)) { + throw new ServerException('No URI to resolve in ActivityUtils::resolveUri'); + } + + if (!$make_relative && parse_url($uri, PHP_URL_SCHEME) == '') { // relative -> absolute + $uri = Activity::SCHEMA . $uri; + } elseif ($make_relative) { // absolute -> relative + $uri = basename($uri); //preg_replace('/^http:\/\/activitystrea\.ms\/schema\/1\.0\//', '', $uri); + } // absolute schemas pass through unharmed + + return $uri; + } + + static function findLocalObject(array $uris, $type=ActivityObject::NOTE) { + $obj_class = null; + // TODO: Extend this in plugins etc. and describe in EVENTS.txt + if (Event::handle('StartFindLocalActivityObject', array($uris, $type, &$obj_class))) { + switch (self::resolveUri($type)) { + case ActivityObject::PERSON: + // GROUP will also be here in due time... + $obj_class = 'Profile'; + break; + default: + $obj_class = 'Notice'; + } + } + $object = null; + $uris = array_unique($uris); + foreach ($uris as $uri) { + try { + // the exception thrown will cancel before reaching $object + $object = call_user_func("{$obj_class}::fromUri", $uri); + break; + } catch (UnknownUriException $e) { + common_debug('Could not find local activity object from uri: '.$e->object_uri); + } + } + if (!$object instanceof Managed_DataObject) { + throw new ServerException('Could not find any activityobject stored locally with given URIs: '.var_export($uris,true)); + } + Event::handle('EndFindLocalActivityObject', array($object->getUri(), $object->getObjectType(), $object)); + return $object; + } + + // Check authorship by supplying a Profile as a default and letting plugins + // set it to something else if the activity's author is actually someone + // else (like with a group or peopletag feed as handled in OStatus). + // + // NOTE: Returned is not necessarily the supplied profile! For example, + // the "feed author" may be a group, but the "activity author" is a person! + static function checkAuthorship(Activity $activity, Profile $profile) + { + if (Event::handle('CheckActivityAuthorship', array($activity, &$profile))) { + // if (empty($activity->actor)), then we generated this Activity ourselves and can trust $profile + + $actor_uri = $profile->getUri(); + + if (!in_array($actor_uri, array($activity->actor->id, $activity->actor->link))) { + // A mismatch between our locally stored URI and the supplied author? + // Probably not more than a blog feed or something (with multiple authors or so) + // but log it for future inspection. + common_log(LOG_WARNING, "Got an actor '{$activity->actor->title}' ({$activity->actor->id}) on single-user feed for " . $actor_uri); + } elseif (empty($activity->actor->id)) { + // Plain without ActivityStreams actor info. + // We'll just ignore this info for now and save the update under the feed's identity. + } + } + + if (!$profile instanceof Profile) { + throw new ServerException('Could not get an author Profile for activity'); + } + + return $profile; + } + + static public function typeToTitle($type) + { + return ucfirst(self::resolveUri($type, true)); + } + + static public function verbToTitle($verb) + { + return ucfirst(self::resolveUri($verb, true)); + } }