diff options
Diffstat (limited to 'Digitigrade/LinkPreview.php')
| -rw-r--r-- | Digitigrade/LinkPreview.php | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/Digitigrade/LinkPreview.php b/Digitigrade/LinkPreview.php new file mode 100644 index 0000000..4716cc8 --- /dev/null +++ b/Digitigrade/LinkPreview.php @@ -0,0 +1,91 @@ +<?php +namespace Digitigrade; + +class LinkPreview implements \JsonSerializable { + public string $url; + public string $siteName; + public string $title; + public string $description; + public string $style; + public ?string $imageUrl = null; + + /** + * Generates a link preview for the given URL. + * @param string $url + * @return LinkPreview|null the link preview, or null if none is available + */ + public static function generate(string $url): ?self { + $p = new self(); + $p->url = $url; + return $p->update() ? $p : null; + } + + /** + * Updates the information for this link preview. + * @return bool true if successful + */ + public function update(): bool { + if (!(str_starts_with($this->url, "https://") || str_starts_with($this->url, "http://"))) { + return false; + } + + $d = new \DOMDocument(); + $c = @file_get_contents($this->url); + if (!$c) + return false; + @$d->loadHTML($c); + + $url = $this->url; + $siteName = hostname_from_uri($this->url); + $style = 'text'; + $title = $d->getElementsByTagName('title')->item(0)?->textContent; + $metas = $d->getElementsByTagName('meta'); + foreach ($metas as $tag) { + if ($tag->attributes->getNamedItem('name')?->textContent == 'description') { + // <meta name="description" content="..."> + $description = $tag->attributes->getNamedItem('content')?->textContent; + } elseif ($prop = $tag->attributes->getNamedItem('property')) { + // <meta property="og:..." content="..."> + $content = $tag->attributes->getNamedItem('content')?->textContent; + match ($prop->textContent) { + 'og:title' => $title = $content, + 'og:description' => $description = $content, + 'og:url' => $url = $content, + 'og:site_name' => $siteName = $content, + 'og:image' => $imageUrl = $content, + default => null + }; + + } elseif ($tag->attributes->getNamedItem('name')?->textContent == 'twitter:card' + && $tag->attributes->getNamedItem("content")?->textContent == 'summary_large_image') { + // <meta name="twitter:card" content="summary_large_image"> + $style = 'largeImage'; + } + } + // turn text into smallImage if an image is present + $style = ($style == 'text' && isset($imageUrl)) ? 'smallImage' : $style; + + if (!isset($title, $description)) + return false; + + $this->url = $url; + $this->siteName = $siteName; + $this->title = $title; + $this->description = $description; + $this->style = $style; + $this->imageUrl = $imageUrl ?? null; + + return true; + } + + public function jsonSerialize(): array { + return [ + 'url' => $this->url, + 'siteName' => $this->siteName, + 'title' => $this->title, + 'description' => $this->description, + 'style' => $this->style, + 'imageUrl' => $this->imageUrl + ]; + } +}
\ No newline at end of file |
