note = $note; $this->source = $source; $this->guzzle = $guzzle ?? new Client(); } /** * Execute the job. * * @param \Jonnybarnes\WebmentionsParser\Parser $parser * @return void */ public function handle(Parser $parser) { $sourceURL = parse_url($this->source); $baseURL = $sourceURL['scheme'] . '://' . $sourceURL['host']; $remoteContent = $this->getRemoteContent($this->source); if ($remoteContent === null) { throw new RemoteContentNotFoundException; } $microformats = Mf2\parse($remoteContent, $baseURL); $webmentions = WebMention::where('source', $this->source)->get(); foreach ($webmentions as $webmention) { //check webmention still references target //we try each type of mention (reply/like/repost) if ($webmention->type == 'in-reply-to') { if ($parser->checkInReplyTo($microformats, $this->note->longurl) == false) { //it doesn't so delete $webmention->delete(); return; } //webmenion is still a reply, so update content $microformats = $this->filterHTML($microformats); $this->dispatch(new SaveProfileImage($microformats)); $webmention->mf2 = json_encode($microformats); $webmention->save(); return; } if ($webmention->type == 'like-of') { if ($parser->checkLikeOf($microformats, $note->longurl) == false) { //it doesn't so delete $webmention->delete(); return; } //note we don't need to do anything if it still is a like } if ($webmention->type == 'repost-of') { if ($parser->checkRepostOf($microformats, $note->longurl) == false) { //it doesn't so delete $webmention->delete(); return; } //again, we don't need to do anything if it still is a repost } }//foreach //no wemention in db so create new one $webmention = new WebMention(); $type = $parser->getMentionType($microformats); //throw error here? $this->dispatch(new SaveProfileImage($microformats)); $microformats = $this->filterHTML($microformats); $webmention->source = $this->source; $webmention->target = $this->note->longurl; $webmention->commentable_id = $this->note->id; $webmention->commentable_type = 'App\Note'; $webmention->type = $type; $webmention->mf2 = json_encode($microformats); $webmention->save(); } /** * Retreive the remote content from a URL, and caches the result. * * @param string The URL to retreive content from * @return string|null The HTML from the URL (or null if error) */ private function getRemoteContent($url) { try { $response = $this->guzzle->request('GET', $url); } catch (RequestException $e) { return; } $html = (string) $response->getBody(); $path = storage_path() . '/HTML/' . $this->createFilenameFromURL($url); $parts = explode('/', $path); $name = array_pop($parts); $dir = implode('/', $parts); if (! is_dir($dir)) { mkdir($dir, 0755, true); } file_put_contents("$dir/$name", $html); return $html; } /** * Create a file path from a URL. This is used when caching the HTML * response. * * @param string The URL * @return string The path name */ private function createFilenameFromURL($url) { $url = str_replace(['https://', 'http://'], ['', ''], $url); if (substr($url, -1) == '/') { $url = $url . 'index.html'; } return $url; } /** * Filter the HTML in a reply webmention. * * @param array The unfiltered microformats * @return array The filtered microformats */ private function filterHTML($microformats) { if (isset($microformats['items'][0]['properties']['content'][0]['html'])) { $microformats['items'][0]['properties']['content'][0]['html_purified'] = $this->useHTMLPurifier( $microformats['items'][0]['properties']['content'][0]['html'] ); } return $microformats; } /** * Set up and use HTMLPurifer on some HTML. * * @param string The HTML to be processed * @return string The processed HTML */ private function useHTMLPurifier($html) { $config = HTMLPurifier_Config::createDefault(); $config->set('Cache.SerializerPath', storage_path() . '/HTMLPurifier'); $purifier = new HTMLPurifier($config); return $purifier->purify($html); } }