feat(og-image.php): proxy open graph + meta images to mitigate cases where query params required by cdn may break requests

This commit is contained in:
Cory Dransfeldt 2025-05-07 16:31:32 -07:00
parent b6dab4831f
commit 45328b26b1
No known key found for this signature in database
15 changed files with 63 additions and 19 deletions

41
api/og-image.php Normal file
View file

@ -0,0 +1,41 @@
<?php
$id = $_GET['id'] ?? null;
$class = $_GET['class'] ?? null;
$extension = $_GET['extension'] ?? 'png';
$isValidId = is_string($id) && preg_match('/^[a-f0-9\-]{36}$/', $id);
if (!$isValidId || !$class) {
header("Location: /404", true, 302);
exit;
}
$cdnUrl = "https://cdn.coryd.dev/$id.$extension?class=$class";
$ch = curl_init($cdnUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
$image = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
error_log("CDN response code: $httpCode, Content-Type: $contentType");
if ($httpCode !== 200 || $image === false) {
error_log("Failed to fetch image: $cdnUrl");
header("Location: /404", true, 302);
exit;
}
if (strpos($contentType, 'image/') === 0) {
header("Content-Type: $contentType");
header("Cache-Control: public, max-age=86400");
echo $image;
} else {
error_log("Invalid content type: $contentType");
header("Location: /404", true, 302);
exit;
}

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "3.5.0", "version": "3.6.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coryd.dev", "name": "coryd.dev",
"version": "3.5.0", "version": "3.6.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"html-minifier-terser": "7.2.0", "html-minifier-terser": "7.2.0",

View file

@ -1,6 +1,6 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "3.5.0", "version": "3.6.1",
"description": "The source for my personal site. Built using 11ty (and other tools).", "description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module", "type": "module",
"engines": { "engines": {

View file

@ -1,4 +1,5 @@
php8.3-cli php8.3-cli
php8.3-curl
php8.3-fpm php8.3-fpm
php8.3-igbinary php8.3-igbinary
php8.3-mbstring php8.3-mbstring

View file

@ -11,7 +11,7 @@ permalink: "{{ feed.permalink }}.json"
{ {
"version": "https://jsonfeed.org/version/1", "version": "https://jsonfeed.org/version/1",
"title": "{{ feed.title | append: " • " | append: globals.site_name }}", "title": "{{ feed.title | append: " • " | append: globals.site_name }}",
"icon": "{{ globals.url }}/assets/icons/feed.png", "icon": "{{ globals.url }}/og/w200/{% appVersion %}{{ globals.avatar }}",
"home_page_url": "{{ globals.url }}", "home_page_url": "{{ globals.url }}",
"feed_url": "{{ globals.url }}{{ feed.permalink }}.json", "feed_url": "{{ globals.url }}{{ feed.permalink }}.json",
"items": [ "items": [

View file

@ -17,7 +17,7 @@ permalink: "{{ feed.permalink }}.xml"
<atom:link href="{{ globals.url }}{{ feed.permalink }}.xml" rel="self" type="application/rss+xml" /> <atom:link href="{{ globals.url }}{{ feed.permalink }}.xml" rel="self" type="application/rss+xml" />
<lastBuildDate>{{ "now" | date:"%a, %d %b %Y %H:%M:%S %z" }}</lastBuildDate> <lastBuildDate>{{ "now" | date:"%a, %d %b %Y %H:%M:%S %z" }}</lastBuildDate>
<image> <image>
<url>{{ globals.url }}/assets/icons/feed.png</url> <url>{{ globals.url }}/og/w200/{% appVersion %}{{ globals.avatar }}</url>
<title><![CDATA[{{ feed.title | append: " • " | append: globals.site_name }}]]></title> <title><![CDATA[{{ feed.title | append: " • " | append: globals.site_name }}]]></title>
<link>{{ globals.url }}{{ feed.permalink }}.xml</link> <link>{{ globals.url }}{{ feed.permalink }}.xml</link>
<width>144</width> <width>144</width>

View file

@ -73,7 +73,7 @@
ENT_QUOTES, ENT_QUOTES,
"UTF-8" "UTF-8"
), 250); ), 250);
$ogImage = htmlspecialchars($artist["image"] . "?class=w800", ENT_QUOTES, "UTF-8"); $ogImage = htmlspecialchars($artist["image"], ENT_QUOTES, "UTF-8");
$fullUrl = "https://www.coryd.dev" . $requestUri; $fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start(); ob_start();

View file

@ -96,7 +96,7 @@
ENT_QUOTES, ENT_QUOTES,
"UTF-8" "UTF-8"
), 250); ), 250);
$ogImage = htmlspecialchars($book["image"] . "?class=w800", ENT_QUOTES, "UTF-8"); $ogImage = htmlspecialchars($book["image"], ENT_QUOTES, "UTF-8");
$fullUrl = "https://www.coryd.dev" . $requestUri; $fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start(); ob_start();

