aboutsummaryrefslogtreecommitdiffhomepage
path: root/Digitigrade/LinkPreview.php
diff options
context:
space:
mode:
Diffstat (limited to 'Digitigrade/LinkPreview.php')
-rw-r--r--Digitigrade/LinkPreview.php91
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