function saveDataFromInput() { $page = Idno::site()->currentPage(); if (empty($this->_id)) { $new = true; } else { $new = false; } $this->likeof = $page->getInput('like-of'); if ($this->likeof) { foreach ((array) $this->likeof as $likeofurl) { $this->syndicatedto = Webmention::addSyndicatedReplyTargets($likeofurl, $this->syndicatedto); } } $this->description = $page->getInput('description'); if (empty($this->description)) { $result = \IdnoPlugins\Reactions\Pages\Fetch::fetch($this->likeof); if (!empty($result['description'])) { $this->description = $result['description']; } } $this->setAccess($page->getInput('access')); Idno::site()->logging()->log("saving like. new: {$new}"); if ($this->publish($new)) { Idno::site()->logging()->log("sending webmentions from {$this->getURL()} to {$this->likeof}"); Webmention::sendWebmentionPayload($this->getURL(), $this->likeof); } return true; }
function testAddSyndicatedReplyTargets() { // test u-syndication $doc = <<<EOD <div class="h-entry"> <span class="p-name e-content">This is a post</span> <a class="u-url" href="http://foo.bar/post">permalink</a> <a class="u-syndication" href="https://twitter.com/foobar/12345">on Twitter</a> <a class="u-syndication" href="https://www.facebook.com/foobar/posts/12345">on Facebook</a> </div> EOD; $result = Webmention::addSyndicatedReplyTargets('http://foo.bar/post', [], ['response' => 200, 'content' => $doc]); $this->assertEquals(['https://twitter.com/foobar/12345', 'https://www.facebook.com/foobar/posts/12345'], $result); // test rel-syndication $doc = <<<EOD <head> <link rel="syndication" href="https://twitter.com/foobar/12345" /> <link rel="syndication" href="https://www.facebook.com/foobar/posts/12345" /> </head> <body> <div class="h-entry"> <span class="p-name e-content">This is a post</span> <a class="u-url" href="http://foo.bar/post">permalink</a> </div> </body> EOD; $result = Webmention::addSyndicatedReplyTargets('http://foo.bar/post', [], ['response' => 200, 'content' => $doc]); $this->assertEquals(['https://twitter.com/foobar/12345', 'https://www.facebook.com/foobar/posts/12345'], $result); }
function saveDataFromInput() { $page = Idno::site()->currentPage(); if (empty($this->_id)) { $new = true; } else { $new = false; } $this->repostof = $page->getInput('repost-of'); if ($this->repostof) { foreach ((array) $this->repostof as $repostofurl) { $this->syndicatedto = Webmention::addSyndicatedReplyTargets($repostofurl, $this->syndicatedto); } } $this->description = $page->getInput('description'); $this->body = $page->getInput('body'); if (empty($this->description) && empty($this->body)) { $result = \IdnoPlugins\Reactions\Pages\Fetch::fetch($this->repostof); if (isset($result['description'])) { $this->description = $result['description']; } if (isset($result['content'])) { $this->body = $result['content']; } } $this->setAccess($page->getInput('access')); if ($this->publish($new)) { Webmention::sendWebmentionPayload($this->getURL(), $this->repostof); } return true; }
function postContent() { $body = strip_tags($this->getInput('body')); $name = strip_tags($this->getInput('name')); $url = trim($this->getInput('url')); $url2 = trim($this->getInput('url-2')); $validator = $this->getInput('validator'); if (!empty($url2)) { $this->deniedContent(); } $this->referrerGatekeeper(); if (!empty($body) && !empty($name) && !empty($validator)) { if ($object = Entity::getByUUID($validator)) { if ($url = Webservice::sanitizeURL($url)) { if ($content = Webservice::get($url)) { if ($content['response'] == '200') { $icon = Webmention::getIconFromWebsiteContent($content['content'], $url); } } } if (empty($icon)) { $bn = hexdec(substr(md5($url), 0, 15)); $number = 1 + $bn % 5; $icon = \Idno\Core\site()->config()->url . 'gfx/users/default-' . str_pad($number, 2, '0', STR_PAD_LEFT) . '.png'; } $object->addAnnotation('reply', $name, $url, $icon, $body); $this->forward($object->getDisplayURL()); } } }
/** * Saves changes to this object based on user input * @return bool */ function saveDataFromInput() { if (empty($this->_id)) { $new = true; } else { $new = false; } $this->title = \Idno\Core\site()->currentPage()->getInput('title'); $this->body = \Idno\Core\site()->currentPage()->getInput('body'); $this->setAccess('PUBLIC'); // Get photo if ($new) { if (!empty($_FILES['photo']['tmp_name'])) { if (\Idno\Entities\File::isImage($_FILES['photo']['tmp_name'])) { if ($photo = \Idno\Entities\File::createFromFile($_FILES['photo']['tmp_name'], $_FILES['photo']['name'], $_FILES['photo']['type'], true)) { $this->attachFile($photo); if ($thumbnail = \Idno\Entities\File::createThumbnailFromFile($_FILES['photo']['tmp_name'], $_FILES['photo']['name'])) { $this->thumbnail = \Idno\Core\site()->config()->url . 'file/' . $thumbnail; $this->thumbnail_id = substr($thumbnail, 0, strpos($thumbnail, '/')); } } else { \Idno\Core\site()->session()->addMessage('Image wasn\'t attached.'); } } else { \Idno\Core\site()->session()->addMessage('This doesn\'t seem to be an image ..'); } } else { \Idno\Core\site()->session()->addMessage('We couldn\'t access your image. Please try again.'); return false; } } if ($this->save()) { if ($new) { $this->addToFeed(); } // Add it to the Activity Streams feed \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\site()->template()->parseURLs($this->getDescription())); \Idno\Core\site()->session()->addMessage('Your photo was successfully saved.'); return true; } else { return false; } }
function post() { parse_str(trim(file_get_contents("php://input")), $vars); // Check that both source and target are non-empty if (!empty($vars['source']) && !empty($vars['target']) && $vars['source'] != $vars['target']) { $source = urldecode($vars['source']); $target = urldecode($vars['target']); // Get the page handler for target if ($page = \Idno\Core\site()->getPageHandler($target)) { // Check that source exists, parse it for mf2 content, // and ensure that it genuinely mentions this page if ($source_content = \Idno\Core\Webmention::getPageContent($source)) { if (substr_count($source_content['content'], $target) || $source_content['response'] == 410) { $source_mf2 = \Idno\Core\Webmention::parseContent($source_content['content']); // Set source and target information as input variables $page->setPermalink(); if ($page->webmentionContent($source, $target, $source_content, $source_mf2)) { $this->setResponse(202); // Webmention received a-ok. exit; } else { $error = 'target_not_supported'; $error_text = 'This is not webmentionable.'; } } else { $error = 'no_link_found'; $error_text = 'The source URI does not contain a link to the target URI.'; error_log('No link from ' . $source . ' to ' . $target); } } else { $error = 'source_not_found'; $error_text = 'The source content could not be obtained.'; error_log('No content from ' . $source); } } else { $error = 'target_not_found'; $error_text = 'The target page does not exist.'; } } $this->setResponse(400); // Webmention failed. echo json_encode(['error' => $error, 'error_text' => $error_text]); }
function getContent() { if (!\Idno\Core\site()->session()->isLoggedIn()) { $this->setResponse(401); $this->forward('/session/login'); } $url = $this->getInput('share_url'); $title = $this->getInput('share_title'); $share_type = 'note'; if ($content = \Idno\Core\Webmention::getPageContent($url)) { if ($mf2 = \Idno\Core\Webmention::parseContent($content['content'])) { if (substr_count($content['content'], 'h-entry') == 1) { $share_type = 'reply'; if (substr_count($content['content'], 'h-event') == 1) { $share_type = 'rsvp'; } } } } $content_type = \Idno\Common\ContentType::getRegisteredForIndieWebPostType($share_type); if (!empty($content_type)) { if ($page = \Idno\Core\site()->getPageHandler('/' . $content_type->camelCase($content_type->getEntityClassName()) . '/edit')) { if ($share_type == 'note' && !substr_count($url, 'twitter.com')) { $page->setInput('body', $title . ' ' . $url); } else { $page->setInput('url', $url); if (substr_count($url, 'twitter.com')) { preg_match("|https?://(www\\.)?twitter\\.com/(#!/)?@?([^/]*)|", $url, $matches); if (!empty($matches[3])) { $page->setInput('body', '@' . $matches[3] . ' '); } } } $page->setInput('hidenav', true); $page->get(); } } else { $t = \Idno\Core\site()->template(); $body = $t->__(['share_type' => $share_type, 'content_type' => $content_type])->draw('firefox/share'); $t->__(['title' => 'Share', 'body' => $body, 'hidenav' => true])->drawPage(); } }
/** * Saves changes to this object based on user input * @return bool */ function saveDataFromInput() { if (empty($this->_id)) { $new = true; } else { $new = false; } $this->title = \Idno\Core\site()->currentPage()->getInput('title'); $this->body = \Idno\Core\site()->currentPage()->getInput('body'); $this->setAccess('PUBLIC'); // Get video if ($new) { if (!empty($_FILES['video']['tmp_name'])) { if (true) { if ($video = \Idno\Entities\File::createFromFile($_FILES['video']['tmp_name'], $_FILES['video']['name'], $_FILES['video']['type'], true)) { $this->attachFile($video); } else { \Idno\Core\site()->session()->addMessage('Video wasn\'t attached.'); } } else { \Idno\Core\site()->session()->addMessage('This doesn\'t seem to be a video ..'); } } else { \Idno\Core\site()->session()->addMessage('We couldn\'t access your video. Please try again.'); return false; } } if ($this->save()) { if ($new) { $this->addToFeed(); } // Add it to the Activity Streams feed \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\site()->template()->parseURLs($this->getDescription())); \Idno\Core\site()->session()->addMessage('Your video was successfully saved.'); return true; } else { return false; } }
function deleteData() { if ($this->getAccess() == 'PUBLIC') { \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\Idno::site()->template()->parseURLs($this->getDescription())); } }
/** * Saves changes to this object based on user input * @return bool */ function saveDataFromInput() { if (empty($this->_id)) { $new = true; } else { $new = false; } if ($new) { if (!\Idno\Core\Idno::site()->triggerEvent("file/upload", [], true)) { return false; } } $this->title = \Idno\Core\Idno::site()->currentPage()->getInput('title'); $this->body = \Idno\Core\Idno::site()->currentPage()->getInput('body'); $this->tags = \Idno\Core\Idno::site()->currentPage()->getInput('tags'); $access = \Idno\Core\Idno::site()->currentPage()->getInput('access'); $this->setAccess($access); if ($time = \Idno\Core\Idno::site()->currentPage()->getInput('created')) { if ($time = strtotime($time)) { $this->created = $time; } } // Get photo if ($new) { if (!empty($_FILES['photo']['tmp_name'])) { if (\Idno\Entities\File::isImage($_FILES['photo']['tmp_name']) || \Idno\Entities\File::isSVG($_FILES['photo']['tmp_name'], $_FILES['photo']['name'])) { // Extract exif data so we can rotate if (is_callable('exif_read_data') && $_FILES['photo']['type'] == 'image/jpeg') { try { if (function_exists('exif_read_data')) { if ($exif = exif_read_data($_FILES['photo']['tmp_name'])) { $this->exif = base64_encode(serialize($exif)); // Yes, this is rough, but exif contains binary data that can not be saved in mongo } } } catch (\Exception $e) { $exif = false; } } else { $exif = false; } if ($photo = \Idno\Entities\File::createFromFile($_FILES['photo']['tmp_name'], $_FILES['photo']['name'], $_FILES['photo']['type'], true, true)) { $this->attachFile($photo); // Now get some smaller thumbnails, with the option to override sizes $sizes = \Idno\Core\Idno::site()->events()->dispatch('photo/thumbnail/getsizes', new \Idno\Core\Event(array('sizes' => array('large' => 800, 'medium' => 400, 'small' => 200)))); $eventdata = $sizes->data(); foreach ($eventdata['sizes'] as $label => $size) { $filename = $_FILES['photo']['name']; // Experiment: let's not save thumbnails for GIFs, in order to enable animated GIF posting. if ($_FILES['photo']['type'] != 'image/gif') { if ($thumbnail = \Idno\Entities\File::createThumbnailFromFile($_FILES['photo']['tmp_name'], "{$filename}_{$label}", $size, false)) { $varname = "thumbnail_{$label}"; $this->{$varname} = \Idno\Core\Idno::site()->config()->url . 'file/' . $thumbnail; $varname = "thumbnail_{$label}_id"; $this->{$varname} = substr($thumbnail, 0, strpos($thumbnail, '/')); } } } } else { \Idno\Core\Idno::site()->session()->addErrorMessage('Image wasn\'t attached.'); } } else { \Idno\Core\Idno::site()->session()->addErrorMessage('This doesn\'t seem to be an image ..'); } } else { \Idno\Core\Idno::site()->session()->addErrorMessage('We couldn\'t access your image. Please try again.'); return false; } } if ($this->save($new)) { \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\Idno::site()->template()->parseURLs($this->getTitle() . ' ' . $this->getDescription())); return true; } else { return false; } }
function deleteData() { \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\Idno::site()->template()->parseURLs($this->getTitle() . ' ' . $this->getDescription())); }
/** * Given the URL of a website, returns a single linked array containing the URL and title of a feed * (whether Microformats or RSS / Atom). The function will attempt to discover RSS and Atom feeds in * the page if this is an HTML site. Returns false if there is no feed. * @param $url * @return array|false */ function getFeedDetails($url) { if (!filter_var($url, FILTER_VALIDATE_URL)) { return false; } $client = new Webservice(); if ($result = $client->get($url)) { $feed = array(); if (!empty($result['content'])) { $feed['webmention'] = Webmention::supportsMentions($url, $result['content']); if ($html = @\DOMDocument::loadHTML($result['content'])) { $xpath = new \DOMXpath($html); $title = $xpath->query('//title')->item(0)->nodeValue; if ($xpath->query("//*[contains(concat(' ', @class, ' '), ' h-entry ')]")->length > 0) { $feed['type'] = 'mf2'; $feed['url'] = $url; if (!empty($title)) { $feed['title'] = $title; } return $feed; } if ($rss_url = $this->findXMLFeedURL($html)) { $feed['type'] = 'xml'; $feed['url'] = $rss_url; if (!empty($title)) { $feed['title'] = $title; } return $feed; } } if ($xml = @simplexml_load_string($result['content'])) { if (!empty($xml->rss->channel->item) || !empty($xml->feed) || !empty($xml->channel->item)) { $feed['type'] = 'xml'; $feed['url'] = $url; if (!empty($xml->rss->channel->title)) { $feed['title'] = $xml->rss->channel->title; } else { if (!empty($xml->channel->title)) { $feed['title'] = $xml->channel->title; } else { if (!empty($xml->title)) { $feed['title'] = $xml->title; } } } return $feed; } } } } return false; }
/** * Given content, returns the type of action you can respond with * @param $content * @return string */ static function getActionTypeFromHTML($content) { $share_type = 'comment'; if ($mf2 = \Idno\Core\Webmention::parseContent($content['content'])) { if (!empty($mf2['items'])) { foreach ($mf2['items'] as $item) { if (!empty($item['type'])) { if (in_array('h-entry', $item['type'])) { $share_type = 'reply'; } if (in_array('h-event', $item['type'])) { $share_type = 'rsvp'; } } } } } return $share_type; }
function getContent() { $this->gatekeeper(); $url = $this->getInput('share_url'); $title = $this->getInput('share_title'); $type = $this->getInput('share_type'); // Provide a hook to a URL shortener (TODO: Tidy this up when #237 is merged) $event = new \Idno\Core\Event(); $event->setResponse($url); \Idno\Core\site()->events()->dispatch('url/shorten', $event); $url = $event->response(); if (!in_array($type, ['note', 'reply', 'rsvp', 'like'])) { $share_type = 'note'; if ($content = \Idno\Core\Webservice::get($url)) { if ($mf2 = \Idno\Core\Webmention::parseContent($content['content'])) { if (!empty($mf2['items'])) { foreach ($mf2['items'] as $item) { if (!empty($item['type'])) { if (in_array('h-entry', $item['type'])) { $share_type = 'reply'; } if (in_array('h-event', $item['type'])) { $share_type = 'rsvp'; } } } } } } } else { $share_type = $type; } $content_type = \Idno\Common\ContentType::getRegisteredForIndieWebPostType($share_type); $hide_nav = false; if ($this->getInput('via') == 'ff_social') { $hide_nav = true; } if (!empty($content_type)) { if ($page = \Idno\Core\site()->getPageHandler('/' . $content_type->camelCase($content_type->getEntityClassName()) . '/edit')) { if ($share_type == 'note') { $page->setInput('body', $title . ' ' . $url); } else { $page->setInput('url', $url); if (substr_count($url, 'twitter.com')) { preg_match("|https?://(www\\.)?twitter\\.com/(#!/)?@?([^/]*)|", $url, $matches); if (!empty($matches[3])) { $page->setInput('body', '@' . $matches[3] . ' '); } } } $page->setInput('hidenav', $hide_nav); $page->setInput('sharing', true); $page->setInput('share_type', $share_type); $page->get(); } } else { $t = \Idno\Core\site()->template(); $body = $t->__(['share_type' => $share_type, 'content_type' => $content_type, 'sharing' => true])->draw('entity/share'); $t->__(['title' => 'Share', 'body' => $body, 'hidenav' => $hide_nav])->drawPage(); } }
function post() { parse_str(trim(file_get_contents("php://input")), $vars); // Check that both source and target are non-empty if (!empty($vars['source']) && !empty($vars['target']) && $vars['source'] != $vars['target']) { $source = $vars['source']; $target = $vars['target']; // Remove anchors from target URL, but save them to '#' input so we can still reference them later if (strpos($target, '#')) { list($target, $fragment) = explode('#', $target, 2); if (!empty($fragment)) { $this->setInput('#', $fragment); } } // Get the page handler for target if ($page = \Idno\Core\Idno::site()->getPageHandler($target)) { // First of all, make sure the target page isn't the source page. Let's not webmention ourselves! $webmention_ok = true; if (\Idno\Common\Entity::isLocalUUID($source)) { if ($source_page = \Idno\Core\Idno::site()->getPageHandler($source)) { if ($source_page == $page) { $webmention_ok = false; } } } // Check that source exists, parse it for mf2 content, // and ensure that it genuinely mentions this page if ($webmention_ok) { if ($source_content = \Idno\Core\Webservice::get($source)) { if (substr_count($source_content['content'], $target) || $source_content['response'] == 410) { $source_mf2 = \Idno\Core\Webmention::parseContent($source_content['content'], $source); // Set source and target information as input variables $page->setPermalink(); if ($page->webmentionContent($source, $target, $source_content, $source_mf2)) { $this->setResponse(202); // Webmention received a-ok. exit; } else { $error = 'target_not_supported'; $error_text = 'This is not webmentionable.'; } } else { $error = 'no_link_found'; $error_text = 'The source URI does not contain a link to the target URI.'; \Idno\Core\Idno::site()->logging->warning('No link from ' . $source . ' to ' . $target); } } else { $error = 'source_not_found'; $error_text = 'The source content for ' . $source . ' could not be obtained.'; \Idno\Core\Idno::site()->logging->warning('No content from ' . $source); } } else { $error = 'target_not_supported'; $error_text = 'A page can\'t webmention itself.'; } } else { $error = 'target_not_found'; $error_text = 'The target page ' . $target . ' does not exist.'; \Idno\Core\Idno::site()->logging()->error('Could not find handler for ' . $target); } } $this->setResponse(400); // Webmention failed. if (empty($error)) { $error = 'unknown_error'; $error_text = 'Not all the required webmention variables were set.'; } echo json_encode(array('error' => $error, 'error_text' => $error_text)); }
/** * A webmention to our profile page means someone mentioned us. */ function webmentionContent($source, $target, $source_response, $source_mf2) { Idno::site()->logging()->info("received user mention from {$source} to {$target}"); if (empty($this->arguments)) { Idno::site()->logging()->debug("could not process user mention, no pagehandler arguments"); return false; } $user = User::getByHandle($this->arguments[0]); if (empty($user)) { Idno::site()->logging()->debug('could not process user mention, no user for handle ' . $this->arguments[0]); return false; } Idno::site()->logging()->debug("found target user {$user->getHandle()}"); // if this is anything other than a normal mention (e.g. a delete), accept the wm, but do nothing if ($source_response['response'] !== 200) { return true; } $title = Webmention::getTitleFromContent($source_response['content'], $source); $mention = ['permalink' => $source, 'title' => $title]; // look for the first and only h-entry or h-event on the page $entry = Webmention::findRepresentativeHEntry($source_mf2, $source, ['h-entry', 'h-event']); $card = Webmention::findAuthorHCard($source_mf2, $source, $entry); // try to get some more specific details of the mention from mf2 content if ($entry) { if (!empty($entry['properties']['url'])) { $mention['permalink'] = $entry['properties']['url'][0]; } if (!empty($entry['properties']['content'])) { $content = $entry['properties']['content'][0]; $mention['content'] = Idno::site()->template()->sanitize_html(is_array($content) ? $content['html'] : $content); } } $sender_url = false; if ($card) { if (!empty($card['properties']['url'])) { $sender_url = $card['properties']['url'][0]; $mention['owner_url'] = $card['properties']['url'][0]; } if (!empty($card['properties']['name'])) { $mention['owner_name'] = $card['properties']['name'][0]; } } $message = 'You were mentioned'; if (isset($mention['owner_name'])) { $message .= ' by ' . $mention['owner_name']; } $message .= ' on ' . parse_url($mention['permalink'], PHP_URL_HOST); $notif = new Notification(); if ($notif->setNotificationKey(['mention', $user->getUUID(), $source, $target])) { $notif->setOwner($user); $notif->setMessage($message); $notif->setMessageTemplate('content/notification/mention'); $notif->setActor($sender_url); $notif->setVerb('mention'); $notif->setObject($mention); $notif->setTarget($user); $notif->save(); $user->notify($notif); } else { \Idno\Core\Idno::site()->logging()->debug("ignoring duplicate notification", ['source' => $source, 'target' => $target, 'user' => $user->getHandle()]); } return true; }
/** * Saves changes to this object based on user input * @return bool */ function saveDataFromInput() { if (empty($this->_id)) { $new = true; } else { $new = false; } $this->title = \Idno\Core\site()->currentPage()->getInput('title'); $this->body = \Idno\Core\site()->currentPage()->getInput('body'); $this->tags = \Idno\Core\site()->currentPage()->getInput('tags'); $this->setAccess('PUBLIC'); if ($time = \Idno\Core\site()->currentPage()->getInput('created')) { if ($time = strtotime($time)) { $this->created = $time; } } // Get photo if ($new) { if (!empty($_FILES['photo']['tmp_name'])) { if (\Idno\Entities\File::isImage($_FILES['photo']['tmp_name'])) { if ($photo = \Idno\Entities\File::createFromFile($_FILES['photo']['tmp_name'], $_FILES['photo']['name'], $_FILES['photo']['type'], true)) { $this->attachFile($photo); // Now get some smaller thumbnails, with the option to override sizes $sizes = \Idno\Core\site()->events()->dispatch('photo/thumbnail/getsizes', new \Idno\Core\Event(array('sizes' => ['large' => 800, 'medium' => 400, 'small' => 200]))); foreach ($sizes->data()['sizes'] as $label => $size) { $filename = $_FILES['photo']['name']; // Experiment: let's not save thumbnails for GIFs, in order to enable animated GIF posting. if ($_FILES['photo']['type'] != 'image/gif') { if ($thumbnail = \Idno\Entities\File::createThumbnailFromFile($_FILES['photo']['tmp_name'], "{$filename}_{$label}", $size)) { $varname = "thumbnail_{$label}"; $this->{$varname} = \Idno\Core\site()->config()->url . 'file/' . $thumbnail; $varname = "thumbnail_{$label}_id"; $this->{$varname} = substr($thumbnail, 0, strpos($thumbnail, '/')); } } } } else { \Idno\Core\site()->session()->addMessage('Image wasn\'t attached.'); } } else { \Idno\Core\site()->session()->addMessage('This doesn\'t seem to be an image ..'); } } else { \Idno\Core\site()->session()->addMessage('We couldn\'t access your image. Please try again.'); return false; } } if ($this->save()) { if ($new) { $this->addToFeed(); } // Add it to the Activity Streams feed \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\site()->template()->parseURLs($this->getTitle() . ' ' . $this->getDescription())); return true; } else { return false; } }
/** * Add webmentions as annotations based on Microformats 2 data * * @param string $source The source URL * @param string $target The target URL (i.e., the page on this site that was pinged) * @param string $source_content The source page's HTML * @param array $source_mf2 Parsed Microformats 2 content from $source * @return bool Success */ function addWebmentions($source, $target, $source_content, $source_mf2) { if ($source_content['response'] == 410) { $this->removeAnnotation($source); $this->save(); } else { if (!empty($source_mf2) && !empty($source_mf2['items']) && is_array($source_mf2['items'])) { // At this point, we don't know who owns the page or what the content is. // First, we'll initialize some variables that we're interested in filling. $mentions = array('owner' => array(), 'mentions' => array()); // Content owner and usable webmention items $return = true; // Return value; // Get the page title from the source content $title = $source; try { $dom = new \DOMDocument(); $dom->loadHTML($source_content['content']); $xpath = new \DOMXPath($dom); if ($xpath_title = $xpath->query('//title')->item(0)->textContent) { $title = $xpath_title; } } catch (\Exception $e) { // Do nothing } // And then let's cycle through them! // A first pass for overall owner ... foreach ($source_mf2['items'] as $item) { // Figure out what kind of Microformats 2 item we have if (!empty($item['type']) && is_array($item['type'])) { foreach ($item['type'] as $type) { switch ($type) { case 'h-card': if (!empty($item['properties'])) { if (!empty($item['properties']['name'])) { $mentions['owner']['name'] = $item['properties']['name'][0]; } if (!empty($item['properties']['url'])) { $mentions['owner']['url'] = $item['properties']['url'][0]; } if (!empty($item['properties']['photo'])) { //$mentions['owner']['photo'] = $item['properties']['photo'][0]; $tmpfname = tempnam(sys_get_temp_dir(), 'webmention_avatar'); file_put_contents($tmpfname, \Idno\Core\Webservice::file_get_contents($item['properties']['photo'][0])); $name = md5($item['properties']['url'][0]); // TODO: Don't update the cache image for every webmention if ($icon = \Idno\Entities\File::createThumbnailFromFile($tmpfname, $name, 300)) { $mentions['owner']['photo'] = \Idno\Core\Idno::site()->config()->url . 'file/' . (string) $icon; } else { if ($icon = \Idno\Entities\File::createFromFile($tmpfname, $name)) { $mentions['owner']['photo'] = \Idno\Core\Idno::site()->config()->url . 'file/' . (string) $icon; } } unlink($tmpfname); } } break; } if (!empty($mentions['owner'])) { break; } } } } // And now a second pass for per-item owners and mentions ... foreach ($source_mf2['items'] as $item) { $mentions = $this->addWebmentionItem($item, $mentions, $source, $target, $title); if (!empty($item['type']) && is_array($item['type'])) { } } if (!empty($mentions['mentions']) && !empty($mentions['owner']) && !empty($mentions['owner']['url'])) { if (empty($mentions['owner']['photo'])) { $mentions['owner']['photo'] = ''; } if (empty($mentions['owner']['url'])) { $mentions['owner']['url'] = $source; } if (empty($mentions['owner']['name'])) { $mentions['owner']['name'] = 'Web user'; } if (empty($mentions['title'])) { $mentions['title'] = ''; } $this->removeAnnotation($source); foreach ($mentions['mentions'] as $mention) { if (!empty($mention['url'])) { $permalink = implode('', $mention['url']); } else { $permalink = $source; } // Special exemption for bridgy if (strpos($source, 'https://brid-gy.appspot.com/') !== false && in_array($mention['type'], array('like', 'share', 'rsvp'))) { $permalink = \Idno\Core\Idno::site()->template()->getURLWithVar('known_from', $source, implode('', $mention['url'])); } if (!$this->addAnnotation($mention['type'], $mentions['owner']['name'], $mentions['owner']['url'], $mentions['owner']['photo'], $mention['content'], $permalink, $mention['created'], $mention['title'])) { $return = false; } } $this->save(); if ($return) { if ($this->isReply()) { $webmentions = new Webmention(); if ($reply_urls = $this->getReplyToURLs()) { foreach ($reply_urls as $reply_url) { $webmentions->sendWebmentionPayload($this->getDisplayURL(), $reply_url); } } } } } return $return; } } return true; // There were no IndieWeb webmentions to add }
function getContent() { $this->gatekeeper(); $url = $this->getInput('share_url', $this->getInput('url')); $title = $this->getInput('share_title', $this->getInput('title')); $type = $this->getInput('share_type'); $syndicatedto = []; // remove cruft added by mobile apps if (preg_match('~\\b(?:f|ht)tps?://[^\\s]+\\b~i', $url, $matches)) { $url = $matches[0]; } $event = new \Idno\Core\Event(); $event->setResponse($url); \Idno\Core\Idno::site()->events()->dispatch('url/shorten', $event); $short_url = $event->response(); if (!$type || !\Idno\Common\ContentType::getRegisteredForIndieWebPostType($type)) { $share_type = 'note'; // Probe to see if this is something we can MF2 parse, before we do $headers = []; if ($head = \Idno\Core\Webservice::head($url)) { $headers = http_parse_headers($head['header']); } // Only MF2 Parse supported types if (isset($headers['Content-Type']) && preg_match('/text\\/(html|plain)+/', $headers['Content-Type'])) { if ($response = \Idno\Core\Webservice::get($url)) { if ($mf2 = \Idno\Core\Webmention::parseContent($response['content'])) { if (!empty($mf2['items'])) { foreach ($mf2['items'] as $item) { if (!empty($item['type'])) { if (in_array('h-entry', $item['type'])) { $share_type = 'reply'; } if (in_array('h-event', $item['type'])) { $share_type = 'rsvp'; } } } } } $syndicatedto = \Idno\Core\Webmention::addSyndicatedReplyTargets($url, $syndicatedto, $response); } } } else { $share_type = $type; } $content_type = \Idno\Common\ContentType::getRegisteredForIndieWebPostType($share_type); $hide_nav = false; if ($this->getInput('via') == 'ff_social') { $hide_nav = true; } if (!empty($content_type)) { if ($page = \Idno\Core\Idno::site()->getPageHandler($content_type->getEditURL())) { if ($share_type == 'note') { $page->setInput('body', $title . ' ' . $short_url); } else { $page->setInput('short-url', $short_url); $page->setInput('url', $url); $page->setInput('syndicatedto', $syndicatedto); // prefill the @-name of the person we're replying to $atusers = []; foreach (array_merge((array) $url, (array) $syndicatedto) as $tweeturl) { if (strstr($tweeturl, 'twitter.com') !== false) { if (preg_match("|https?://([a-z]+\\.)?twitter\\.com/(#!/)?@?([^/]*)|", $tweeturl, $matches) && !empty($matches[3])) { $atusers[] = '@' . $matches[3]; } if (preg_match_all("|@([^\\s^\\)]+)|", $title, $matches)) { $atusers = array_merge($atusers, $matches[0]); } } } if ($atusers) { // See if one of your registered twitter handles is present, if so remove it. $user = \Idno\Core\Idno::site()->session()->currentUser(); if (!empty($user->twitter) && is_array($user->twitter)) { $me = []; foreach ($user->twitter as $k => $v) { $me[] = '@' . $k; } $atusers = array_diff($atusers, $me); } } if ($atusers) { $atusers = array_unique($atusers); $page->setInput('body', implode(' ', $atusers) . ' '); } } $page->setInput('hidenav', $hide_nav); $page->setInput('sharing', true); $page->setInput('share_type', $share_type); $page->get(); } } else { $t = \Idno\Core\Idno::site()->template(); $body = $t->__(array('share_type' => $share_type, 'content_type' => $content_type, 'sharing' => true))->draw('entity/share'); $t->__(array('title' => 'Share', 'body' => $body, 'hidenav' => $hide_nav))->drawPage(); } }
function getContent() { $this->gatekeeper(); $url = $this->getInput('share_url', $this->getInput('url')); $title = $this->getInput('share_title', $this->getInput('title')); $type = $this->getInput('share_type'); $event = new \Idno\Core\Event(); $event->setResponse($url); \Idno\Core\site()->events()->dispatch('url/shorten', $event); $short_url = $event->response(); if (!in_array($type, array('note', 'reply', 'rsvp', 'like', 'bookmark'))) { $share_type = 'note'; if ($content = \Idno\Core\Webservice::get($url)) { if ($mf2 = \Idno\Core\Webmention::parseContent($content['content'])) { if (!empty($mf2['items'])) { foreach ($mf2['items'] as $item) { if (!empty($item['type'])) { if (in_array('h-entry', $item['type'])) { $share_type = 'reply'; } if (in_array('h-event', $item['type'])) { $share_type = 'rsvp'; } } } } } } } else { $share_type = $type; } $content_type = \Idno\Common\ContentType::getRegisteredForIndieWebPostType($share_type); $hide_nav = false; if ($this->getInput('via') == 'ff_social') { $hide_nav = true; } if (!empty($content_type)) { if ($page = \Idno\Core\site()->getPageHandler('/' . $content_type->camelCase($content_type->getEntityClassName()) . '/edit')) { if ($share_type == 'note') { $page->setInput('body', $title . ' ' . $short_url); } else { $page->setInput('short-url', $short_url); $page->setInput('url', $url); if (substr_count($url, 'twitter.com')) { $atusers = []; preg_match("|https?://([a-z]+\\.)?twitter\\.com/(#!/)?@?([^/]*)|", $url, $matches); if (!empty($matches[3])) { $atusers[] = '@' . $matches[3]; // $page->setInput('body', '@' . $matches[3] . ' '); } if (preg_match_all("|@([^\\s^\\)]+)|", $title, $matches)) { $atusers = array_merge($atusers, $matches[0]); } // See if one of your registered twitter handles is present, if so remove it. $user = \Idno\Core\site()->session()->currentUser(); if (!empty($user->twitter) && is_array($user->twitter)) { $me = []; foreach ($user->twitter as $k => $v) { $me[] = "@{$k}"; } $atusers = array_diff($atusers, $me); } $atusers = array_unique($atusers); $page->setInput('body', implode(' ', $atusers) . ' '); } } $page->setInput('hidenav', $hide_nav); $page->setInput('sharing', true); $page->setInput('share_type', $share_type); $page->get(); } } else { $t = \Idno\Core\site()->template(); $body = $t->__(array('share_type' => $share_type, 'content_type' => $content_type, 'sharing' => true))->draw('entity/share'); $t->__(array('title' => 'Share', 'body' => $body, 'hidenav' => $hide_nav))->drawPage(); } }
/** * Saves changes to this object based on user input * @return bool */ function saveDataFromInput() { if (empty($this->_id)) { $new = true; } else { $new = false; } if ($new) { if (!\Idno\Core\Idno::site()->triggerEvent("file/upload", [], true)) { return false; } } $this->title = \Idno\Core\Idno::site()->currentPage()->getInput('title'); $this->body = \Idno\Core\Idno::site()->currentPage()->getInput('body'); $this->tags = \Idno\Core\Idno::site()->currentPage()->getInput('tags'); $access = \Idno\Core\Idno::site()->currentPage()->getInput('access'); $this->setAccess($access); if ($time = \Idno\Core\Idno::site()->currentPage()->getInput('created')) { if ($time = strtotime($time)) { $this->created = $time; } } // This flag will tell us if it's safe to save the object later on if ($new) { $ok = false; } else { $ok = true; } // Get media if ($new) { // This is awful, but unfortunately, browsers can't be trusted to send the right mimetype. $ext = pathinfo($_FILES['media']['name'], PATHINFO_EXTENSION); if (!empty($ext)) { if (in_array($ext, array('mp4', 'mov', 'webm', 'ogg', 'mpeg', 'mp3', 'vorbis'))) { $media_file = $_FILES['media']; if ($media_file['type'] == 'application/octet-stream') { switch ($ext) { case 'mp4': $media_file['type'] = 'video/mp4'; break; case 'mov': $media_file['type'] = 'video/mov'; break; case 'webm': $media_file['type'] = 'video/webm'; break; case 'ogg': $media_file['type'] = 'audio/ogg'; break; case 'mp3': $media_file['type'] = 'audio/mpeg'; break; case 'mpeg': $media_file['type'] = 'video/mpeg'; break; case 'ogv': $media_file['type'] = 'audio/ogv'; break; } } $this->media_type = $media_file['type']; if ($media = \Idno\Entities\File::createFromFile($media_file['tmp_name'], $media_file['name'], $media_file['type'], true)) { $this->attachFile($media); $ok = true; } else { \Idno\Core\Idno::site()->session()->addErrorMessage('Media wasn\'t attached.'); } } else { \Idno\Core\Idno::site()->session()->addErrorMessage('This doesn\'t seem to be a media file .. ' . $_FILES['media']['type']); } } else { \Idno\Core\Idno::site()->session()->addErrorMessage('We couldn\'t access your media. Please try again.'); return false; } } // If a media file wasn't attached, don't save the file. if (!$ok) { return false; } if ($this->save($new)) { \Idno\Core\Webmention::pingMentions($this->getURL(), \Idno\Core\Idno::site()->template()->parseURLs($this->getTitle() . ' ' . $this->getDescription())); return true; } else { return false; } }
/** * Add webmentions as annotations based on Microformats 2 data * * @param string $source The source URL * @param string $target The target URL (i.e., the page on this site that was pinged) * @param array $source_response The Webservice response from fetching the source page * @param array $source_mf2 Parsed Microformats 2 content from $source * @return bool Success */ function addWebmentions($source, $target, $source_response, $source_mf2) { if ($source_response['response'] == 410) { $this->removeAnnotation($source); $this->save(); return true; } $return = false; if (!empty($source_mf2) && !empty($source_mf2['items']) && is_array($source_mf2['items'])) { // At this point, we don't know who owns the page or what the content is. // First, we'll initialize some variables that we're interested in filling. $mentions = array('owner' => array(), 'mentions' => array()); // Content owner and usable webmention items // Get the page title from the source content $title = Webmention::getTitleFromContent($source_response['content'], $source); // primary h-entry on the page $primary = Webmention::findRepresentativeHEntry($source_mf2, $source, ['h-entry']); $author = Webmention::findAuthorHCard($source_mf2, $source, $primary); // Convert the h-entry to one or more mentions if ($primary) { $mentions = $this->addWebmentionItem($primary, $author, $mentions, $source, $target, $title); } if (!empty($mentions['mentions']) && !empty($mentions['owner'])) { $return = true; if (empty($mentions['owner']['photo'])) { $mentions['owner']['photo'] = ''; } if (empty($mentions['owner']['url'])) { $mentions['owner']['url'] = $source; } if (empty($mentions['owner']['name'])) { $mentions['owner']['name'] = 'Web user'; } if (empty($mentions['title'])) { $mentions['title'] = ''; } $this->removeAnnotation($source); foreach ($mentions['mentions'] as $mention) { if (!empty($mention['url'])) { $permalink = $mention['url'][0]; //implode('', $mention['url']); } else { $permalink = $source; } // Special exemption for bridgy if (strpos($source, 'https://brid-gy.appspot.com/') !== false && in_array($mention['type'], array('like', 'share', 'rsvp'))) { $permalink = \Idno\Core\Idno::site()->template()->getURLWithVar('known_from', $source, implode('', $mention['url'])); } if (!$this->addAnnotation($mention['type'], $mentions['owner']['name'], $mentions['owner']['url'], $mentions['owner']['photo'], $mention['content'], $permalink, $mention['created'], $mention['title'])) { $return = false; } } $this->save(); if ($return && $this->isReply()) { if ($reply_urls = $this->getReplyToURLs()) { foreach ($reply_urls as $reply_url) { Webmention::sendWebmentionPayload($this->getDisplayURL(), $reply_url); } } } } } return $return; }