<?php } else { ?> <div class="empty-property-block"> <p>Add your Email! <code class="pull-right"><a rel="me" class="u-email">…</a></code></p> </div> <?php } ?> <p class="property-block-name">Note</p> <?php if (Mf2\hasProp($hCard, 'note')) { ?> <p><?php echo Mf2\getProp($hCard, 'note'); ?> </p> <?php } else { ?> <div class="empty-property-block"> <p>Add a note/bio! <code class="pull-right"><p class="p-note">…</p></code></p> </div> <?php } ?> </div> <?php }
function processHEntry($hEntry, $mf, $url, $resolveRelationships = true, Guzzle\Http\ClientInterface $client = null, $purifier = null) { if ($client === null) { $client = new Guzzle\Http\Client(); } if ($purifier === null) { $purifier = function ($value) { return $value; }; } // Use comment-presentation algorithm to clean up. $cleansed = comments\parse($hEntry); $referencedPosts = []; $referencedPostUrls = []; // Used internally to keep track of what referenced posts have been processed already. $indexedContent = M\getPlaintext($hEntry, 'content', $cleansed['text']); $displayContent = $purifier(M\getHtml($hEntry, 'content')); $cleansed['content'] = $indexedContent; $cleansed['display_content'] = $displayContent; // Handle all datetime cases, as per http://indiewebcamp.com/h-entry#How_to_consume_h-entry try { $published = new DateTime($cleansed['published']); $utcPublished = clone $published; $utcPublished->setTimezone(new DateTimeZone('UTC')); } catch (Exception $e) { $published = $utcPublished = false; } $inTheFuture = $utcPublished > new DateTime(null, new DateTimeZone('UTC')); // DateTime() accepts “false” as a constructor param for some reason. if (!$published and !$cleansed['published'] or $utcPublished > new DateTime(null, new DateTimeZone('UTC'))) { // If there’s absolutely no datetime, our best guess has to be “now”. // Additional heuristics could be used in the bizarre case of having a feed where an item without datetime is // published in between two items with datetimes, allowing us to guess the published datetime is between the two, // but until that actually happens it’s not worth coding for. $cleansed['published'] = gmdate('c'); $utcPublished = new DateTime(null, new DateTimeZone('UTC')); } else { // “published” is given and parses correctly, into $published. // Currently it’s not trivial to figure out if a given datetime is floating or not, so assume that the timezone // given here is correct for the moment. When this can be determined, follow http://indiewebcamp.com/datetime#implying_timezone_from_webmentions } // There’s some case causing $utcPublished to still be false and I can’t be bothered to debug it right now, so here’s a fix. if ($utcPublished === false) { $utcPublished = new DateTime(null, new DateTimeZone('UTC')); } // Store a string representation of published to be indexed+queried upon. $cleansed['published_utc'] = $utcPublished->format(DateTime::W3C); if (M\hasProp($hEntry, 'photo')) { $cleansed['photo'] = $purifier(M\getHtml($hEntry, 'photo')); } if (M\hasProp($hEntry, 'logo')) { $cleansed['logo'] = $purifier(M\getHtml($hEntry, 'logo')); } // For every post this post has a relation (in-reply-to, repost-of, like-of etc.), fetch and resolve that URL, // index it as it’s own post (if it doesn’t already exist) and store only a reference to it here. $references = ['in-reply-to' => [], 'like-of' => [], 'repost-of' => []]; foreach ($references as $relation => $_) { $refUrls = []; // These will be feed pages not permalink pages so cannot check rels, only microformats properties. if (M\hasProp($hEntry, $relation)) { foreach ($hEntry['properties'][$relation] as $value) { if (is_string($value)) { $refUrls[] = $value; } elseif (is_array($value) and isset($value['html'])) { // e-* properties unlikely to be URLs but try all the same. $refUrls[] = $value['value']; } elseif (M\isMicroformat($value)) { if (M\hasProp($value, 'url')) { $refUrls[] = M\getProp($value, 'url'); } elseif (M\hasProp($value, 'uid')) { $refUrls[] = M\getProp($value, 'uid'); } } else { // If this happens, the microformats parsing spec has changed. Currently do nothing as we don’t know how to interpret this. } } } if ($resolveRelationships) { foreach ($refUrls as $refUrl) { try { $resp = $client->get($refUrl)->send(); $refResolvedUrl = $resp->getEffectiveUrl(); $refMf = Mf2\parse($resp->getBody(1), $refResolvedUrl); $refHEntries = M\findMicroformatsByType($refMf, 'h-entry'); $relatedUrl = $refResolvedUrl; if (count($refHEntries) > 0) { $refHEntry = $refHEntries[0]; $refSearchUrl = M\hasProp($refHEntry, 'url') ? M\getProp($refHEntry, 'url') : $refResolvedUrl; if (!in_array($refSearchUrl, $referencedPostUrls)) { list($refCleansed, $_) = processHEntry($refHEntry, $refMf, $refResolvedUrl, false, $client, $purifier); $referencedPosts[] = $refCleansed; $referencedPostUrls[] = $refSearchUrl; $relatedUrl = $refSearchUrl; } } $references[$relation][] = $relatedUrl; } catch (Guzzle\Common\Exception\GuzzleException $e) { $references[$relation][] = $refUrl; } } } else { // If we’re not resolving relationships, the most accurate data we have is the data given already. $references[$relation] = $refUrls; } // Now we have the best possible list of URLs, attach it to $cleansed. $cleansed[$relation] = array_unique($references[$relation]); } if (!M\hasProp($hEntry, 'author') or !M\isMicroformat($hEntry['properties']['author'][0])) { // No authorship data given, we need to find the author! // TODO: proper /authorship implementation. // TODO: wrap proper /authorship implementation in layer which does purification, simplification, fallback. $potentialAuthor = M\getAuthor($hEntry, $mf, $url); if (M\isMicroformat($potentialAuthor)) { $cleansed['author'] = flattenHCard($potentialAuthor, $url); } elseif (!empty($mf['rels']['author'])) { // TODO: look in elasticsearch index for a person with the first rel-author URL then fall back to fetching. // Fetch the first author URL and look for a representative h-card there. $relAuthorMf = Mf2\fetch($mf['rels']['author'][0]); $relAuthorHCards = M\findMicroformatsByType($relAuthorMf, 'h-card'); foreach ($relAuthorHCards as $raHCard) { $relMes = @($relAuthorMf['rels']['me'] ?: []); if ((M\getProp($raHCard, 'url') === M\getProp($raHCard, 'url')) === $mf['rels']['author'][0]) { $cleansed['author'] = flattenHCard($raHCard, $mf['rels']['author'][0]); } elseif (M\hasProp($raHCard, 'url') and count(array_intersect($raHCard['properties']['url'], $relMes)) > 0) { $cleansed['author'] = flattenHCard($raHCard, $mf['rels']['author'][0]); } } } // If after all that there’s still no authorship data, fake some. if ($cleansed['author']['name'] === false) { $cleansed['author'] = flattenHCard(['properties' => []], $url); try { $response = $client->head("{$cleansed['author']['url']}/favicon.ico")->send(); if (strpos($response->getHeader('content-type'), 'image') !== false) { // This appears to be a valid image! $cleansed['author']['photo'] = $response->getEffectiveUrl(); } } catch (Guzzle\Common\Exception\GuzzleException $e) { // No photo fallback could be found. } } } // TODO: this will be M\getLocation when it’s ported to the other library. if (($location = getLocation($hEntry)) !== null) { $cleansed['location'] = $location; // TODO: do additional reverse lookups of address details if none are provided. if (!empty($location['latitude']) and !empty($location['longitude'])) { // If this is a valid point, add a point with mashed names for elasticsearch to index. $cleansed['location_point'] = ['lat' => $location['latitude'], 'lon' => $location['longitude']]; } } // TODO: figure out what other properties need storing/indexing, and whether anything else needs mashing for // elasticsearch to index more easily. return [$cleansed, $referencedPosts]; }
<p>Add a publication datetime!</p> <p><code><time class="dt-published" datetime="YYYY-MM-DD HH:MM:SS">The Date</time></code></p> </div> <?php } ?> <p class="property-block-name">URL <?php if (Mf2\hasProp($hEntry, 'url')) { ?> <a href="<?php echo Mf2\getProp($hEntry, 'url'); ?> "><?php echo Mf2\getProp($hEntry, 'url'); ?> </a></p> <?php } else { ?> </p><p class="empty-property-block">Add a URL! <code class="pull-right"><a class="u-url" href="…">…</a></code></p> <?php } ?> <p class="property-block-name">Syndicated Copies</p> <?php if (Mf2\hasProp($hEntry, 'syndication')) { ?> <ul>
} $hEntries = Mf2\findMicroformatsByType($mfs, 'h-entry'); if (count($hEntries) > 0) { $hEntry = $hEntries[0]; if (Mf2\hasProp($hEntry, 'in-reply-to')) { $postType = 'reply'; } elseif (Mf2\hasProp($hEntry, 'like-of')) { $postType = 'like'; } elseif (Mf2\hasProp($hEntry, 'repost-of')) { $postType = 'repost'; } else { $postType = 'post'; } // Determine the state of the post name. $content = Mf2\hasProp($hEntry, 'content') ? Mf2\getProp($hEntry, 'content') : (isset($hEntry['value']) ? $hEntry['value'] : null); $parsedName = Mf2\getProp($hEntry, 'name'); $nameState = null; if ($content != null and $content != $parsedName) { $nameState = mb_strlen($parsedName) > mb_strlen($content) ? 'invalid' : 'valid'; } } else { $postType = $hEntry = $nameState = null; } return crossOriginResponse(render('validate-h-entry.html', array('showResult' => true, 'postType' => $postType, 'hEntry' => $hEntry, 'nameState' => $nameState, 'url' => htmlspecialchars($url)))); } }); $app->get('/send-webmentions/', function (Http\Request $request) { return render('send-webmentions.html', array('url' => $request->query->get('url', ''))); }); $app->post('/send-webmentions/', function (Http\Request $request) { ob_start();
$testSuite = $testSuites[0]; echo "\n" . Mf2\getProp($testSuite, 'name') . "\n"; echo "============================\n"; foreach ($testSuite['properties']['x-test-case'] as $testCase) { echo "\n"; $params = $testCase['properties']['x-parameter']; $meUrl = array_shift($params); if (count($params) === 0) { $redirects = mockFollowOneRedirect(array(null)); } else { $redirects = mockFollowOneRedirect($params); } list($expectedUrl, $expectedSecure) = $testCase['properties']['x-expected-result']; $expectedSecure = $expectedSecure === 'true'; // Begin testing $meUrl = normaliseUrl($meUrl); list($url, $secure, $previous) = relMeDocumentUrl($meUrl, $redirects); // end testing if ($url === $expectedUrl and $secure === $expectedSecure) { echo "(pass) " . Mf2\getProp($testCase, 'name') . "\n"; } else { echo "(fail) " . Mf2\getProp($testCase, 'name') . "\n"; if ($url != $expectedUrl) { echo "- {$url} should match {$expectedUrl}\n"; } if ($secure != $expectedSecure) { echo "- {$secure} didn’t match {$expectedSecure}\n"; } } } }