View file

@ -64,7 +64,7 @@
$pageTitle = htmlspecialchars("Genres • " . $genre["name"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Genres • " . $genre["name"], ENT_QUOTES, "UTF-8");
$pageDescription = truncateText(htmlspecialchars(strip_tags($genre["description"]), ENT_QUOTES, "UTF-8"), 250); $pageDescription = truncateText(htmlspecialchars(strip_tags($genre["description"]), ENT_QUOTES, "UTF-8"), 250);
$ogImage = htmlspecialchars($genre["artists"][0]["image"] . "?class=w800", ENT_QUOTES, "UTF-8"); $ogImage = htmlspecialchars($genre["artists"][0]["image"], ENT_QUOTES, "UTF-8");
$fullUrl = "https://www.coryd.dev" . $requestUri; $fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start(); ob_start();

View file

@ -73,7 +73,7 @@
ENT_QUOTES, ENT_QUOTES,
"UTF-8" "UTF-8"
), 250); ), 250);
$ogImage = htmlspecialchars($movie["backdrop"] . "?class=w800", ENT_QUOTES, "UTF-8"); $ogImage = htmlspecialchars($movie["backdrop"], ENT_QUOTES, "UTF-8");
$fullUrl = "https://www.coryd.dev" . $requestUri; $fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start(); ob_start();

View file

@ -64,7 +64,7 @@
$pageTitle = htmlspecialchars("Show • " . $show["title"], ENT_QUOTES, "UTF-8"); $pageTitle = htmlspecialchars("Show • " . $show["title"], ENT_QUOTES, "UTF-8");
$pageDescription = truncateText(htmlspecialchars(strip_tags($show["description"]), ENT_QUOTES, "UTF-8"), 250); $pageDescription = truncateText(htmlspecialchars(strip_tags($show["description"]), ENT_QUOTES, "UTF-8"), 250);
$ogImage = htmlspecialchars($show["image"] . "?class=w800", ENT_QUOTES, "UTF-8"); $ogImage = htmlspecialchars($show["image"], ENT_QUOTES, "UTF-8");
$fullUrl = "https://www.coryd.dev" . $requestUri; $fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start(); ob_start();

View file

@ -4,10 +4,9 @@
<meta name="theme-color" content="{{ globals.theme_color }}" /> <meta name="theme-color" content="{{ globals.theme_color }}" />
<meta name="fediverse:creator" content="{{ globals.mastodon }}" /> <meta name="fediverse:creator" content="{{ globals.mastodon }}" />
<meta name="generator" content="{{ eleventy.generator }}" /> <meta name="generator" content="{{ eleventy.generator }}" />
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50&v={% appVersion %}" rel="icon" sizes="any" /> <link href="/og/w50/{% appVersion %}{{ globals.avatar_transparent }}" rel="icon" sizes="any" />
<link href="{{ globals.cdn_url }}{{ globals.avatar_transparent }}?class=w50&v={% appVersion %}&type=svg" rel="icon" type="image/svg+xml" /> <link href="/og/w800/{% appVersion %}{{ globals.avatar }}" rel="apple-touch-icon" />
<link href="{{ globals.cdn_url }}{{ globals.avatar }}?class=w800&v={% appVersion %}" rel="apple-touch-icon" /> <link rel="alternate" href="/feeds/posts.xml" title="Posts • {{ globals.site_name }}" />
<link rel="alternate" href="{{ globals.url }}/feeds/posts.xml" title="Posts • {{ globals.site_name }}" /> <link rel="alternate" href="/feeds/links.xml" title="Links • {{ globals.site_name }}" type="application/rss+xml" />
<link rel="alternate" href="{{ globals.url }}/feeds/links.xml" title="Links • {{ globals.site_name }}" type="application/rss+xml" /> <link rel="alternate" href="/feeds/movies.xml" title="Movies • {{ globals.site_name }}" type="application/rss+xml" />
<link rel="alternate" href="{{ globals.url }}/feeds/movies.xml" title="Movies • {{ globals.site_name }}" type="application/rss+xml" /> <link rel="alternate" href="/feeds/books.xml" title="Books • {{ globals.site_name }}" type="application/rss+xml" />
<link rel="alternate" href="{{ globals.url }}/feeds/books.xml" title="Books • {{ globals.site_name }}" type="application/rss+xml" />

