Blog Implementation Guides 6 min read

PHP img onerror Fallback Pattern (No Framework)

Add reliable image fallbacks in plain PHP using server-side null checks, HTML onerror attributes, and fallback.pics placeholder URLs without any framework dependency.

php image fallbackphp onerror imgphp placeholder imagehtml img fallbackvanilla php
PHP img onerror Fallback Pattern (No Framework)

Plain PHP applications and themes can add reliable image fallbacks without any framework. Server-side null checks in PHP echo statements resolve empty database fields before the HTML is sent, and HTML onerror attributes catch CDN or file-system failures after the page loads.

The combination covers the two main failure modes: a null or empty image field in the database, and an image URL that exists but returns a 404 because the file was moved or deleted.

Server-side null check

Resolve null image fields before HTML output

The simplest PHP image fallback pattern uses the null coalescing operator or a ternary to substitute a fallback URL when the database field is empty.

Handle this before the HTML tag, not inside the src attribute. Inline PHP in attributes gets messy and hard to audit as fallback logic grows.

Always escape output with htmlspecialchars() to prevent XSS if any user-controlled data ends up in the URL.

Implementation text
<?php
// Resolve at top of template or in a helper
$image_src = !empty($product['image'])
  ? $product['image']
  : 'https://fallback.pics/api/v1/400x400?text=' . urlencode($product['name']);
?>

<img
  src="<?= htmlspecialchars($image_src) ?>"
  alt="<?= htmlspecialchars($product['name']) ?>"
  width="400"
  height="400"
  onerror="this.onerror=null; this.src='https://fallback.pics/api/v1/400x400?text=No+Image'"
  loading="lazy"
/>

Helper function

Create a reusable image_url() helper

Repeating the fallback URL construction across multiple templates creates maintenance problems. Extract it into a helper function that accepts the image field value, the fallback text, and the dimensions.

The function handles empty string, null, and false values from a database query — all common return types depending on PHP version and the database driver.

Implementation tsx
<?php
function image_url($src, string $text = 'Image', int $w = 400, int $h = 400): string
{
    if (!empty($src)) return htmlspecialchars($src);
    return 'https://fallback.pics/api/v1/' . $w . 'x' . $h . '?text=' . urlencode($text);
}

// Usage
<img
  src="<?= image_url($row['photo'], $row['name'], 400, 400) ?>"
  alt="<?= htmlspecialchars($row['name']) ?>"
  width="400"
  height="400"
  onerror="this.onerror=null; this.src='https://fallback.pics/api/v1/400x400?text=No+Image'"
/>

Avatar pattern

User avatar fallback with initials

User profile pages frequently show an avatar that may not be set. Use the fallback.pics avatar route with initials derived from the user's name.

Generate initials server-side in PHP so the fallback URL is embedded in the HTML before any JavaScript runs.

Implementation tsx
<?php
function avatar_url(?string $avatar, string $name, int $size = 64): string
{
    if (!empty($avatar)) return htmlspecialchars($avatar);

    $words = explode(' ', trim($name));
    $initials = '';
    foreach ($words as $word) {
        $initials .= strtoupper(mb_substr($word, 0, 1));
        if (strlen($initials) >= 2) break;
    }
    return 'https://fallback.pics/api/v1/avatar/' . $size . '?text=' . urlencode($initials);
}

// In template
<img
  src="<?= avatar_url($user['avatar'], $user['name'], 64) ?>"
  alt="<?= htmlspecialchars($user['name']) ?>"
  width="64"
  height="64"
  onerror="this.onerror=null; this.src='https://fallback.pics/api/v1/avatar/64?text=??'"
/>

File existence check

Check local file existence before generating URLs

When images are stored on the local file system in an uploads/ directory, a database path can point to a file that no longer exists. Check existence with file_exists() when performance allows.

For frequently accessed pages, avoid calling file_exists() on every request for every image. Use a cached boolean in the database or a background task to validate stored paths periodically.

Implementation tsx
<?php
function local_image_url(string $path, string $fallback_text): string
{
    $full_path = $_SERVER['DOCUMENT_ROOT'] . $path;
    if (!empty($path) && file_exists($full_path)) {
        return htmlspecialchars($path);
    }
    return 'https://fallback.pics/api/v1/400x400?text=' . urlencode($fallback_text);
}

OG image

Resolve og:image in PHP head output

Set og:image in the page head using the same helper function. Compute it before the HTML output starts so the meta tag uses the resolved URL.

Append a raster file extension when the URL points to fallback.pics, since social crawlers do not support SVG.

Implementation text
<?php
$og_image = image_url($post['featured_image'], $post['title'], 1200, 630);
// Ensure raster format for social crawlers
if (strpos($og_image, 'fallback.pics') !== false) {
    $og_image = str_replace('/api/v1/1200x630', '/api/v1/1200x630.jpg', $og_image);
}
?>
<meta property="og:image" content="<?= htmlspecialchars($og_image) ?>" />

Security note

Always escape output and avoid user input in onerror

Any value from a database field echoed into an HTML attribute must be escaped with htmlspecialchars(). This applies to both the real image URL and any fallback URL that contains user-controlled text.

For the onerror attribute specifically, the value is a JavaScript string. Never put user-controlled data inside the onerror handler. The fallback URL in onerror should be a hard-coded string.

Key takeaways

What to standardize before shipping

  • Resolve empty database fields server-side before echoing the src attribute — prevents the broken-image flash on first render.
  • Wrap fallback URL logic in a helper function to avoid repeating it across templates.
  • Pass user-controlled strings through urlencode() in URLs and htmlspecialchars() before outputting to HTML.
  • The onerror fallback URL should be a hard-coded string — never constructed from user input.
  • Use the avatar route with server-generated initials for a more informative fallback than a blank placeholder.

Production fallback layer

Use fallback.pics anywhere an image URL is accepted.

Start with one deterministic URL and standardize fallback behavior across your design system.

Read the docs