| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  | <?php | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * StatusNet, the distributed open-source microblogging tool | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * An activity | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * PHP version 5 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * LICENCE: This program is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU Affero General Public License as published by | 
					
						
							|  |  |  |  * the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  |  * (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU Affero General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU Affero General Public License | 
					
						
							|  |  |  |  * along with this program.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @category  Feed | 
					
						
							|  |  |  |  * @package   StatusNet | 
					
						
							|  |  |  |  * @author    Evan Prodromou <evan@status.net> | 
					
						
							|  |  |  |  * @author    Zach Copley <zach@status.net> | 
					
						
							|  |  |  |  * @copyright 2010 StatusNet, Inc. | 
					
						
							|  |  |  |  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPLv3 | 
					
						
							|  |  |  |  * @link      http://status.net/ | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if (!defined('STATUSNET')) { | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Utilities for turning DOMish things into Activityish things | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Some common functions that I didn't have the bandwidth to try to factor | 
					
						
							|  |  |  |  * into some kind of reasonable superclass, so just dumped here. Might | 
					
						
							|  |  |  |  * be useful to have an ActivityObject parent class or something. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @category  OStatus | 
					
						
							|  |  |  |  * @package   StatusNet | 
					
						
							|  |  |  |  * @author    Evan Prodromou <evan@status.net> | 
					
						
							|  |  |  |  * @copyright 2010 StatusNet, Inc. | 
					
						
							|  |  |  |  * @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'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const LINK = 'link'; | 
					
						
							|  |  |  |     const REL  = 'rel'; | 
					
						
							|  |  |  |     const TYPE = 'type'; | 
					
						
							|  |  |  |     const HREF = 'href'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const CONTENT = 'content'; | 
					
						
							|  |  |  |     const SRC     = 'src'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the permalink for an Activity object | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param DOMElement $element A DOM element | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string related link, if any | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static function getPermalink($element) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return self::getLink($element, 'alternate', 'text/html'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the permalink for an Activity object | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param DOMElement $element A DOM element | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ($linkRel == $rel && | 
					
						
							|  |  |  |                     (is_null($type) || $linkType == $type)) { | 
					
						
							|  |  |  |                     return $link->getAttribute(self::HREF); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static function getLinks(DOMNode $element, $rel, $type=null) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $els = $element->childNodes; | 
					
						
							|  |  |  |         $out = array(); | 
					
						
							| 
									
										
										
										
											2011-05-30 09:57:11 -04:00
										 |  |  |          | 
					
						
							|  |  |  |         for ($i = 0; $i < $els->length; $i++) { | 
					
						
							|  |  |  |             $link = $els->item($i); | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             if ($link->localName == self::LINK && $link->namespaceURI == self::ATOM) { | 
					
						
							|  |  |  |                 $linkRel = $link->getAttribute(self::REL); | 
					
						
							|  |  |  |                 $linkType = $link->getAttribute(self::TYPE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ($linkRel == $rel && | 
					
						
							|  |  |  |                     (is_null($type) || $linkType == $type)) { | 
					
						
							|  |  |  |                     $out[] = $link; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $out; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Gets the first child element 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 DOMElement found element or null | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static function child(DOMNode $element, $tag, $namespace=self::ATOM) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $els = $element->childNodes; | 
					
						
							|  |  |  |         if (empty($els) || $els->length == 0) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             for ($i = 0; $i < $els->length; $i++) { | 
					
						
							|  |  |  |                 $el = $els->item($i); | 
					
						
							|  |  |  |                 if ($el->localName == $tag && $el->namespaceURI == $namespace) { | 
					
						
							|  |  |  |                     return $el; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-19 16:38:58 -04:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * 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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Grab the text content of a DOM element child of the current element | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param DOMElement $element   Element whose children we examine | 
					
						
							|  |  |  |      * @param string     $tag       Tag to look up | 
					
						
							|  |  |  |      * @param string     $namespace Namespace to use, defaults to Atom | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string content of the child | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static function childContent(DOMNode $element, $tag, $namespace=self::ATOM) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $el = self::child($element, $tag, $namespace); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (empty($el)) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return $el->textContent; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static function childHtmlContent(DOMNode $element, $tag, $namespace=self::ATOM) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $el = self::child($element, $tag, $namespace); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (empty($el)) { | 
					
						
							|  |  |  |             return null; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             return self::textConstruct($el); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the content of an atom:entry-like object | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param DOMElement $element The element to examine. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return string unencoded HTML content of the element, like "This -< is <b>HTML</b>." | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @todo handle remote content | 
					
						
							|  |  |  |      * @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); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static function textConstruct($el) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $src  = $el->getAttribute(self::SRC); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($src)) { | 
					
						
							| 
									
										
										
										
											2010-09-13 00:49:42 +02:00
										 |  |  |             // TRANS: Client exception thrown when there is no source attribute.
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             throw new ClientException(_("Can't handle remote content yet.")); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $type = $el->getAttribute(self::TYPE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // slavishly following http://atompub.org/rfc4287.html#rfc.section.4.1.3.3
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (empty($type) || $type == 'text') { | 
					
						
							| 
									
										
										
										
											2010-04-23 15:40:48 -07:00
										 |  |  |             // We have plaintext saved as the XML text content.
 | 
					
						
							|  |  |  |             // Since we want HTML, we need to escape any special chars.
 | 
					
						
							|  |  |  |             return htmlspecialchars($el->textContent); | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |         } else if ($type == 'html') { | 
					
						
							| 
									
										
										
										
											2010-04-23 15:40:48 -07:00
										 |  |  |             // We have HTML saved as the XML text content.
 | 
					
						
							|  |  |  |             // No additional processing required once we've got it.
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             $text = $el->textContent; | 
					
						
							| 
									
										
										
										
											2010-04-23 15:40:48 -07:00
										 |  |  |             return $text; | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |         } else if ($type == 'xhtml') { | 
					
						
							| 
									
										
										
										
											2010-04-23 15:40:48 -07:00
										 |  |  |             // Per spec, the <content type="xhtml"> contains a single
 | 
					
						
							|  |  |  |             // HTML <div> with XHTML namespace on it as a child node.
 | 
					
						
							|  |  |  |             // We need to pull all of that <div>'s child nodes and
 | 
					
						
							|  |  |  |             // serialize them back to an (X)HTML source fragment.
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             $divEl = ActivityUtils::child($el, 'div', 'http://www.w3.org/1999/xhtml'); | 
					
						
							|  |  |  |             if (empty($divEl)) { | 
					
						
							|  |  |  |                 return null; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $doc = $divEl->ownerDocument; | 
					
						
							|  |  |  |             $text = ''; | 
					
						
							|  |  |  |             $children = $divEl->childNodes; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             for ($i = 0; $i < $children->length; $i++) { | 
					
						
							|  |  |  |                 $child = $children->item($i); | 
					
						
							|  |  |  |                 $text .= $doc->saveXML($child); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return trim($text); | 
					
						
							|  |  |  |         } else if (in_array($type, array('text/xml', 'application/xml')) || | 
					
						
							|  |  |  |                    preg_match('#(+|/)xml$#', $type)) { | 
					
						
							| 
									
										
										
										
											2010-09-13 00:49:42 +02:00
										 |  |  |             // TRANS: Client exception thrown when there embedded XML content is found that cannot be processed yet.
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             throw new ClientException(_("Can't handle embedded XML content yet.")); | 
					
						
							|  |  |  |         } else if (strncasecmp($type, 'text/', 5)) { | 
					
						
							|  |  |  |             return $el->textContent; | 
					
						
							|  |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2010-09-13 00:49:42 +02:00
										 |  |  |             // TRANS: Client exception thrown when base64 encoded content is found that cannot be processed yet.
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  |             throw new ClientException(_("Can't handle embedded Base64 content yet.")); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-03-21 16:25:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Is this a valid URI for remote profile/notice identification? | 
					
						
							|  |  |  |      * Does not have to be a resolvable URL. | 
					
						
							|  |  |  |      * @param string $uri | 
					
						
							|  |  |  |      * @return boolean | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     static function validateUri($uri) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2010-07-22 16:00:26 -07:00
										 |  |  |         // Check mailto: URIs first
 | 
					
						
							| 
									
										
										
										
											2015-07-07 19:30:14 +02:00
										 |  |  |         $validate = new Validate(); | 
					
						
							| 
									
										
										
										
											2010-07-22 16:00:26 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (preg_match('/^mailto:(.*)$/', $uri, $match)) { | 
					
						
							| 
									
										
										
										
											2015-07-07 19:30:14 +02:00
										 |  |  |             return $validate->email($match[1], common_config('email', 'check_domain')); | 
					
						
							| 
									
										
										
										
											2010-07-22 16:00:26 -07:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-07 19:30:14 +02:00
										 |  |  |         if ($validate->uri($uri)) { | 
					
						
							| 
									
										
										
										
											2010-03-21 16:25:12 -07:00
										 |  |  |             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.
 | 
					
						
							| 
									
										
										
										
											2015-07-07 19:30:14 +02:00
										 |  |  |         if ($validate->uri($uri, array('allowed_scheme' => array('tag')))) { | 
					
						
							| 
									
										
										
										
											2010-03-21 16:25:12 -07:00
										 |  |  |             return true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-17 13:09:37 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-11 02:59:18 +00:00
										 |  |  |         // Try the feed author
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $author = ActivityUtils::child($feedEl, Activity::AUTHOR, Activity::ATOM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!empty($author)) { | 
					
						
							|  |  |  |             return new ActivityObject($author); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-17 13:09:37 -05:00
										 |  |  |         // 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); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-02-11 02:59:18 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // Try the author
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $author = ActivityUtils::child($entry, Activity::AUTHOR, Activity::ATOM); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (!empty($author)) { | 
					
						
							|  |  |  |                 return new ActivityObject($author); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2010-12-17 13:09:37 -05:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-24 16:42:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-10 15:27:40 +02:00
										 |  |  |     static function compareTypes($type, $objects) | 
					
						
							| 
									
										
										
										
											2014-06-24 16:42:34 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-01-21 02:10:34 +01:00
										 |  |  |         $type = self::resolveUri($type, false); | 
					
						
							| 
									
										
										
										
											2014-06-24 16:42:34 +02:00
										 |  |  |         foreach ((array)$objects as $object) { | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |             if ($type === self::resolveUri($object)) { | 
					
						
							| 
									
										
										
										
											2014-06-24 16:42:34 +02:00
										 |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-09-10 15:27:40 +02:00
										 |  |  |     static function compareVerbs($type, $objects) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return self::compareTypes($type, $objects); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |     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) { | 
					
						
							| 
									
										
										
										
											2016-01-04 02:04:18 +01:00
										 |  |  |         $obj_class = null; | 
					
						
							|  |  |  |         // TODO: Extend this in plugins etc. and describe in EVENTS.txt
 | 
					
						
							|  |  |  |         if (Event::handle('StartFindLocalActivityObject', array($uris, $type, &$obj_class))) { | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |             switch (self::resolveUri($type)) { | 
					
						
							|  |  |  |             case ActivityObject::PERSON: | 
					
						
							|  |  |  |                 // GROUP will also be here in due time...
 | 
					
						
							| 
									
										
										
										
											2016-01-04 02:04:18 +01:00
										 |  |  |                 $obj_class = 'Profile'; | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |                 break; | 
					
						
							|  |  |  |             default: | 
					
						
							| 
									
										
										
										
											2016-01-04 02:04:18 +01:00
										 |  |  |                 $obj_class = 'Notice'; | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-01-04 02:04:18 +01:00
										 |  |  |         $object = null; | 
					
						
							| 
									
										
										
										
											2016-01-04 01:58:45 +01:00
										 |  |  |         $uris = array_unique($uris); | 
					
						
							|  |  |  |         foreach ($uris as $uri) { | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |             try { | 
					
						
							|  |  |  |                 // the exception thrown will cancel before reaching $object
 | 
					
						
							| 
									
										
										
										
											2016-01-04 02:04:18 +01:00
										 |  |  |                 $object = call_user_func("{$obj_class}::fromUri", $uri); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |                 break; | 
					
						
							| 
									
										
										
										
											2016-01-04 01:53:33 +01:00
										 |  |  |             } catch (UnknownUriException $e) { | 
					
						
							|  |  |  |                 common_debug('Could not find local activity object from uri: '.$e->object_uri); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-01-04 01:58:45 +01:00
										 |  |  |         if (!$object instanceof Managed_DataObject) { | 
					
						
							|  |  |  |             throw new ServerException('Could not find any activityobject stored locally with given URIs: '.var_export($uris,true)); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-01-04 01:58:45 +01:00
										 |  |  |         Event::handle('EndFindLocalActivityObject', array($object->getUri(), $object->getObjectType(), $object)); | 
					
						
							| 
									
										
										
										
											2014-06-28 21:16:45 +02:00
										 |  |  |         return $object; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-01 15:48:34 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     // 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 <author> 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; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2014-07-05 23:39:17 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     static public function typeToTitle($type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return ucfirst(self::resolveUri($type, true)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static public function verbToTitle($verb) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return ucfirst(self::resolveUri($verb, true)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-03-20 16:06:22 -05:00
										 |  |  | } |