View file

@ -2,7 +2,7 @@
<meta name="description" content="<?= cleanMeta($pageDescription ?? '{{ pageDescription | escape }}') ?>" /> <meta name="description" content="<?= cleanMeta($pageDescription ?? '{{ pageDescription | escape }}') ?>" />
<meta property="og:title" content="<?= cleanMeta($pageTitle ?? '{{ pageTitle }}') ?> • {{ globals.site_name }}" /> <meta property="og:title" content="<?= cleanMeta($pageTitle ?? '{{ pageTitle }}') ?> • {{ globals.site_name }}" />
<meta property="og:description" content="<?= cleanMeta($pageDescription ?? '{{ pageDescription | escape }}') ?>" /> <meta property="og:description" content="<?= cleanMeta($pageDescription ?? '{{ pageDescription | escape }}') ?>" />
<meta property="og:image" content="<?= cleanMeta("{{ globals.cdn_url }}" . ($ogImage ?? '{{ ogImage }}')) ?>" /> <meta property="og:image" content="<?= cleanMeta("/og/w800/{% appVersion %}" . ($ogImage ?? '{{ ogImage }}')) ?>" />
<meta property="og:url" content="<?= cleanMeta($fullUrl ?? '{{ fullUrl }}') ?>" /> <meta property="og:url" content="<?= cleanMeta($fullUrl ?? '{{ fullUrl }}') ?>" />
<link rel="canonical" href="<?= cleanMeta($fullUrl ?? '{{ fullUrl }}') ?>" /> <link rel="canonical" href="<?= cleanMeta($fullUrl ?? '{{ fullUrl }}') ?>" />
<?php if (!empty($pagination)): ?> <?php if (!empty($pagination)): ?>

View file

@ -6,4 +6,4 @@
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:url" content="{{ fullUrl }}" /> <meta property="og:url" content="{{ fullUrl }}" />
<link rel="canonical" href="{{ fullUrl }}" /> <link rel="canonical" href="{{ fullUrl }}" />
<meta property="og:image" content="{{ ogImage }}?class=w800" /> <meta property="og:image" content="/og/w800/{% appVersion %}{{ globals.avatar }}" />

View file

@ -47,6 +47,9 @@ RewriteRule ^music/genres/([^/]+)/?$ music/genres/index.php [L]
## tags ## tags
RewriteRule ^tags/([^/]+)(?:/([0-9]+))?/?$ tags/index.php [L] RewriteRule ^tags/([^/]+)(?:/([0-9]+))?/?$ tags/index.php [L]
## open graph assets
RewriteRule ^og/([a-z0-9\-]+)/([\d\.]+)/([a-f0-9\-]+)\.([a-z0-9]+)$ /api/og-image.php?id=$3&class=$1&v=$2&extension=$4 [L]
{% for redirect in redirects -%} {% for redirect in redirects -%}
Redirect {{ redirect.status_code | default: "301" }} {{ redirect.source_url }} {{ redirect.destination_url }} Redirect {{ redirect.status_code | default: "301" }} {{ redirect.source_url }} {{ redirect.destination_url }}
{% endfor -%} {% endfor -%}